Skip to content

Add visualization for cortical depth profiles - #738

Open
sunaguo wants to merge 16 commits into
gallantlab:mainfrom
sunaguo:main
Open

sunaguo wants to merge 16 commits into
gallantlab:mainfrom
sunaguo:main

Conversation

@sunaguo

@sunaguo sunaguo commented Sep 17, 2026

Copy link
Copy Markdown

Visualize laminar data with quickflat tool or webgl.
Closes #731.

quickflat/laminar.py

Given two points (flatmap coordinates) on the surface, grab cortical depth data along the line that connects the two points.

webgl

Ports quickflat/laminar.py into the browser: draw a line across the flatmap and get the W x H matrix spanning that line (gamma) and cortical depth (alpha, pial to white matter), sampled from the volume.

Everything is computed client-side, nothing is round-tripped to python:

laminar.js FlatIndex is a uniform grid over the flatmap triangles,
standing in for the scipy Delaunay/trifinder (the flatmap
already carries its own triangulation). For each of the W+1
columns it locates the flatmap point and barycentrically
interpolates the pial position, the white matter position
and the two surface areas -- _column_geometry(), once per
column rather than once per pixel.

Shaders.laminar Per fragment, turns alpha into an equivolume depth
(_depth_blend), mixes pial/wm to get that pixel's own
anatomical coordinate, pushes it through volxfm and samples

  • colormaps it via the same colorlut() the surface shader
    uses. So each panel pixel maps to its own point in the
    volume, and vmin/vmax/colormap/sampler follow the dataview.

The line lives in the shared, nudged flatmap space (the uv attribute), which is the same merged space laminar.py triangulates. That makes the profile independent of the view state and lets a line run across both hemispheres, with columns landing in the gap coming out transparent.

The line is drawn into a flatmap-space texture that the surface shader composites through vUv alongside the ROI overlay, so it sits on the cortex in every view -- flattened, inflated or folded -- with the right occlusion. Endpoints are dragged from a screen-space overlay that is only active while the brain is flat.

UI: a "depth profile" folder (show / equivolume / samples / depths / reset_line, shortcut J) and a draggable panel. The readout reports the endpoints in raw flatmap units, i.e. the arguments make_laminar_profile() takes.

Verified against cortex.quickflat.laminar on S1: the columns computed in the browser match _column_geometry to within CTM quantization (<0.002 voxels). The equivolume spacing uses the viewer's smoothed per-vertex areas rather than laminar.py's raw triangle areas, so the profile's depths agree with what the surface shader draws at the same depth.

sunaguo and others added 16 commits August 20, 2026 15:13
Ports quickflat/laminar.py into the browser: draw a line across the
flatmap and get the W x H matrix spanning that line (gamma) and cortical
depth (alpha, pial to white matter), sampled from the volume.

Everything is computed client-side, nothing is round-tripped to python:

  laminar.js  FlatIndex is a uniform grid over the flatmap triangles,
              standing in for the scipy Delaunay/trifinder (the flatmap
              already carries its own triangulation). For each of the W+1
              columns it locates the flatmap point and barycentrically
              interpolates the pial position, the white matter position
              and the two surface areas -- _column_geometry(), once per
              column rather than once per pixel.

  Shaders.laminar  Per fragment, turns alpha into an equivolume depth
              (_depth_blend), mixes pial/wm to get that pixel's own
              anatomical coordinate, pushes it through volxfm and samples
              + colormaps it via the same colorlut() the surface shader
              uses. So each panel pixel maps to its own point in the
              volume, and vmin/vmax/colormap/sampler follow the dataview.

The line lives in the shared, nudged flatmap space (the uv attribute),
which is the same merged space laminar.py triangulates. That makes the
profile independent of the view state and lets a line run across both
hemispheres, with columns landing in the gap coming out transparent.

The line is drawn into a flatmap-space texture that the surface shader
composites through vUv alongside the ROI overlay, so it sits on the
cortex in every view -- flattened, inflated or folded -- with the right
occlusion. Endpoints are dragged from a screen-space overlay that is
only active while the brain is flat.

UI: a "depth profile" folder (show / equivolume / samples / depths /
reset_line, shortcut J) and a draggable panel. The readout reports the
endpoints in raw flatmap units, i.e. the arguments make_laminar_profile()
takes.

Verified against cortex.quickflat.laminar on S1: the columns computed in
the browser match _column_geometry to within CTM quantization (<0.002
voxels). The equivolume spacing uses the viewer's smoothed per-vertex
areas rather than laminar.py's raw triangle areas, so the profile's
depths agree with what the surface shader draws at the same depth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add cortical depth profiles to the webgl viewer
@mvdoc

mvdoc commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Something funky is happening with roi labels with this PR

image

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.

add PR for laminar visualization

3 participants