In-browser ROI and sulcus drawing¶
pycortex-roidraw is a drop-in add-on that lets you draw, edit, and export ROIs and sulci directly in a pycortex WebGL viewer — no Inkscape and no re-generation of the viewer required. You draw on the flattened cortical surface; the stroke is fitted to a smooth, re-editable bezier curve, drawn as a colored outline and label baked into the surface.
ROIs are closed curves that carry per-hemisphere vertex membership and export to a portable
JSON vertex set. Sulci are open curves that carry no vertex data and export as a standalone SVG
whose sulci layer is the same representation pycortex already uses for sulci.
It ships as a single self-contained bundle (roidraw.bundle.js, CSS included) that can be added
to any pycortex viewer — a static make_static export or a freshly generated dynamic viewer.
Note
pycortex-roidraw lives in its own repository and is distributed separately from pycortex. The
ROIs it exports are a portable JSON vertex set (with the editable bezier), independent of
the Inkscape-based surface-defined ROI system — they are not read by
get_roi_masks and friends. Use it for quick interactive annotation in the viewer; use the
Inkscape workflow when you need ROI masks in the pycortex Python API.
Drawn sulci are different: they are exported as overlays.svg markup, so they are read
by pycortex’s own machinery (quickflat’s sulci overlay, the WebGL viewer, Inkscape) once
their shape groups are copied into a subject’s overlay file — see Installing drawn sulci into a subject.
Adding it to a viewer¶
Download
roidraw.bundle.jsfrom the latest release (or build it from source — see the project README).Copy it next to the viewer’s HTML.
Add two tags before the closing
</body>(pycortexmake_staticfragments have no</body>— append at the end instead):<script src="roidraw.bundle.js"></script> <script>window.ROIDraw.autoAttach();</script>
autoAttach() waits for the viewer to finish loading, then attaches. That is the entire
integration. The project also provides a bake.py helper that injects the bundle and the two
script tags into an existing static viewer non-destructively.
Drawing and editing¶
A Display / Draw toggle is added at the top of the viewer. Switch to Draw: the brain
flattens and a draw panel appears. A ROI | Sulcus selector at the top of the panel chooses what
a plain drag draws.
Gesture |
Action |
|---|---|
drag (ROI) |
Lasso a region, name it, and fit it to a smooth closed bezier |
drag (Sulcus) |
Trace along the sulcus, name it, and fit it to a smooth open bezier |
scroll wheel |
Zoom (to draw fine detail) |
shift + drag |
Pan the surface |
shift + click |
Inspect the voxel under the cursor |
esc |
Cancel the current stroke (or finish editing) |
Click ✎ edit next to any shape in the panel to reveal its bezier anchors and tangent handles:
drag anchors and handles to reshape the curve, double-click the curve to insert an anchor,
double-click an anchor to toggle smooth/corner, and press Delete to remove one. An open curve’s
endpoints show a single handle each and are always corners. For an ROI, vertex membership is
re-derived from the bezier on every change, so the exported vertex set always matches the curve you
see; a sulcus has no membership, and its label instead follows the curve.
Export formats¶
Export ROIs (JSON) writes a rois.json file holding, per ROI, the per-hemisphere subject
vertex indices, an ordered boundary ring, a label vertex, and the editable bezier (control points
in view-independent flat-UV coordinates). It re-imports — here or in any viewer on the same
surface — to the exact same outline, ready to re-edit.
Export sulci (SVG) writes a standalone sulci.svg document whose sulci layer is in
pycortex’s own overlay format: open, unfilled <path> elements, one inkscape-labeled group per
named sulcus. Trace a sulcus on each hemisphere and give both strokes the same name, and they merge
into a single group with one <path> per hemisphere — exactly how a hand-authored sulcus such as
CaS is stored.
Sulci carry no vertex data, matching pycortex: there is no get_sulci_verts, and sulci are
display geometry. The sulci_labels layer is deliberately left empty — pycortex derives each
sulcus’s label position from its path geometry when the overlay is loaded, so no label needs to be
written. Sulcus export is one-way: sulci are not re-imported from SVG.
Installing drawn sulci into a subject¶
Warning
Copy the <g inkscape:label="…"> groups out of the exported file’s sulci_shapes group and
into the existing sulci_shapes group of the subject’s overlays.svg.
Do not append the whole <g id="sulci"> layer. SVGOverlay keys its layers by
inkscape:label, so a second layer labelled sulci replaces the subject’s own in
SVGOverlay.layers — every sulcus already in that file becomes invisible to pycortex.
So, given an exported sulci.svg containing a group for the central sulcus:
<!-- sulci.svg, as downloaded -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" ...>
<g inkscape:groupmode="layer" id="sulci" inkscape:label="sulci" style="display:inline">
<g inkscape:groupmode="layer" id="sulci_shapes" inkscape:label="shapes">
<g inkscape:groupmode="layer" inkscape:label="CS"> <!-- copy THIS group ... -->
<path style="fill:none;stroke:white;..." d="M412.55,301.90C..." />
<path style="fill:none;stroke:white;..." d="M598.31,297.44C..." />
</g>
</g>
<g inkscape:groupmode="layer" id="sulci_labels" inkscape:label="labels" />
</g>
</svg>
paste that one <g inkscape:label="CS"> group inside the subject’s own
<g id="sulci_shapes">, alongside the sulci already there. Then:
import cortex
svg = cortex.db.get_overlay('S1')
svg.sulci['CS'] # the drawn sulcus, parsed
cortex.quickflat.make_figure(volume, with_sulci=True)
The paths’ coordinates are already in the overlay’s own coordinate system, so nothing needs to be rescaled. Inkscape can also open the exported file directly.
Full documentation¶
See the pycortex-roidraw README for the complete gesture reference, the JSON schema, the helper scripts, and notes on porting the tool to other viewer engines.