Summary
The WebGL viewer's hover and click value indicators (#mouseover_value / #picked_value) always read the first frame (verts[0] for vertex data, textures[0] for volume data) — they do not update with the currently rendered frame for movie / time-series dataviews. This affects every dataview type (1D and 2D, vertex and volume) whenever a cortex.Vertex / cortex.Volume / cortex.Vertex2D / cortex.Volume2D has more than one frame.
This is a pre-existing issue, not introduced by #635 — the original 1D handler was already hardcoded to [0]. Surfaced by Codex review on that PR (cortex/webgl/resources/js/mriview.js:762-764 is the new 2D path; the old 1D code had the same pattern).
Reproduction
- Build a movie dataview, e.g.
import numpy as np, cortex
data = np.random.randn(20, n_voxels) # 20 frames
v = cortex.Volume(data, 'S1', 'fullhead')
cortex.webgl.show(v)
- In the viewer, advance the frame via the movie UI (or
viewer.setFrame(t) with t > 0).
- Hover or click on the brain. The displayed value is the value at frame 0 for that vertex / voxel, not the value at the currently rendered frame.
Where it lives
In cortex/webgl/resources/js/mriview.js, both handlers index [0] directly:
- mousemove handler (vertex branch):
return d.verts[0][hemiIdx].array[vertex]
- mousemove handler (volume branch):
return d.textures[0].image.data[mouse_index]
- pick handler: same indexing in both branches.
The renderer, by contrast, uses DataView.setFrame() which advances this.frame and dispatches frame fframe and fframe+1 (with framemix for interpolation). See dataset.js VertexData.set / VolumeData.set.
Suggested fix
Replace the hardcoded [0] indexing with a frame derived the same way DataView.setFrame() does. Roughly:
const fframe = Math.floor(this.active.frame);
// vertex branch
return d.verts[fframe][hemiIdx].array[vertex];
// volume branch
return d.textures[fframe].image.data[mouse_index];
Edge cases to handle:
framemix > 0 (interpolation between frames). For the hover/click readout, displaying the value at the floor frame is probably fine — picking/hovering is discrete by design — but optionally we could lerp between fframe and (fframe+1) % frames by framemix for visual consistency with the rendered colormap.
- Static (single-frame) data:
fframe = 0 works as before.
- Bounds check:
fframe < d.verts.length / fframe < d.textures.length (should always be true if setFrame was called legitimately, but defensive).
Acceptance
- Movie data: hover/click readout matches the rendered frame as you scrub the movie slider.
- Static (1-frame) data: behavior unchanged.
- Both 1D and 2D, vertex and volume, RGB stays hidden as today.
🤖 Filed as a follow-up from PR #635 review.
Summary
The WebGL viewer's hover and click value indicators (
#mouseover_value/#picked_value) always read the first frame (verts[0]for vertex data,textures[0]for volume data) — they do not update with the currently rendered frame for movie / time-series dataviews. This affects every dataview type (1D and 2D, vertex and volume) whenever acortex.Vertex/cortex.Volume/cortex.Vertex2D/cortex.Volume2Dhas more than one frame.This is a pre-existing issue, not introduced by #635 — the original 1D handler was already hardcoded to
[0]. Surfaced by Codex review on that PR (cortex/webgl/resources/js/mriview.js:762-764 is the new 2D path; the old 1D code had the same pattern).Reproduction
viewer.setFrame(t)witht > 0).Where it lives
In
cortex/webgl/resources/js/mriview.js, both handlers index[0]directly:The renderer, by contrast, uses
DataView.setFrame()which advancesthis.frameand dispatches framefframeandfframe+1(withframemixfor interpolation). Seedataset.jsVertexData.set/VolumeData.set.Suggested fix
Replace the hardcoded
[0]indexing with a frame derived the same wayDataView.setFrame()does. Roughly:Edge cases to handle:
framemix > 0(interpolation between frames). For the hover/click readout, displaying the value at the floor frame is probably fine — picking/hovering is discrete by design — but optionally we could lerp betweenfframeand(fframe+1) % framesbyframemixfor visual consistency with the rendered colormap.fframe = 0works as before.fframe < d.verts.length/fframe < d.textures.length(should always be true ifsetFramewas called legitimately, but defensive).Acceptance
🤖 Filed as a follow-up from PR #635 review.