Increased GUI font sizes#74
Closed
amichaellu wants to merge 24 commits into
Closed
Conversation
"Sensor visualization unavailable. The HDF5 file for this shot has not been fetched yet. Use the pull panel in the left sidebar to fetch the data."
- "coils" header → "Coils" - Removed the "coils" overlay checkbox - Added a "DIII-D first wall" legend label in 3D viewer
Every Plotly figure gets a hover toolbar to save the plot as PNG (2× raster)
or SVG (vector — prints to PDF from any viewer), and node-backed plots get a
"Data" button that downloads that node's arrays as a self-describing HDF5 file.
- service/export.py: node_to_hdf5() — one generic serializer mapping each `kind`
(contour/heatmap/scatter2d/line/equilibrium/metrics) to datasets + root attrs
(kind/title/axes/shot/node_id/params), with a fallback dump for unknown kinds.
- service/app.py: GET /api/node/{shot}/{node_id}/download streams the file
(application/x-hdf5 attachment); forwards + records the view query params so a
download matches what's on screen. 404/422 mapping mirrors the node route.
- Plot.tsx: hover toolbar (PNG/SVG via Plotly.downloadImage + optional Data link),
new exportName/download props. Image export works on every plot for free.
- api.ts nodeDownloadUrl(); NodeView forwards the props (metrics panel gets a data
link). Tabs thread the download descriptor into node-backed plots; client-derived
plots point their Data button at the source node they're computed from.
Tests: serializer per-kind + every builder downloads valid HDF5 (backend);
nodeDownloadUrl + metrics data-link (frontend).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
kappa (elongation) and other EFIT-tree signals came back "no data" on the toksearch/remote backend while PTDATA channels succeeded. Root cause: the remote backend runs the cluster interpreter directly (no conda activate / module load), so the MDSplus tree-path env EFIT needs is never set and a local `MdsSignal` tree open fails for every candidate. PTDATA is local and needs no env, so it worked. Fix: don't use `MdsSignal` for tree signals. The cluster is on-network, so open a direct mdsip connection to the device's server (network.mdsip → atlas.gat.com:8000) and reuse the mdsthin path's proven openTree->get fetch — the same server the mdsthin backend already resolves kappa through. A connection failure degrades to not-ok Channels so the PTDATA pull still completes. - _fetch_toksearch: drop the MdsSignal pipeline registration/resolution; take a `server` arg and delegate tree signals to the new _toksearch_tree_channels. - fetch_shot passes the resolved mdsip server through. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Optional pre-gate 2-D Gaussian blur of the rotating spectrogram so contiguous coherent structure survives aggressive gating: smooth_spectrogram (power + coherence) and smooth_mode_spectrogram (n-map quality + amplitude) in core, run before denoise_spectrogram and applied consistently across the spectrogram / coherence / n-spectrum / n-map nodes. Two fixes make it actually visible: - σ in grid cells, not ms/kHz. Physical widths mapped to sub-bin σ on the coarse STFT grid (2 ms slice → 0.5 kHz bins; time-decimated columns), so the defaults rounded to a near-no-op and moving the sliders did nothing. Cells are one STFT bin, resolution-relative, and can't collapse below a bin. The GUI shows the physical equivalent per live grid (e.g. "3.0 cells ≈ 6.0 ms") via the new pure medianStep helper. Params: smooth_t_cells / smooth_f_cells. - Smooth LINEAR power (arithmetic mean), not log power. A log/geometric mean is dominated by the darkest cell, so a punched-out ridge gap stayed dark and never survived the gate. Linear averaging is pulled toward the bright cells, so a ridge bleeds into and fills its dim neighbours — the whole point of the pass. Contract (CONTRACT.md) + plan docs updated. Tests: core smooth incl. ridge-gap reinforcement, node smoke/no-op, medianStep. Full suite 222 passed / 1 skipped; frontend tsc + 26 vitest green; ruff clean. Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add an `api` entry to .claude/launch.json (uvicorn on :8000, --reload) so the FastAPI backend can be launched alongside the web dev server. Re-resolve uv.lock (drop the stale exclude-newer pin; loosen a pexpect marker). Co-Authored-By: Claude Opus 4.8 <[email protected]>
Plotly's image exporter paints the plot margins with paper_bgcolor, which is transparent on screen so it blends with the panel. On export that transparency flattened to grey in most viewers. Temporarily set paper_bgcolor to the live --panel color (white in light mode, near-black in dark) around the download and restore it after; the swap is invisible on screen since the plot already sits on that color. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The HDF5 writer call sat outside the download route's try/except, so a node that built cleanly (200 on /api/node) could still 500 the download with a raw stack trace if serialization failed. Wrap it and map any writer error to a clean, logged 500. Also switch scatter2d label/group datasets from fixed-width "S" to utf-8 vlen strings: a φ/θ/µ-decorated sensor label would raise UnicodeEncodeError under "S". Adds regression tests for both and corrects the _num_array docstring, which claimed the object-dtype fallback "still succeeds" (h5py can't store it). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(gui): per-node plot image + HDF5 data export
The offline suite reached _toksearch_tree_channels only through its two early returns and exercised the shared _mdsthin_tree_channels via a single-candidate stub, so the code this PR actually adds -- the wrapper's host normalization, the MDSplus->mdsthin import fallback, and the connection-failure degradation branch -- plus the multi-candidate fallthrough that production always uses for kappa were untested. Add tests that inject a fake Connection to drive the wrapper's success path (asserting host normalization), the mdsthin fallback when MDSplus is absent, and graceful degradation to not-ok Channels when connect() raises; plus _mdsthin_tree_channels coverage for second-candidate-wins (on both degenerate data and open failure), degenerate/non-finite-time rejection, and client-side window trim. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…fetch fix(fetch): fetch EFIT tree signals via mdsip on the toksearch backend
…name The coils cleanup replaced the generic `meta.coils` overlay (which renders whatever coil sets any device config supplies) with a default-on check against the literal sensor-set name "All 3D Coils" — a DIII-D-only string. On any other device (e.g. NSTX-U, whose coils exist only as `meta.coils`, with no coil-kind sensor set) coils no longer rendered by default and had no toggle at all. Restore the generic overlay: bring back the `showCoils` state, the 2D footprint and 3D-loop render blocks, the overlays checkbox, and the `showCoils` memo deps; remove the `"All 3D Coils"` magic default. This also un-orphans the `CoilSet` interface and `GeoMeta.coils` field (dead after the readers were removed). The PR's other changes are kept: the pre-fetch 404 message, the per-loop tilt saddle-loop orientation, the wall legend proxy, and the label capitalizations. Verified with Playwright against DIII-D 184927 (fetched live): coils render in 2D + 3D, checkbox on by default, and unchecking removes the coil traces. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
SensorsTab additions: adding pre-fetch message, sensor array checkbox cleanup
Follow-up patch to the 2-D Gaussian pre-smoothing in this feature: it blurred *linear* power, which haloed bright ridges and, viewed on the log heatmap, *raised* the visible log-variance instead of lowering it — so the blur was effectively invisible. Smooth log10 power (then map back) so the blur is uniform across the dynamic range and matches both the display and the log-power gate; coherence stays linear. Real-shot log-variance now drops monotonically with sigma. Co-Authored-By: Claude Opus 4.8 <[email protected]>
…ooth test - app.py: drop the raw exception text from the /download 500 body (keep it in logger.exception) so an h5py/OSError message can't leak to the client - contract.ts: type HeatmapNode.z as (number | null)[][] to match the denoise-gated cells the server now emits as null - test_nodes.py: assert the smoothed spectrogram z actually differs from the baseline, so a no-op regression in the smooth-param wiring fails
The contract change typed HeatmapNode.z as (number | null)[][] to match the denoise-gated cells the server emits as null. tsc -b (strict project build) then flagged three RotatingTab consumers that assumed number[][]: - cursor-column power trace: null cell → NaN so the log trace gaps there - live coherence column: coalesce a gated/absent cell to 0 - stripePlot: widen its param to (number | null)[][]; Plotly renders null as gaps
Rotating live wiring
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Increased default GUI font sizes - tried adding settings dropdown with clickable font increase/decrease feature, but it was worse than zooming in/out on Google Chrome.