Skip to content

Allow viewer data to be updated in real-time (supersedes #142) - #675

Merged
mvdoc merged 2 commits into
mainfrom
claude/pr-142-merge-tests-njui5w
Aug 21, 2026
Merged

Allow viewer data to be updated in real-time (supersedes #142)#675
mvdoc merged 2 commits into
mainfrom
claude/pr-142-merge-tests-njui5w

Conversation

@mvdoc

@mvdoc mvdoc commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Supersedes #142 by @r-b-g-b, whose branch predates the history rewrite and can no longer be merged (refusing to merge unrelated histories). The idea and the original patch are theirs; this re-applies them to current main, fixes what no longer fit, and adds tests.

What this does

JSMixer.addData lets you push new data into an already running cortex.webshow viewer, without restarting the server:

client = cortex.webshow(volume)
client.addData(second=other_volume)

Why the original patch needed rework

addData on main was dead code in two ways:

  • it called _convert_dataset(Dataset(...)), and neither name exists in cortex.webgl.view — any call raised NameError (there was an xfailed test pinning exactly that);
  • it proxied to window.viewers.addData, but mixer.html only ever defines window.viewer, a mriview.Viewer rather than the mriview.MultiView the original patch modified.

Changes

  • show() keeps the packaged metadata as a dict instead of a JSON string, and serializes it when the mixer page is generated (this part is unchanged from Allow viewer data to be updated in real-time #142). That is what lets addData merge new dataviews into it, so reloading the page shows everything added so far.
  • addData builds a Package for the new dataviews, runs Package.reorder against the ctm files the viewer was started with (vertex data is uploaded as a raw vertex attribute array, so it has to match the CTM vertex order), registers the new images with the data handler, merges the metadata, and sends only the new dataviews to the browser — Allow viewer data to be updated in real-time #142 sent the whole accumulated metadata, which would re-create every brain on each call.
  • Adding a name that is already displayed replaces it, and the images of the replaced dataview are dropped, so repeatedly refreshing the same dataview does not pile up unused image buffers in the server.
  • Data for a subject the viewer was not started with is rejected with a clear ValueError, since surfaces are baked into the page at startup and cannot be added to a running viewer.
  • mriview.Viewer.addData (and mriview.MultiView.addData) accept the raw metadata package in addition to dataset.DataView objects.

Tests

The xfailed test_addData_no_crash is replaced by a TestAddData group in cortex/tests/test_webgl_headless.py covering:

  • the new dataview being registered and becoming the active one, with no JS page errors;
  • the metadata served by mixer.html after the call, including that every referenced image URL still returns a PNG;
  • the rendered image actually changing when switching between the original and the added dataview;
  • re-adding a name replacing it rather than duplicating it, and the replaced brain being pruned;
  • the unknown-subject ValueError.

Plus test_addData_vertex_data, which exercises the reorder path and checks the added vertex data is served as a raw .npy blob rather than a PNG mosaic.

All six fail against the pre-fix code (NameError) and pass with it; the two pruning assertions were separately confirmed to fail without the pruning change.

🤖 Generated with Claude Code

https://claude.ai/code/session_013MCFG1Uez4JMFZK65KeTeT


Generated by Claude Code

Rebases and completes GH-142: `JSMixer.addData` lets you push new data
into an already running `cortex.webshow` viewer, without restarting the
server:

    client = cortex.webshow(volume)
    client.addData(second=other_volume)

The method was dead code -- it referenced `_convert_dataset` and
`Dataset`, neither of which exists in `cortex.webgl.view`, so any call
raised `NameError`, and it proxied to `window.viewers`, which the mixer
page never defines.

Changes:

- `show()` keeps the packaged metadata as a dict instead of a JSON
  string, and serializes it when the mixer page is generated. That lets
  `addData` merge new dataviews into it, so a page reload shows
  everything that has been added so far.
- `addData` builds a `Package` for the new dataviews, reorders vertex
  data against the ctm files the viewer was started with, registers the
  new images with the data handler, merges the metadata, and sends only
  the new dataviews to the browser. Adding a name that is already
  displayed replaces it, and the images of the replaced dataview are
  dropped so that repeatedly refreshing data does not pile up unused
  buffers in the server. Data for a subject the viewer was not started
  with is rejected with a clear `ValueError`, since surfaces cannot be
  added to a running viewer.
- `mriview.Viewer.addData` (and `mriview.MultiView.addData`) now accept
  the raw metadata package in addition to `dataset.DataView` objects.

Tests: the `xfail`-ed `test_addData_no_crash` is replaced by a
`TestAddData` group covering dataview registration and switching, the
metadata served on reload, the rendered image actually changing, name
replacement and the pruning that goes with it, and the unknown-subject
error, plus a separate test for vertex data (which exercises the
reorder path).
Brings in #681, which fixes vmin/vmax being left as numpy float32 when not
specified. That matters here: since show() now serializes the metadata at
page-generation time rather than once at startup, a dataview with computed
vmin/vmax made every subsequent GET /mixer.html fail with
"Object of type float32 is not JSON serializable" -- so addData could
silently leave a running viewer unable to reload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLJk77nSbbqh7QRFzhWbmB
@mvdoc
mvdoc merged commit d8c0cf1 into main Aug 21, 2026
12 checks passed
@mvdoc
mvdoc deleted the claude/pr-142-merge-tests-njui5w branch August 21, 2026 00:13
mvdoc added a commit to mvdoc/pycortex that referenced this pull request Aug 21, 2026
* origin/main: (44 commits)
  WebGL viewer: make opacity slider and `o` toggle work for Vertex data (gallantlab#685)
  docs(mapper): add get_mapper docstring (gallantlab#686)
  ENH add types for dataset classes (BrainData, Dataview, ...) (gallantlab#669)
  Allow viewer data to be updated in real-time (gallantlab#675)
  FIX: fix minor bug in handling of vmin and vmax when not specified (replaces old cast code) (gallantlab#681)
  docs: correct the sulcus install instructions, which destroyed existing sulci (gallantlab#657)
  WebGL viewer: fix help-menu shortcut display (gallantlab#642)
  MNT ignore docs build outputs written into the source tree (gallantlab#680)
  DOC fix build warnings (gallantlab#673)
  webgl: bind an OS-assigned ephemeral port for the viewer server (gallantlab#676)
  ENH add types for Database and transforms (gallantlab#667)
  MNT remove obsolete Python 2 syntax, add some types (gallantlab#666)
  Bump JamesIves/github-pages-deploy-action from 4.8.0 to 4.9.0 (gallantlab#671)
  Bump actions/setup-python from 6 to 7 (gallantlab#661)
  docs: document in-browser sulcus drawing (pycortex-roidraw v0.4.0) (gallantlab#656)
  ENH Pure-python surf2surf matrix (direct nnfr construction) (gallantlab#651)
  Bump actions/cache from 5 to 6 (gallantlab#654)
  webgl: fix overlay/label async texture-bake races (complete) (gallantlab#653)
  docs: add in-browser ROI drawing (pycortex-roidraw) page (gallantlab#652)
  FIX: update BuWtRd and BuWtRd_alpha colormaps to have pure white at center, more sensible for biphasic data (gallantlab#649)
  ...

# Conflicts:
#	cortex/quickflat/composite.py
#	cortex/utils.py
#	cortex/webgl/resources/js/shaderlib.js
#	cortex/webgl/view.py
alexhuth pushed a commit that referenced this pull request Aug 21, 2026
Rebases and completes GH-142: `JSMixer.addData` lets you push new data
into an already running `cortex.webshow` viewer, without restarting the
server:

    client = cortex.webshow(volume)
    client.addData(second=other_volume)

The method was dead code -- it referenced `_convert_dataset` and
`Dataset`, neither of which exists in `cortex.webgl.view`, so any call
raised `NameError`, and it proxied to `window.viewers`, which the mixer
page never defines.

Changes:

- `show()` keeps the packaged metadata as a dict instead of a JSON
  string, and serializes it when the mixer page is generated. That lets
  `addData` merge new dataviews into it, so a page reload shows
  everything that has been added so far.
- `addData` builds a `Package` for the new dataviews, reorders vertex
  data against the ctm files the viewer was started with, registers the
  new images with the data handler, merges the metadata, and sends only
  the new dataviews to the browser. Adding a name that is already
  displayed replaces it, and the images of the replaced dataview are
  dropped so that repeatedly refreshing data does not pile up unused
  buffers in the server. Data for a subject the viewer was not started
  with is rejected with a clear `ValueError`, since surfaces cannot be
  added to a running viewer.
- `mriview.Viewer.addData` (and `mriview.MultiView.addData`) now accept
  the raw metadata package in addition to `dataset.DataView` objects.

Tests: the `xfail`-ed `test_addData_no_crash` is replaced by a
`TestAddData` group covering dataview registration and switching, the
metadata served on reload, the rendered image actually changing, name
replacement and the pruning that goes with it, and the unknown-subject
error, plus a separate test for vertex data (which exercises the
reorder path).

Co-authored-by: Claude <noreply@anthropic.com>
@kroq-gar78

Copy link
Copy Markdown
Contributor

This PR may have introduced a race condition. See this failed run for an unrelated change: https://github.com/gallantlab/pycortex/actions/runs/32525918728/job/96907786022

FAILED cortex/tests/test_webgl_headless.py::test_addData_vertex_data - OSError: image file is truncated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants