Skip to content

feat(dashboard): plot multiple training metrics on one chart (#265) - #304

Open
Paopao-C wants to merge 4 commits into
inclusionAI:mainfrom
Paopao-C:feat/multi-metric-plot-265
Open

feat(dashboard): plot multiple training metrics on one chart (#265)#304
Paopao-C wants to merge 4 commits into
inclusionAI:mainfrom
Paopao-C:feat/multi-metric-plot-265

Conversation

@Paopao-C

@Paopao-C Paopao-C commented Jul 28, 2026

Copy link
Copy Markdown

Closes #265.

What changed

File Change
dashboard/src/main.jsx Extend MetricChart: multi-select metrics on one chart, dual axes, hover card, normalization, LTTB downsampling, A11y attributes (hand-rolled SVG, no new dep)
dashboard/src/styles.css Styles for the new controls/legend/hover card
areno/cli/dashboard.py New areno metrics export command (human + --json), guarded state reads
areno/cli/main.py +1 line: register "metrics"
tests/test_dashboard_metrics_cli_cpu.py New: 11 CPU tests (pytest, no torch)
tests/test_multi_metric_plot_cpu.mjs New: 24 node tests for pure helpers (incl. NaN/zero/empty edge cases)
docs/cli/observability.rst Usage, input contract, output fields, examples

Usage

Dashboard: open the metrics panel, toggle metrics in the dropdown — one or
many on one chart. No backend change; reuses /api/jobs/<id>/metric.

CLI:
areno metrics --job --names train/loss,train/reward [--limit N] [--json]

Features

  • Multi-select onto one chart (hand-rolled dropdown; no charting dep).
  • Click-to-toggle legend, hover values (snap-to-step card), optional dual
    Y-axes (auto when scales differ >1 order of magnitude).
  • View-only normalization (off by default); stored data never modified.
  • LTTB downsampling for series >480 points (display only, NaN-safe).
  • Backward compatible: single metric = today's view.

CLI output (human-readable)

$ areno metrics --job <id> --names train/loss,train/reward --limit 3
job: <id>  limit: 3
# train/loss  (3 points)
  step     57  0.6957
  step     58  0.7113
# train/reward  (3 points)
  step     57  4.9981

Real-data validation

Verified on Kaggle (GPU), Qwen3.5-0.8B run. Multi-metric chart, dual axes,
hover values work on real TensorBoard scalars.
image

Tests

  • pytest tests/test_dashboard_metrics_cli_cpu.py — 11 passed (success,
    malformed input, boundary 1/5000/out-of-range, default-unchanged, fixture).
  • node tests/test_multi_metric_plot_cpu.mjs — 24 passed (downsample 2000
    pts, axis assignment, normalization toggles, deterministic, NaN/zero/empty
    edge cases).

Notes

  • No backend/API change. No GPU paths touched.
  • dynamic metrics / responsive resize implemented; responsive is CSS-level,
    dynamic-metric refresh rides existing poll loop — lighter dedicated test
    coverage but exercised via the existing fixtures.

志佳 and others added 4 commits July 28, 2026 15:13
…onAI#265)

- Multi-select metrics onto one chart with click-to-toggle legend, hover
  values, optional dual Y-axes, view-only normalization, and LTTB
  downsampling. Colorblind-safe Okabe-Ito palette. Frontend-only, reuses the
  existing /api/jobs/<id>/metric endpoint; no new dependency.
- Backward compatible: a single selected metric reproduces today's view.
- New  CLI export (human-readable + --json) reusing
  metric_series, with validation that names the failing stage/input.
- CPU tests (pytest + node) cover success, malformed input, boundary values,
  default-unchanged, and a tiny local JSONL fixture.
- Docs in docs/cli/observability.rst with input contract, output fields, and
  copyable examples.

Co-Authored-By: Claude <noreply@anthropic.com>
- assignAxes: replace truthy range check with Number.isFinite + compare absolute
  peak magnitudes so zero-containing ranges ([0, 3]) are not split by a 1e-12
  floor (real bug: min==0 was treated as missing).
- downsampleLttb: clamp bucket start/end to [1, n-2] and compute the next-bucket
  average over its actual range instead of two fixed indices; no out-of-bounds.
- MetricSelector: add aria-expanded/haspopup/controls + per-item aria-label for
  keyboard / screen-reader use.
- MetricChart hover: name the viewBox-width constant (SVG_WIDTH) and document
  the pointer-x to step mapping.
- metrics_command: guard metric_summaries/metric_series with meaningful errors
  on malformed dashboard state.
- tests: add 7 LTTB/axis edge cases (duplicate steps, NaN/Inf, n near target,
  uneven gaps, zero-containing ranges, negative-crossing ranges) and delete the
  extracted helper module at the end of the node run.

Co-Authored-By: Claude <noreply@anthropic.com>
- downsampleLttb: skip non-finite candidates explicitly (do not rely on NaN
  comparison semantics across engines); document the length==target guarantee
  and the [start, end) half-open bucket convention.
- buildMultiMetricPlot: guard empty / all-empty series so Math.min(...) over an
  empty spread no longer yields Infinity and corrupts coordinates; return [].
- assignAxes: unfold the peak-ratio check into a readable if/else.
- MultiMetricPlot hoverGuide: draw using the first non-empty plot that has the
  hovered step, instead of an implicit x=0 fallback.
- _load_dashboard_state: document the ARENO_DASHBOARD_ROOT precondition.
- tests: +1 regression for all-empty series (24 node checks now).

Co-Authored-By: Claude <noreply@anthropic.com>
No behavior change; only formatting (collapse wrapped echo call, wrap the
metrics registry tuple, add trailing newline to the test file) requested by
the repo's pre-commit hooks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plot multiple training metrics together in the dashboard

1 participant