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

    Fields

    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