Skip to content

Overplot Ip / Bt / β context on all time-series plots (+ fetch βN) #58

Description

@matt-pharr

Summary

Add Ip / Bt / β (βN) as first-class context signals and let the operator overplot them
on any time-series plot
. When a fit goes wonky at some time, overlaying the global plasma
context makes the cause obvious at a glance — an Ip spike, a Bt ramp, or β collapsing (an ELM /
minor disruption) lines up with the feature in the magnetics.

The overlay must be generic — available on every time-series view (raw signals, amplitude
& phase vs time, χ²(t), φ(t), n(t) …), not bolted onto one plot — because the whole point is to
correlate an anomaly in any trace against the machine context.

What already exists (don't rebuild it)

  • Ip and Bt are already fetched on every pull — data/signals.py::AUX = ["ip", "bt"], pulled
    for all analyses via ANALYSIS_GROUPS[...] += "AUX". They land in the HDF5 and are readable
    through h5source.load_channel(shot, "ip"|"bt").
  • κ (elongation) already comes from the EFIT tree — signals.TREE_SIGNALS["kappa"] — and is
    already consumed (nodes._kappa_at). This is the exact template for adding β.
  • The line kind exists (core/contracts.line) and the GUI renders it generically.

So most of the fetch plumbing is in place. Two real gaps remain.

Gap 1 — β/βN is not fetched

βN lives in the EFIT tree, not PTDATA, so it needs a TREE_SIGNALS entry exactly like kappa:

  • Add to data/signals.py::TREE_SIGNALS a "betan" (and probably "beta" / "li") entry with
    (tree, node) candidates — e.g. ("efit01", r"\betan"), aeqdsk fallbacks — mirroring the kappa
    candidate list.
  • Add those names to ANALYSIS_TREE_SIGNALS for quasi-stationary / rotating / both.
  • No fetcher code changes needed — the tree-signal path (toksearch._*_tree_channels) already
    resolves candidate lists generically.

(Decide: βN vs β vs stored energy — βN is the usual "did we just have an ELM/βN collapse" quantity;
li is cheap to grab alongside and useful. Keep the set small.)

Gap 2 — the line node/renderer has no secondary axis or context overlay

contracts.line today is just {series, axes} with a single y-scale. Ip (~MA), Bt (~T), and βN
(~O(1)) live on wildly different scales than the magnetics traces, so overplotting needs a
secondary y-axis and per-context-trace scaling. Proposed generic mechanism:

  1. Contract: extend the line kind (both core/contracts.py and gui/web/src/lib/contract.ts)
    with an optional context list — traces the renderer draws on a secondary axis (each with its
    own label/units/scale), distinct from the primary series. Keep it a first-class field so
    every line view inherits it for free.
  2. A context provider the GUI can fetch once per shot. Options:
    • a new context_traces node kind that returns Ip/Bt/βN(/κ/li) as {t, y, label, units}, or
    • a small /api/context/{shot} endpoint.
      Fetched once, cached, and reused across all time-series views (these are cheap, coarse EFIT/scalar
      traces — a few hundred points).
  3. GUI (generic line renderer): a toggle set ("Ip / Bt / βN") that overlays the chosen context
    traces on the right-hand axis of any line plot, sharing the plot's time axis and the global time
    cursor. Off by default; state ideally shared across tabs so a toggle sticks as the user moves views.

Why this belongs in the generic renderer, not per-view

If each analysis node has to hand-assemble its own Ip/Bt overlay, the feature will be inconsistent
and half the plots won't have it. Putting context on the line kind + overlay logic in the shared
line renderer means it "just works" on raw signals, phase-vs-time, χ²(t), φ(t), n(t), and anything
added later.

Open questions

  • βN vs β vs Wmhd (+ li?) — which context set ships? (lean: Ip, Bt, βN, and κ which is already there)
  • Secondary-axis policy when 2–3 context traces are on at once — one shared normalized axis, or one
    axis per trace? (Normalized/overlaid with a small legend is simplest and readable.)
  • Should the time cursor readout show the context values at the cursor time (Ip=…, βN=… at t)?
  • Auto-annotate obvious events (ELM/βN-drop, Ip spike) as vertical markers — nice follow-up, separate.

Touch points

  • src/magnetics/data/signals.py — add βN(/β/li) to TREE_SIGNALS + ANALYSIS_TREE_SIGNALS
  • src/magnetics/core/contracts.pygui/web/src/lib/contract.tscontext on the line kind
  • src/magnetics/service/nodes.py (+ maybe service/app.py) — a context_traces node / endpoint
  • gui/web/.../ shared line renderer — the overlay toggles + secondary axis + cursor readout

Cross-team: Data Streamers own the βN fetch, Interfacers own the line-kind contract + generic
renderer; both analysis teams get the overlay for free. Worth a quick Slack/PR before implementing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions