Skip to content

FAC-141 feat: dimension-level performance visualization (radar chart) #346

Description

@y4nder

Context

The faculty analysis view currently shows quantitative performance via (a) a bar-style per-section performance chart and (b) a per-question table nested under each section. Both are aggregated at the section level (weighted average of section questions).

However, the underlying data model also tracks dimension codes on QuestionnaireAnswer (e.g. PREPARATION, TEACHING_LEARNING_PROCESS, ASSESSMENT, LEARNING_ENVIRONMENT, PROFESSIONALISM) which cut orthogonally to sections. Dimensions are a richer diagnostic view because:

  • Fewer, more meaningful categories (typically 4–7) — sweet spot for radar visualisation
  • Map cleanly to well-known pedagogical dimensions stakeholders recognise
  • Already used by RecommendationGenerationService.Generate (lines ~172-197) to bias LLM recommendations
  • Produce an at-a-glance "fingerprint" of faculty strengths and weaknesses

Proposed feature

Add a radar (spider) chart visualisation of per-dimension averages, mounted at the top of the Quantitative Scores collapsible in FacultyReportScreen. Existing section chart stays — the two are complementary (dimensions = cross-section, sections = weight-aggregated).

radar example

Backend

  • Extract the dimension-aggregation logic currently inline in RecommendationGenerationService.Generate into a reusable helper on AnalyticsService (or a shared lib under src/modules/analytics/lib/).
  • Extend GET /analytics/faculty/:facultyId/report response (or add a sibling endpoint) to include:

```ts
dimensionScores: {
code: string; // e.g. 'PREPARATION'
label: string; // human-readable from dimension registry
average: number; // normalised 0–1
responseCount: number; // questions × submissions contributing
}[]
```

  • Normalise to 0–1 so different Likert ranges (LIKERT_1_4 vs LIKERT_1_5) plot comparably. Divide by the per-question max so the radar axis is always 0–100% full.

Frontend

  • New faculty-dimension-radar-chart.tsx component using recharts' RadarChart (recharts already installed for the existing section chart — no new deps).
  • Mount at the top of the Quantitative Scores collapsible, above the existing section performance chart.
  • Theme-token styled (stroke / fill using var(--color-primary) + opacity, grid lines via var(--color-border)). Dark-mode aware.
  • Responsive sizing via recharts' ResponsiveContainer.

Stretch — comparative overlay

  • Second radar layered over the faculty's own, representing department average for the same semester + questionnaire type (dashed line, muted colour).
  • Requires a new backend endpoint or param: GET /analytics/department/:deptId/dimensions?semesterId=&questionnaireTypeCode=.
  • Unlocks "how does this faculty differ from their peers" at a glance — the single biggest stakeholder value-add.

Concerns to resolve during refinement

  1. Dimension taxonomy consistency — does every questionnaire type use the same set of dimension codes? If not, the radar is per-questionnaire-type and we need to confirm per-type dimension metadata (label, display order) exists.
  2. Scale normalisation — confirm all answer types can be normalised to 0–1; LIKERT_1_4, LIKERT_1_5 are obvious; investigate whether any non-likert answer types contribute to dimension_code aggregation and how they normalise.
  3. Minimum responses per dimension — show the radar only if every dimension has >= N responses? Or dim the sparse spokes? Tie-in with the low-volume-handling companion ticket.

Acceptance criteria

  • Backend exposes dimensionScores[] with normalised 0–1 averages and response counts
  • Aggregation logic extracted from RecommendationGenerationService into a shared helper (eliminates duplication)
  • Radar chart renders on the faculty analysis view, mounted at the top of the quantitative scores section
  • Theme-token styled; dark-mode aware
  • Responsive across screen widths
  • Graceful empty / single-dimension states (radar needs >= 3 dimensions to form a polygon)
  • Typecheck + lint clean; no new npm deps

Related

  • FAC-134 (quantitative section UX — this lands inside the collapsible we built there)
  • FAC-138 (recommendation prompt — the radar's "weakest dimension" could explicitly bias the LLM prompt)
  • FAC-132 (pipeline — where the aggregation logic currently lives, to be extracted)
  • Future: dashboard-scope extension — same radar at department / program / campus scope on the scoped-analytics-dashboard

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions