Skip to content

FE-1513: Contour plot over two swept parameters, navigable in real time - #9369

Merged
kube merged 4 commits into
cf/fe-1263-experiment-parameter-rangesfrom
cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real
Sep 3, 2026
Merged

FE-1513: Contour plot over two swept parameters, navigable in real time#9369
kube merged 4 commits into
cf/fe-1263-experiment-parameter-rangesfrom
cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real

Conversation

@kube

@kube kube commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Important

Experimental
Behind the Parameter sweeps feature flag.

Summary

Before this PR, a sweep's results drawer shows one combination at a time. Navigator selects it and its metric charts stream. There is no view of a metric across the swept grid.

A sweep with two or more swept parameters gains a Surface section under its metrics: a filled contour of one metric's final value over two chosen parameters, in the style of Optuna's plot_contour. Every other parameter is held at its navigator value. Plot fills in live as the view walks the X×Y grid coarse-to-fine at 8 runs per combination. Clicking the surface moves the navigator to the nearest combination, whose ladder then refines it.

Links

Changes

UI

  • sweep-surface.tsx adds pickers, canvas, click-to-navigate, and caption

    X/Y/metric pickers, a canvas the pure module paints, and a caption counting sampled combinations.
    Canvas is device-pixel aware and dots sampled combinations.
    Walk restarts when the slice, axes, or metric changes.
    Unmounting stops it.

  • Context gains sampleSweepCell(experimentId, values, minRuns)

    Delegates to the session.

Contour grid and sampling

  • New pure module react/experiments/contour-grid.ts holds the surface maths

    Inverse-distance-weighted rasterization, marching-squares iso-lines with saddle resolution, the ColorBrewer Blues ramp, the coarse-to-fine sampling order, and final-frame objective extraction.
    Rasterization reads sensibly at every fill stage, from blobs around the first samples converging to the surface.
    Sampling order takes corners and lattice midpoints first.

  • react/experiments/sweep-session.ts gains a background sampling lane

    sampleCell(values, minRuns) brings any combination up to a minimum run count with serialized batches of one CPU worker each, under the same seed-ladder rule, so the navigator's sharded batch keeps the cores.
    A cell sampled here and later visited by the navigator resumes the identical run sequence into the same cache.

  • Navigator lane now calls handle.start()

    It never did. Hand-driven test fakes hid it and now refuse to stream before start.

Test coverage

  • contour-grid.test.ts, 10 tests:

    Sampling order coverage and priority, IDW exactness at samples and single-sample flatness, marching squares on a ramp, level placement, ramp endpoints, objective extraction from final frames.

  • sweep-session.test.ts, two new tests:

    Background batches serialize on the same seed ladder with background: true.
    Cells already deep enough resolve from cache with no batch.

  • Verified live in Storybook:

    Progressive fill with a 49/50 mid-walk caption, iso-lines and sample dots, click moving the navigator from transmission_rate 0.3 to 0.4 and recovery_days 8 to 14.

How to test

  • Open Petrinaut preview on Vercel
  • Viewport controls > Settings > Simulation > Parameter sweeps
  • Load example, select scenario with at least two numeric parameters
  • Simulate > Experiments > Create
  • Flip Sweep on two parameters, Run
  • Open experiment, scroll to Surface
  • Expect contour to fill in over a few seconds
  • Click around surface
  • Expect Parameters strip to follow
  • Change X, Y, or metric
  • Expect fill to restart

@kube kube self-assigned this Aug 27, 2026
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 2, 2026 7:54pm UTC
petrinaut Ready Ready Preview Sep 2, 2026 7:54pm UTC
petrinaut-docs Ready Ready Preview Sep 2, 2026 7:54pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 2, 2026 7:54pm UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team labels Aug 27, 2026
@kube
kube force-pushed the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch from e937d32 to cb2b00d Compare August 27, 2026 16:40
@kube
kube force-pushed the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch from cb2b00d to e09a224 Compare August 27, 2026 18:24
@kube
kube force-pushed the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch from e09a224 to c9d777c Compare August 30, 2026 13:08
@kube
kube force-pushed the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch from c9d777c to 383d025 Compare September 1, 2026 23:17
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches sweep compute scheduling and experiment batch lifecycle (including the navigator start() fix); background work is isolated but adds concurrent load and cache-merge edge cases alongside existing sweep sessions.

Overview
Multi-parameter sweeps get a Surface section in the experiment drawer: an Optuna-style filled contour of one metric’s final value over two chosen axes, with other parameters fixed to the navigator slice.

Compute and session: sweep-session adds a serialized background lane (sampleCell) that runs 8-run batches with background: true, shares the combination cache and seed ladder with the navigator, and resolves from cache when a cell is already deep enough. The experiments provider exposes sampleSweepCell and routes background CPU batches through a lazy single-worker pool so navigator sharding keeps the cores. Navigator batches now call handle.start() (previously missing).

Rendering: New pure contour-grid module (coarse-to-fine grid walk, IDW raster, marching-squares iso-lines, Blues ramp, objective from final metric frames) backs SweepSurface—axis/metric pickers, progressive sampling while open, canvas redraw, and click-to-navigate to the nearest grid cell. User and architecture docs plus a changeset describe the feature.

Reviewed by Cursor Bugbot for commit 72ce138. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Initialization, cache refresh, cancellation, sampling order, and accessibility issues affect core behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a live contour surface for multi-parameter sweeps, backed by progressive background sampling.

Changes:

  • Adds contour interpolation, rendering, navigation, and controls.
  • Extends sweep sessions with serialized background sampling.
  • Adds tests, fixtures, user documentation, and architecture documentation.
File summaries
File Description
.changeset/sweep-surface-contour.md Records the Petrinaut patch release.
libs/@hashintel/petrinaut/docs/experiments.md Documents the surface view.
libs/@hashintel/petrinaut/src/react/experiments/context.ts Exposes background cell sampling.
libs/@hashintel/petrinaut/src/react/experiments/contour-grid.ts Implements contour mathematics and ordering.
libs/@hashintel/petrinaut/src/react/experiments/contour-grid.test.ts Tests contour utilities.
libs/@hashintel/petrinaut/src/react/experiments/provider.tsx Connects sampling to compute backends.
libs/@hashintel/petrinaut/src/react/experiments/sweep-session.ts Adds the background sampling lane.
libs/@hashintel/petrinaut/src/react/experiments/sweep-session.test.ts Tests background sampling behavior.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/create-experiment-drawer.test.tsx Updates the test context fixture.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/experiments-story-fixtures.tsx Adds a synthetic contour data source.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/sweep-surface.tsx Implements the interactive canvas surface.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/view-experiment-drawer.tsx Adds the Surface drawer section.
libs/@local/petrinaut-arch-docs/content/diagrams/sweep-surface-feed.d2 Diagrams the sampling flow.
libs/@local/petrinaut-arch-docs/content/experiments/sweep-surface.mdx Documents the surface architecture.
Review details

Suppressed comments (2)

libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/view-experiment-drawer.tsx:403

  • Section keeps collapsed content mounted by default (src/ui/components/section.tsx:172,198,226-227), so collapsing Surface leaves this component's sampling effect running through the whole grid. Set unmountOnCollapse so closing the section actually stops the background walk.
              collapsible
              defaultOpen

libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/view-experiment-drawer.tsx:405

  • ExperimentsView passes different selected records through the same drawer instance (experiments-view.tsx:152-156), while SweepSurface initializes its axis and metric IDs only on first mount. Switching directly between experiments can retain IDs absent from the new experiment, making all three controls invalid and leaving the surface blank. Remount this stateful component per experiment.
              <SweepSurface experiment={experiment} />
  • Files reviewed: 14/14 changed files
  • Comments generated: 5
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread libs/@hashintel/petrinaut/src/react/experiments/contour-grid.ts
Comment thread libs/@hashintel/petrinaut/src/react/experiments/sweep-session.ts
Comment thread libs/@hashintel/petrinaut/src/react/experiments/provider.tsx
Comment thread libs/@hashintel/petrinaut/src/react/experiments/sweep-session.ts
kube added 4 commits September 2, 2026 21:33
sampleCell brings any combination up to a minimum run count off the
navigator's lane: serialized single-worker batches on the same seed
ladder, folding into the same cache, so a sampled cell and a visited
cell are the same thing. Also fixes the navigator lane never calling
handle.start() — the test fakes were hand-driven and hid it; they now
refuse to stream before start.
An Optuna-style filled contour of one metric's final value over two
swept parameters. The view walks the grid coarse-to-fine through the
background lane, so the surface's shape appears within the first few
sampled combinations and sharpens as cells land; the pure module
(IDW interpolation, marching squares, the Blues ramp) is tested apart
from the canvas. Clicking the surface moves the navigator; the fixed
parameters' navigator values slice the grid, and changing them restarts
the walk.
User guide, architecture page with the sampling-feed diagram, and the
changeset; the surface's axis and metric selects become compact inline
controls.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 72ce138. Configure here.

@kube
kube added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit 21ab8f1 Sep 3, 2026
119 checks passed
@kube
kube deleted the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch September 3, 2026 12:07
@kube
kube restored the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch September 3, 2026 12:26
@kube
kube deleted the cf/fe-1513-contour-plot-over-two-swept-parameters-navigable-in-real branch September 3, 2026 12:37
@hash-release hash-release Bot mentioned this pull request Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants