Skip to content

Commit 00cac17

Browse files
committed
Add docs for gradebook
1 parent ec7be42 commit 00cac17

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed

docs/staff/gradebook.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
title: Gradebook
3+
---
4+
5+
## Column Semantics in the Gradebook System
6+
7+
In the Pawtograder gradebook system, **columns** represent individual grade components that collectively form a student's overall course performance. Each column is defined by a unique slug identifier, a human-readable name, and a maximum score, but their power lies in their flexibility for grade calculation and data sources. Columns can be **manually entered** by instructors who directly input grades cell-by-cell, **imported from CSV files** to bulk-load grades from external systems (with full metadata tracking of the import source and date), or **linked to programming assignments** through the assignment reference system. When linked to assignments, columns automatically pull grades from the autograder system, creating a seamless connection between student code submissions and gradebook entries.
8+
9+
**Expressions:** The most sophisticated column type uses **mathematical expressions** that reference other columns or assignments, creating a powerful dependency system for calculated grades. Using MathJS syntax, instructors can create complex formulas like `(gradebook_columns("homework-*") + assignments("project-*")) / 2` to automatically compute weighted averages, drop lowest scores, or apply curve adjustments. Score expressions can define functions and have access to the full MathJS library of math and utility functions. Any grade that is automatically calculated can also be manually overridden by the instructor on a case-by-case basis.
10+
11+
**Student visibility of grades:** The **"released"** status in the gradebook determines whether students can see a particular column and its grades. For imported or manually-entered columns, instructors have direct control over this visibility - they can release columns to make them visible to students or unrelease them to hide grades during grading periods or for sensitive assessments. This setting is at the column-level only (you can't release or unrelease individual grades). For columns that are automatically calculated by Pawtograder (via an expression), students always see the current calculation *based only on what they can see*. For example, a column defined as the average of all homeworks will show the student the average of all homeworks they have released.
12+
13+
## Importing Grades
14+
15+
To import grades, instructors use a 3-step wizard:
16+
17+
1. **File Selection**: Click the "Import Column" button and select a CSV file from your computer, which the system parses client-side to extract tabular data.
18+
19+
2. **Column Mapping**: Choose which CSV column contains student identifiers and select whether they are email addresses or student IDs. For each remaining CSV column, decide whether to map it to an existing gradebook column for updates, create a new column (requiring you to set the maximum score), or ignore the column entirely. The system automatically detects email columns if present.
20+
21+
3. **Preview & Confirm**: Review a comprehensive preview table that shows exactly what changes will occur, highlighting grade updates with strikethrough old values and bold new values, warning about students in the CSV who aren't enrolled in the course, and providing alerts when attempting to override calculated column scores. Only after reviewing this detailed preview can you click "Confirm Import" to execute the changes.
22+
23+
The system automatically creates new columns with full audit metadata including filename, date, and creator information, updates only enrolled students' grades while preserving override behavior for calculated columns, and maintains complete import history for traceability and compliance purposes.
24+
25+
26+
## Expression Syntax
27+
28+
## Gradebook Expression Syntax Documentation
29+
30+
The gradebook expression system uses **MathJS** as its foundation, enhanced with specialized functions for grade calculations. Expressions must return a numeric value that becomes the student's score for that column. The final expression line is the student's score for that column.
31+
32+
### Core Syntax
33+
34+
Expressions follow standard mathematical notation with variables, operators, and functions:
35+
36+
```javascript
37+
// Basic arithmetic
38+
hw_average = (hw1 + hw2 + hw3) / 3
39+
40+
// Boolean logic and conditionals
41+
passing = grade >= 60 ? 1 : 0
42+
43+
// Multi-line expressions (last line is the result)
44+
midterm_weight = 0.3
45+
final_weight = 0.7
46+
weighted_score = midterm * midterm_weight + final * final_weight
47+
weighted_score
48+
```
49+
50+
### Data Access Functions
51+
52+
#### `gradebook_columns("slug-pattern")`
53+
Retrieves gradebook column data with glob pattern matching. Returns objects with:
54+
- `score`: `number | null` - The student's score (including overrides)
55+
- `is_missing`: `boolean` - Whether the grade is missing/not entered
56+
- `is_excused`: `boolean` - Whether the student is excused from this item
57+
- `is_droppable`: `boolean` - Whether this item can be dropped in calculations
58+
59+
```javascript
60+
// Single column
61+
homework1 = gradebook_columns("hw-01")
62+
63+
// Multiple columns with glob patterns
64+
all_homeworks = gradebook_columns("hw-*")
65+
skill_assessments = gradebook_columns("skill-*")
66+
67+
// Access score property
68+
hw_score = gradebook_columns("hw-01").score
69+
```
70+
71+
### Array Processing Functions
72+
73+
#### `countif(array, predicate)`
74+
Counts array elements matching a condition using lambda syntax:
75+
76+
```javascript
77+
// Count skill assessments scoring exactly 2
78+
meets_expectations = countif(gradebook_columns("skill-*"), f(x) = x.score == 2)
79+
80+
// Count passing grades
81+
passing_count = countif(gradebook_columns("exam-*"), f(x) = x.score >= 70)
82+
```
83+
84+
#### `sum(array)`
85+
Sums numeric values or scores from gradebook objects:
86+
87+
```javascript
88+
total_points = sum(gradebook_columns("hw-*"))
89+
```
90+
91+
#### `mean(array, weighted=true)`
92+
Calculates weighted (default) or unweighted averages:
93+
94+
```javascript
95+
// Weighted average (accounts for different max scores)
96+
hw_average = mean(gradebook_columns("hw-*"))
97+
98+
// Unweighted average
99+
hw_simple_avg = mean(gradebook_columns("hw-*"), false)
100+
```
101+
102+
Weighted average is defined as:
103+
```javascript
104+
const totalPoints = validValues.reduce((a, b) => a + (b?.max_score ?? 0), 0);
105+
const totalScore = validValues.reduce((a, b) => a + (b?.score ?? 0), 0);
106+
if (totalPoints === 0) {
107+
return undefined;
108+
}
109+
return (100 * totalScore) / totalPoints;
110+
```
111+
112+
Unweighted average is defined as:
113+
```javascript
114+
return (100 * validValues.reduce((a, b) => a + (b && b.score ? b.score / b.max_score : 0), 0)) / validValues.length;
115+
```
116+
117+
In either case, grades that are missing will count as 0 points, *unless* the grade is marked as `excused`, in which case it is excluded from the average.
118+
119+
#### `drop_lowest(array, count)`
120+
Removes the lowest scoring droppable items:
121+
122+
```javascript
123+
// Drop 2 lowest homework scores
124+
best_homeworks = drop_lowest(gradebook_columns("hw-*"), 2)
125+
hw_final = mean(best_homeworks)
126+
```
127+
128+
`drop_lowest` drops the lowest grades (including those that are "missing" or "excused") as long as the "droppable" flag is set on the grade (this is the default).
129+
130+
### Conditional Logic
131+
132+
#### `case_when([condition, value; ...])`
133+
Convenience function for multi-condition branching using matrix syntax:
134+
135+
```javascript
136+
letter_grade = case_when([
137+
score >= 93, 97; // A
138+
score >= 90, 93; // A-
139+
score >= 87, 90; // B+
140+
score >= 83, 87; // B
141+
true, 0 // Default case
142+
])
143+
```
144+
145+
### Comparison Functions
146+
147+
Normal comparison functions like `==`, `>=`, `<=`, etc. are available, and can automatically coerce a gradebook value to a score for you (so that you do not need to map each gradebook value to a score to compare it).
148+
149+
### Complete Examples
150+
151+
#### Simple Counting Example
152+
```javascript
153+
// Count skills meeting expectations (score = 2)
154+
countif(gradebook_columns("skill-*"), f(x) = x.score == 2)
155+
```
156+
157+
#### Complex Grade Calculation
158+
```javascript
159+
// Multi-criteria grading with modifiers
160+
CriteriaA = gradebook_columns("meets-expectations") >= 10 and
161+
gradebook_columns("does-not-meet-expectations") == 0 and
162+
gradebook_columns("average.hw") >= 85
163+
164+
CriteriaB = gradebook_columns("meets-expectations") >= 8 and
165+
gradebook_columns("does-not-meet-expectations") == 0 and
166+
gradebook_columns("average.hw") >= 75
167+
168+
CriteriaC = gradebook_columns("meets-expectations") >= 5 and
169+
gradebook_columns("does-not-meet-expectations") == 0 and
170+
gradebook_columns("average.hw") >= 65
171+
172+
CriteriaD = gradebook_columns("approaching-expectations") >= 9 and
173+
gradebook_columns("does-not-meet-expectations") == 0 and
174+
gradebook_columns("average.hw") >= 55
175+
176+
CriteriaPlus = gradebook_columns("total-labs") >= 8
177+
CriteriaMinus = gradebook_columns("total-labs") < 6
178+
179+
letter = case_when([
180+
CriteriaA, 95;
181+
CriteriaB, 85;
182+
CriteriaC, 75;
183+
CriteriaD, 65;
184+
true, 0
185+
])
186+
187+
mod = case_when([
188+
CriteriaPlus, 3;
189+
CriteriaMinus, -3;
190+
true, 0
191+
])
192+
193+
final = max(letter + mod, 0)
194+
final
195+
```

0 commit comments

Comments
 (0)