Skip to content

Add a Y-Axis scale toggle to perf plots#947

Draft
epompeii wants to merge 1 commit into
develfrom
claude/plot-y-axis
Draft

Add a Y-Axis scale toggle to perf plots#947
epompeii wants to merge 1 commit into
develfrom
claude/plot-y-axis

Conversation

@epompeii

@epompeii epompeii commented Jul 16, 2026

Copy link
Copy Markdown
Member

What

Add a three-mode Y-Axis scale to perf plots: Auto, Linear, and Log.

  • Auto (default): preserves the existing adaptive power scaling
  • Linear: a true linear scale that shows magnitudes as-is
  • Log: a genuine logarithmic scale; it falls back to Auto when the data includes zero or negative values, since the logarithm is undefined there

The selection is:

  • Toggled from the perf plot header button, cycling Auto, Linear, Log
  • Saved in the plot URL and restored for pinned plots
  • Settable via the API (y_axis on plot create and update) and CLI (bencher plot create --y-axis, bencher plot update --y-axis)
  • Carried along by the Perf explorer "Update Pin" button with the rest of the display settings

How

  • New YAxis enum (auto | linear | log) in bencher_json, stored on the plot table via a new migration as an integer column with strong Diesel ToSql/FromSql impls
  • #[serde(default)] keeps existing API clients and pinned plots working: an omitted y_axis means auto, matching prior behavior
  • y_axis is included in JsonPlotPatch/JsonPlotPatchNull and UpdatePlot, so PATCH /v0/projects/{project}/plots/{plot} can change it in place
  • The d3 y-scale construction is extracted from LinePlot.tsx into scale.ts with unit tests covering all three modes and the zero/negative fallback

Testing

  • cargo nextest run -p bencher_json --features server and -p bencher_schema --features plus
  • Console npx vitest run, including new scale.test.ts
  • cargo clippy --no-deps --all-targets --all-features -- -Dwarnings, cargo check --no-default-features, cargo gen-types, Biome CI lint/format commands

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

PR: #947
Base: devel
Head: claude/plot-y-axis
Commit: 29461a5e9d3d4dc4281338ca6835db6e089e6aa1


I've reviewed the full diff. Here is my assessment.

Review: Add a Y-Axis scale toggle to perf plots

Overall this is a clean, well-tested, and complete change. It threads a new YAxis enum (Auto/Linear/Log) end-to-end: wire types → DB → CLI → console UI, with matching tests at each layer. It closely mirrors the existing x_axis plumbing, which makes it easy to verify for completeness.

Strengths

  • Consistent, complete plumbing. Every layer is updated symmetrically with x_axis: JsonNewPlot/JsonPlot/JsonPlotPatch(Null) + the manual JsonUpdatePlot deserializer (including the duplicate_field guard), QueryPlot/InsertPlot/UpdatePlot, CLI create/update, and all console prop chains (PerfPanelPerfFramePerfPlotPlotLinePlot, plus PinnedFrame, modals, and plotQueryString). The project's destructuring convention means any missed field would be a compile error, and I confirmed no non-test construction sites lack y_axis.
  • Strong typing per CLAUDE.md. YAxis is a real validated type with Diesel ToSql/FromSql impls and a thiserror error, integer-backed like XAxis. test_util.rs was even improved to pass XAxis::DateTime/YAxis::Auto instead of a raw 0.
  • Good test coverage. Serde round-trips, DB round-trip, apply_update for both axes, the get_y_scale unit tests (including the log→auto fallback for zero/negative mins), and the isYAxis guard tests. Tests use deterministic DateTime::TEST.
  • Nice refactor. Extracting the scale logic into scale.ts with a YScale union and preserving the existing .ticks()/.tickFormat()/callable interface makes the swap transparent to Observable Plot's mapY/axisY mechanism.
  • Migration correctness. Full table-rebuild is the dominant convention here (82 vs 2 ADD COLUMN), and the up/down correctly preserve the index_plot_project_created index added by a later migration (2025-12-29), backfilling y_axis = 0 (Auto). #[serde(default)] on JsonNewPlot.y_axis keeps the API backward compatible.

Correctness note (not a bug)

  • Log fallback is safe. get_y_scale(Log, ...) only uses d3.scaleLog when min > 0, else falls back to the auto pow scale. Since data_min is the minimum across all active series (primary + boundary/value), a positive min guarantees every plotted point (including boundaries) is positive, so mapY through the log scale can't produce NaN. Dividing by the positive unit factor preserves the sign, so the min > 0 check is valid. Good defensive handling, and the button/changelog copy explains the fallback to users.

Minor observations (optional)

  • The LinePlot change-detection effect uses an if/else if chain that handles one changed prop per run; y_axis was inserted at position 2. This matches the pre-existing pattern (Solid re-runs the effect until settled), so no behavior change, but it's worth being aware the chain relies on repeated effect runs to converge when multiple props change at once.
  • No explicit test that JsonNewPlot omitting y_axis deserializes to Auto, though #[serde(default)] + the covered YAxis::default() == Auto makes this low risk.

Standards compliance

  • No emdashes in code/comments/changelog/docs. ✅
  • y_axis uses a strong validated type with Diesel impls, not a raw i32. ✅
  • thiserror used for YAxisError; no anyhow/Box<dyn Error>. ✅
  • Changelog appended to the bottom of ## Pending; modified bumped to 2026-07-18. ✅
  • Generated openapi.json and bencher.ts are in sync with the Rust types. ✅

Verification I did not run: I reviewed statically but did not execute cargo nextest, cargo test --doc, cargo gen-types, or the console vitest suite. The CLI relies on bencher_client::types::YAxis being progenitor-generated from the updated openapi.json (which includes the YAxis schema), so it should build, but I'd recommend confirming a full cargo build + npx vitest run before merge.

One process reminder: per CLAUDE.md, since this PR changes the CLI (bencher plot create/update --y-axis), avoid auto-closing keywords (Closes #N) in the PR description.


Model: claude-opus-4-8

@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchclaude/plot-y-axis
Testbedintel-v1
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
microseconds (µs)
(Result Δ%)
Upper Boundary
microseconds (µs)
(Limit %)
Adapter::Json📈 view plot
🚷 view threshold
4.69 µs
(+0.94%)Baseline: 4.65 µs
4.90 µs
(95.71%)
Adapter::Magic (JSON)📈 view plot
🚷 view threshold
4.59 µs
(+1.56%)Baseline: 4.52 µs
4.72 µs
(97.18%)
Adapter::Magic (Rust)📈 view plot
🚷 view threshold
25.51 µs
(-0.45%)Baseline: 25.63 µs
26.75 µs
(95.39%)
Adapter::Rust📈 view plot
🚷 view threshold
3.52 µs
(+0.73%)Baseline: 3.50 µs
3.60 µs
(97.72%)
Adapter::RustBench📈 view plot
🚷 view threshold
3.52 µs
(+0.81%)Baseline: 3.49 µs
3.60 µs
(97.83%)
🐰 View full continuous benchmarking report in Bencher

@epompeii
epompeii force-pushed the claude/plot-y-axis branch from fc2cd65 to 04daea3 Compare July 18, 2026 03:19
Add a three-mode Y-Axis scale to perf plots: Auto, Linear, and Log.
Auto preserves the existing adaptive power scaling. Log uses a true
logarithmic scale and falls back to Auto when the data includes zero
or negative values. The selection is saved in the plot URL and restored
for pinned plots. It can be set at creation with `bencher plot create
--y-axis` and changed with `bencher plot update --y-axis`, the Perf
explorer "Update Pin" button, or the plot PATCH endpoint.
@epompeii
epompeii force-pushed the claude/plot-y-axis branch from 04daea3 to 29461a5 Compare July 18, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant