Dashboard: Solution Grouping and Clustering
Relevant source files
The following files were used as context for generating this wiki page:
- frontend/src/components/dashboard/hooks/useGrouping.ts
- frontend/src/components/dashboard/hooks/useManualGrouping.ts
- frontend/src/components/dashboard/Analyzer.tsx
- frontend/src/components/dashboard/Analysis.tsx
- frontend/src/components/dashboard/CodeComparison.tsx
- frontend/src/components/dashboard/Analyzer.state.ts
- frontend/src/components/dashboard/hooks/types.ts
The Solution Grouping and Clustering feature provides a powerful data visualization tool within the session analysis dashboard. It plots student solutions as points on a 2D scatter chart, where axes represent different code analysis metrics (e.g., number of statements, test results). This allows educators to identify patterns and clusters of similar solutions.
The system supports two primary modes of operation: manual grouping, where the user can draw lines ("splits") on the chart to define group boundaries, and automatic grouping, which algorithmically clusters the solutions. These groups can then be used to filter and compare solutions side-by-side in the CodeComparison component. The entire feature is orchestrated by the Analyzer component, which manages state and user interactions.
Architecture Overview
The grouping and clustering functionality is primarily driven by a set of React components and hooks. The Analyzer component serves as the main container, managing the overall state. It utilizes the useGrouping hook to process solution data, which in turn delegates to either useManualGrouping or useAutomaticGrouping based on user selection. The resulting categorized data points are rendered by the Analysis component using Chart.js.
This diagram illustrates the high-level interaction between the key components and hooks.
Core Components and State
Analyzer Component
The Analyzer component is the top-level component for the analysis dashboard. It is responsible for:
- Fetching task and solution analysis data.
- Managing the feature's state via the
analyzerStateReducer. - Providing UI controls for selecting tasks, sub-tasks, filters, and grouping modes.
- Orchestrating the flow of data between the
useGroupinghook and theAnalysisandCodeComparisondisplay components.
Sources: frontend/src/components/dashboard/Analyzer.tsx:70-299
AnalyzerState
State is managed centrally using a reducer (analyzerStateReducer). This ensures predictable state transitions.
| Property | Type | Description | Source File |
|---|---|---|---|
selectedTask | number | The ID of the currently selected task. | frontend/src/components/dashboard/Analyzer.tsx:73 |
isAutomaticGrouping | boolean | A flag to toggle between automatic and manual grouping modes. | frontend/src/components/dashboard/Analyzer.tsx:75 |
xAxis, yAxis | AxesCriterionType | The metrics selected for the X and Y axes of the chart. | frontend/src/components/dashboard/Analyzer.tsx:76-77 |
filters | Filter[] | An array of active filters applied to the solution data. | frontend/src/components/dashboard/Analyzer.tsx:78 |
splits | ChartSplit[] | An array of horizontal and vertical lines used for manual grouping. | frontend/src/components/dashboard/Analyzer.tsx:79 |
selectedSolutionIds | Set<string> | A set of solution IDs that have been selected by the user via the chart's selection tool. | frontend/src/components/dashboard/Analyzer.tsx:80 |
comparison | object | State object for the code comparison view, including selected solutions for left and right panes. | frontend/src/components/dashboard/Analyzer.tsx:81-87 |
useGrouping Hook
This is the central hook that drives the grouping logic. It takes the grouping mode (isAutomaticGrouping), solution data, and manual splits as input. Based on the mode, it invokes either useManualGrouping or useAutomaticGrouping to generate the final list of categorizedDataPoints.
The following diagram shows the conditional logic within the useGrouping hook.
Grouping Strategies
Manual Grouping
Manual grouping is enabled when isAutomaticGrouping is false. It allows the user to define groups by creating "splits" on the chart.
Logic:
- The
useManualGroupinghook receives the list of horizontal and verticalsplitsfrom theAnalyzerState. - It sorts the splits along their respective axes.
- It constructs a grid of rectangular group areas defined by adjacent splits (or the chart boundaries). An artificial split at
Number.POSITIVE_INFINITYis added to close the last group on each axis. - Each group is assigned a key and a letter-based name (A, B, C, ...).
- Each solution data point is then iterated over, and its (x, y) coordinates are checked to determine which group it falls into.
- If a data point does not fall into any group, a
SolutionNotInGroupErroris thrown.
Sources: frontend/src/components/dashboard/hooks/useManualGrouping.ts:68-149
The getGroupName function generates labels for manual groups by converting an index into a base-26 alphabetical representation (0 -> A, 25 -> Z, 26 -> BA).
Sources: frontend/src/components/dashboard/hooks/useManualGrouping.ts:50-61
Automatic Grouping
When isAutomaticGrouping is true, the useGrouping hook calls the computeAutomaticGrouping function returned by the useAutomaticGrouping hook. This is an asynchronous operation that performs clustering on the solution data.
The implementation details of the clustering algorithm are located in frontend/src/components/dashboard/hooks/automatic-grouping/index.ts, which was not available for this analysis. However, its interface is clear from useGrouping.ts: it's a function that returns a promise, which resolves to an array of Group objects. The useGrouping hook then sets isGroupingAvailable to false while computing and sets it back to true once the promise resolves.
Sources: frontend/src/components/dashboard/hooks/useGrouping.ts:40-54
Data Visualization (Analysis Component)
The Analysis component uses primereact/chart, a wrapper around Chart.js, to render the scatter plot.
Data Point Aggregation and Styling
- Aggregation: Before rendering, data points with the exact same (x, y) coordinates are aggregated. This is handled by the
aggregateDataPointsByCoordinatefunction. The size of the rendered bubble is proportional to the number of solutions at that coordinate.
Sources: frontend/src/components/dashboard/Analysis.tsx:219-250, 344-347 - Styling: Data points are styled based on several factors:
- Category: A pattern (
getCanvasPattern) is applied based on the point's category (e.g.,mixed,passesAllTests). - Selection: Points selected for comparison or part of a selection group have a thicker, colored border.
- Reference Solutions: Reference solutions are rendered with a special symbol (
createReferenceSymbol) or a star shape (createStar).
Sources: frontend/src/components/dashboard/Analysis.tsx:381-432
- Category: A pattern (
Chart.js Plugins
The chart's interactivity is enhanced with custom plugins.
| Plugin | Enabled Condition | Functionality | Source File |
|---|---|---|---|
SplitPlugin | !state.isAutomaticGrouping | Allows users to click and drag on the chart axes to create horizontal or vertical split lines. On creation, it dispatches an addSplit action. | frontend/src/components/dashboard/Analysis.tsx:694-701 |
SelectPlugin | true | Allows users to draw a rectangle on the chart to select multiple data points. On selection, it dispatches a setSelectedAnalyses action with the IDs of the solutions within the rectangle. | frontend/src/components/dashboard/Analysis.tsx:703-728 |
annotation | true | A standard Chart.js plugin used here to render the split lines and group labels. It also handles the logic for deleting a split when its "x" label is clicked. | frontend/src/components/dashboard/Analysis.tsx:552-658 |
Data Consumption (CodeComparison Component)
The CodeComparison component is a direct consumer of the grouping data. It provides two panes for side-by-side code viewing. Each pane has dropdowns to select a group and then a specific solution within that group.
- The "Group" dropdown is populated with all available groups (manual or automatic) from the
groupsprop. It also includes special options for "All solutions" and "Selected solutions". - The "Solution" dropdown is dynamically populated based on the selected group.
- When groups or axes change, a
useEffecthook ensures that the selected solutions in the comparison panes are updated or cleared if they are no longer valid within the new context.
This demonstrates how the grouping feature directly enables a more focused analysis workflow, allowing educators to easily compare solutions from the same cluster.
Sources: frontend/src/components/dashboard/CodeComparison.tsx:151-165, 268-330