Analytics: add per-total-score quartile sparklines for each question#1449
Analytics: add per-total-score quartile sparklines for each question#1449
Conversation
339beee to
84d6de7
Compare
da540b7 to
e7cf706
Compare
There was a problem hiding this comment.
Pull request overview
Adds per-question “score by overall-session quartile” visualization to the flow analytics page, letting instructors see whether questions discriminate between stronger and weaker students.
Changes:
- Backend: compute session quartiles from overall session score and include per-quartile average correctness in
PageAnswerStats. - Frontend: add a new JS bundle to render 4-point sparklines from per-quartile data.
- Template/build: load the new bundle on
analytics-flow.htmland add data attributes; wire bundle into Rollup/CI; addsparklinesdependency.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
course/analytics.py |
Computes session→quartile mapping and accumulates per-quartile correctness into PageAnswerStats. |
course/templates/course/analytics-flow.html |
Loads the new bundle and adds a sparkline element per question (layout refactor to table). |
frontend/js/analytics.js |
Renders sparklines from embedded quartile correctness JSON. |
rollup.config.mjs |
Adds a new Rollup bundle output (bundle-analysis.js). |
package.json / package-lock.json |
Adds sparklines dependency and build script. |
.ci/run-tests-for-ci.sh |
Adds the new bundle to the CI “touched staticfiles” list for collectstatic. |
tests/test_analytics.py |
Adds tests for quartile_correctness_json serialization. |
biome.json |
Reformatting only. |
.basedpyright/baseline.json |
Updates type-check baseline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def compute_session_quartile_map( | ||
| pctx: CoursePageContext, | ||
| flow_id: str) -> dict[int, int]: | ||
| """Return a mapping from session ID to quartile index (0 = Q1, ..., 3 = Q4). | ||
|
|
||
| Quartiles are assigned based on each session's percentage score, using only | ||
| completed sessions for participants with grade-statistics permission. | ||
| """ | ||
| sessions = FlowSession.objects.filter( | ||
| course=pctx.course, | ||
| flow_id=flow_id, | ||
| in_progress=False, | ||
| participation__roles__permissions__permission=( | ||
| PPerm.included_in_grade_statistics)) | ||
|
|
||
| session_scores: list[tuple[int, float]] = [] | ||
| for session in sessions: | ||
| pperc = session.points_percentage() | ||
| if pperc is not None: | ||
| session_scores.append((session.id, float(pperc))) | ||
|
|
||
| if not session_scores: | ||
| return {} | ||
|
|
||
| session_scores.sort(key=operator.itemgetter(1)) | ||
| n = len(session_scores) | ||
| return { | ||
| sid: min(NUM_QUARTILES - 1, int(i * NUM_QUARTILES / n)) | ||
| for i, (sid, _score) in enumerate(session_scores) | ||
| } |
There was a problem hiding this comment.
New behavior in compute_session_quartile_map (quartile assignment logic) is not covered by tests. The added tests only validate JSON serialization, but don't verify that sessions are bucketed into quartiles correctly (including edge cases like small N). Please add a unit test that creates sessions with known points/max_points and asserts the resulting quartile indices.
There was a problem hiding this comment.
@copilot apply changes based on this feedback, i.e. add unit tests for compute_session_quartile_map
There was a problem hiding this comment.
Added ComputeSessionQuartileMapTest in commit 3fc40eb with 8 unit tests covering:
- Empty session set → empty map
- Sessions without
pointsexcluded - In-progress sessions excluded
- Single session → Q1 (index 0)
- 4 sessions correctly assigned to Q1–Q4
- Small-N edge cases (n=2 and n=3)
- Sorting by score regardless of insertion order
…lytics - Add compute_session_quartile_map() to analytics.py to assign sessions to Q1-Q4 quartiles based on total score percentage - Add quartile_correctness_list field and quartile_correctness_json property to PageAnswerStats dataclass - Update make_page_answer_stats_list() to compute per-quartile average correctness for each page - Add frontend/js/analytics.js using sparklines npm package to render per-quartile sparklines for each question - Add bundle-analytics to rollup.config.mjs - Update analytics-flow.html to show sparkline charts and load analytics bundle - Install sparklines npm package - Add PageAnswerStatsTest tests for quartile_correctness_json" Co-authored-by: inducer <352067+inducer@users.noreply.github.com> Agent-Logs-Url: https://github.com/inducer/relate/sessions/90d505da-f8b0-4ecc-8317-d826bd923f6a Add unit tests for compute_session_quartile_map Tests cover: empty set, sessions without points, in-progress sessions, single-session, 4 sessions (one per quartile), small-N edge cases (2 and 3 sessions), and ordering by score regardless of insertion order. Agent-Logs-Url: https://github.com/inducer/relate/sessions/890b63ca-7ebb-4571-ab4c-6844838e9121 Co-authored-by: inducer <352067+inducer@users.noreply.github.com> Translations Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Add distinct Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Fix mid-file import Fix HTML
3fc40eb to
93cb43d
Compare
93cb43d to
bb5d181
Compare
compute_session_quartile_map()function tocourse/analytics.pyto map session IDs to quartiles (Q1-Q4) based on total scorequartile_correctness_listfield andquartile_correctness_jsonproperty toPageAnswerStatsdataclassmake_page_answer_stats_list()to compute per-quartile average scores for each pagesparklinesnpm packagefrontend/js/analytics.jsto render sparklines using the sparklines library (nulls handled by filtering out missing quartile data)rollup.config.mjscourse/templates/course/analytics-flow.htmlto show sparkline charts and load the analytics bundlecompute_session_quartile_mapcovering: empty set, unscored sessions, in-progress sessions, single-session, 4-session quartile assignment, small-N edge cases (2 and 3 sessions), and sorting by scoreOriginal prompt
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.