Neuroglancer Export¶
This guide shows how to export muDM data to the Neuroglancer precomputed format and how to serve it to an external Neuroglancer viewer.
There are two distinct paths, and choosing the right one matters:
- Python writer subsystem (
mudm_tools.neuroglancer) — a toolkit of small writers for skeletons, annotations (Point / LineString), legacy single-resolution meshes, and segment properties, plus helpers to build a Neuroglancer viewer state and a shareable URL. Use this for neuron morphologies (SWC skeletons) and point/line annotations. - Scalable Rust mesh path (
mudm_tools._rs.StreamingTileGenerator) —generate_neuroglancer(legacy single-res mesh) andgenerate_neuroglancer_multilod(multi-LOD Draco, with optional sharding). Use this for large mesh corpora that need level-of-detail and object-store-scale deployment. See the 3D Tiling guide for how to feed the generator.
The bundled viewers do NOT render Neuroglancer
muDM ships its own 2D and 3D viewers, but they do not render Neuroglancer precomputed data. Neuroglancer export targets an external Neuroglancer client (the public demo at https://neuroglancer-demo.appspot.com, or your own instance). mudm-serve only serves the files under a /neuroglancer/ route; the rendering happens in the external Neuroglancer app.
Package names
The writers live in mudm_tools.neuroglancer. The compiled mesh generator is mudm_tools._rs.StreamingTileGenerator (never mudm._rs). Geometry types (MuDMFeature, MuDMFeatureCollection) come from the sibling core package mudm (mudm.model).
Path 1: The Python writer subsystem¶
Quick start: SWC neurons to precomputed skeletons¶
The fastest way to see something is the bundled swc_to_neuroglancer example. It converts one or more SWC files into a precomputed skeleton source, attaches segment properties, prints a ready-to-open Neuroglancer URL, and serves the files over a CORS-enabled HTTP server.
# Convert + serve (CORS server on :9000)
uv run python -m mudm_tools.examples.swc_to_neuroglancer neuron.swc
# Several neurons at once
uv run python -m mudm_tools.examples.swc_to_neuroglancer n1.swc n2.swc n3.swc
# Export only, no server
uv run python -m mudm_tools.examples.swc_to_neuroglancer neuron.swc --no-serve
# Custom output dir + port
uv run python -m mudm_tools.examples.swc_to_neuroglancer neuron.swc -o out -p 8080
| Flag | Default | Meaning |
|---|---|---|
--output-dir, -o |
neuroglancer_output |
Root output directory |
--port, -p |
9000 |
Port for the CORS HTTP server |
--no-serve |
off | Export only, do not start the server |
The example writes skeletons to <output-dir>/skeletons/, prints the viewer URL, then serves on http://localhost:<port>. Copy the printed URL into your browser.
Where to get SWC files
NeuroMorpho.Org hosts 200,000+ reconstructions. Search and download .swc, then point the example at the file.
Writing skeletons directly¶
write_skeleton writes one precomputed skeleton segment. Call it repeatedly with distinct segment_ids into the same directory to build a multi-skeleton source — the info file is rewritten on each call.
from pathlib import Path
from mudm_tools.swc import _parse_swc
from mudm_tools.neuroglancer import write_skeleton
morphology = _parse_swc("neuron.swc") # mudm_tools.swc.NeuronMorphology
write_skeleton(Path("out/skeletons"), segment_id=1, morphology=morphology)
The signature:
def write_skeleton(
output_dir: str | Path,
segment_id: int,
morphology: NeuronMorphology,
*,
transform: Optional[AffineTransform] = None,
include_radius: bool = True,
include_type: bool = True,
segment_properties: Optional[str] = None,
) -> Path
| Parameter | Default | Notes |
|---|---|---|
output_dir |
— | Created with parents |
segment_id |
— | Binary written to a file named str(segment_id) |
morphology |
— | A mudm_tools.swc.NeuronMorphology |
transform |
None |
A mudm.transforms.AffineTransform, embedded as a 12-float row-major upper 3×4 |
include_radius |
True |
Emit a per-vertex radius attribute |
include_type |
True |
Emit a per-vertex SWC type attribute |
segment_properties |
None |
Relative path to a segment_properties dir to reference in info |
Edges are derived from each sample's parent (parent index → child index).
Unit scaling
write_skeleton builds its info without the micrometre→nanometre transform. If your coordinates are in µm and you want Neuroglancer to treat them as nm, pass an explicit transform, or build the info yourself with build_skeleton_info(scale_um_to_nm=True) and write it after your skeletons (see the SWC example, which rewrites info to attach segment_properties).
Segment properties¶
write_segment_properties writes a neuroglancer_segment_properties source from each feature's .properties dict. Numeric columns become type number (uint32 if all values are ints, else float32); everything else becomes a label. Values are ordered to match segment_ids; missing values become an empty string.
from mudm_tools.neuroglancer.properties_writer import write_segment_properties
write_segment_properties(
"out/skeletons/seg_props",
features=features, # Sequence[MuDMFeature]
segment_ids=[1, 2, 3], # one id per feature
)
Use features_to_segment_properties(features, segment_ids) if you want the info dict without writing it.
To wire the property source into the skeleton info, rebuild and rewrite info with a relative path:
import json
from mudm_tools.neuroglancer.skeleton_writer import build_skeleton_info
info = build_skeleton_info(segment_properties="seg_props")
(skel_dir / "info").write_text(json.dumps(info.to_info_dict(), indent=2))
Annotations: to_neuroglancer and write_annotations¶
to_neuroglancer is NOT a one-call full exporter
to_neuroglancer only handles Point features (→ point_annotations/ subdir) and LineString features (→ line_annotations/ subdir). It does not export skeletons or meshes — for those, call write_skeleton or write_mesh directly. Features whose geometry is neither Point nor LineString are silently ignored.
from mudm_tools.neuroglancer import to_neuroglancer
result = to_neuroglancer(collection, "out/mixed")
# result["paths"] -> {"point_annotations": <dir>, "line_annotations": <dir>}
Signature:
def to_neuroglancer(
data: Union[MuDMFeature, MuDMFeatureCollection],
output_dir: str | Path,
*,
base_url: Optional[str] = None,
) -> dict[str, Any]
to_neuroglancer always returns {"paths": {layer_name: dir}}. If you pass base_url and at least one annotation layer was written, it also returns "viewer_state" (a Neuroglancer state dict) and "viewer_url" (an encoded URL).
Two different base_urls
to_neuroglancer's base_url is the precomputed data source base. Annotation layers are added as precomputed://{base_url}/point_annotations and precomputed://{base_url}/line_annotations. This is distinct from viewer_state_to_url's base_url, which is the Neuroglancer viewer instance (default https://neuroglancer-demo.appspot.com).
For finer control, call write_annotations directly:
def write_annotations(
output_dir: str | Path,
features: Sequence[MuDMFeature],
annotation_type: Literal["point", "line"],
) -> Path
This produces {output_dir}/info (@type neuroglancer_annotations_v1), an empty {output_dir}/by_id/ dir, and a single spatial chunk {output_dir}/spatial0/0_0_0.
Line annotation semantics
For annotation_type="line", each consecutive pair of LineString coordinates becomes one LINE annotation — an N-vertex line yields N−1 segments, all sharing the feature's enumerate() index (0-based) as their annotation id. Annotation ids are the feature index, not a property. Missing z defaults to 0.0.
A complete in-memory example (adapted from neuroglancer_export.py):
from pathlib import Path
from mudm.model import MuDMFeature, MuDMFeatureCollection
from mudm_tools.neuroglancer import to_neuroglancer, write_skeleton
out = Path("out/mixed")
# Skeletons are written directly (NOT via to_neuroglancer)
write_skeleton(out / "skeletons", segment_id=1, morphology=neuron_a)
write_skeleton(out / "skeletons", segment_id=2, morphology=neuron_b)
collection = MuDMFeatureCollection(
type="FeatureCollection",
features=[
MuDMFeature(
type="Feature",
geometry={"type": "Point", "coordinates": [500, 500, 200]},
properties={"label": "pyramidal_soma"},
),
MuDMFeature(
type="Feature",
geometry={
"type": "LineString",
"coordinates": [[500, 500, 200], [650, 550, 200], [800, 600, 200]],
},
properties={"label": "connecting_fiber"},
),
],
)
result = to_neuroglancer(collection, out)
# -> writes out/point_annotations/ and out/line_annotations/
Run all three patterns from the bundled example:
| Flag | Default | Meaning |
|---|---|---|
--output-dir |
neuroglancer_output |
Root output directory |
Legacy single-resolution meshes¶
The Python mesh writer emits the legacy single-LOD mesh format (@type neuroglancer_legacy_mesh). Write the info once with write_mesh_info, then one segment at a time with write_mesh.
import numpy as np
from mudm_tools.neuroglancer import write_mesh, write_mesh_info
write_mesh_info("out/meshes", segment_properties="segment_properties")
write_mesh("out/meshes", segment_id=1, vertices=verts, indices=faces)
def write_mesh_info(output_dir: str | Path, segment_properties: Optional[str] = None) -> Path
def write_mesh(output_dir: str | Path, segment_id: int, vertices: np.ndarray, indices: np.ndarray) -> Path
write_mesh writes {output_dir}/{segment_id} (binary, via mesh_to_binary) plus {output_dir}/{segment_id}:0 (a JSON fragment manifest {"fragments": ["{segment_id}"]}). It does not write info — call write_mesh_info separately. vertices are Nx3 float32 and indices are Mx3 uint32.
Choosing a mesh path
write_mesh is the legacy single-resolution path. For large meshes that need genuine level-of-detail, use the scalable Rust generate_neuroglancer_multilod instead. Do not conflate the two — they emit different @types and different on-disk layouts.
Low-level binary codecs are also exported: mesh_to_binary(vertices, indices) -> bytes and its inverse decode_mesh_binary(data) -> (vertices, indices). For point/line annotation bytes, see points_to_annotation_binary and lines_to_annotation_binary.
Building a viewer state and URL¶
The viewer-state helpers in mudm_tools.neuroglancer.state build a plain JSON state dict and a shareable fragment URL using only json + urllib.parse. They do not depend on the official neuroglancer Python package and do not run a viewer server.
from mudm_tools.neuroglancer.state import (
build_skeleton_layer,
build_annotation_layer,
build_viewer_state,
viewer_state_to_url,
)
layer = build_skeleton_layer(
"neurons",
"precomputed://http://localhost:9000/skeletons",
)
layer["segments"] = ["1", "2"] # pre-select segments so they render immediately
state = build_viewer_state([layer], position=[650.0, 550.0, 200.0])
url = viewer_state_to_url(state)
print(url) # https://neuroglancer-demo.appspot.com/#!<encoded-state>
| Function | Signature | Purpose |
|---|---|---|
build_skeleton_layer |
(name, source_url, *, use_radius=True) |
A segmentation layer for a skeleton source. With use_radius=True, attaches a GLSL skeletonRendering shader mapping the radius attribute to line width. |
build_annotation_layer |
(name, source_url) |
An annotation layer pointing at a precomputed:// annotation source. |
build_viewer_state |
(layers, position=None, projection_scale=None, layout="3d") |
A full viewer-state dict. position sets the camera, projection_scale the zoomFactor, layout defaults to "3d" (use "4panel" for all views). |
viewer_state_to_url |
(state, base_url="https://neuroglancer-demo.appspot.com") |
Encodes the state as {base_url}/#!{encoded}. |
Pre-selecting segments
build_skeleton_layer returns a plain dict; callers commonly set layer["segments"] = [...] afterward so the listed segments are visible on load.
Python writer API reference¶
to_neuroglancer
¶
to_neuroglancer(
data: Union[MuDMFeature, MuDMFeatureCollection],
output_dir: str | Path,
*,
base_url: Optional[str] = None,
) -> dict[str, Any]
Export MuDM data to Neuroglancer precomputed format.
Auto-dispatches based on geometry type: - Point -> point annotations - LineString -> line annotations
For skeleton export, call write_skeleton() directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
Union[MuDMFeature, MuDMFeatureCollection]
|
A MuDMFeature or MuDMFeatureCollection. |
required |
output_dir
|
str | Path
|
Root output directory. |
required |
base_url
|
Optional[str]
|
Optional Neuroglancer instance URL for viewer state. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dict with keys: |
Source code in src/mudm_tools/neuroglancer/writer.py
write_annotations
¶
write_annotations(
output_dir: str | Path,
features: Sequence[MuDMFeature],
annotation_type: Literal["point", "line"],
) -> Path
Write annotations to Neuroglancer precomputed directory.
Creates
{output_dir}/info — JSON info file {output_dir}/by_id/ — empty dir (required by Neuroglancer) {output_dir}/spatial0/0_0_0 — binary annotation data
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_dir
|
str | Path
|
Directory to write to. |
required |
features
|
Sequence[MuDMFeature]
|
MuDM features with Point or LineString geometry. |
required |
annotation_type
|
Literal['point', 'line']
|
"point" or "line". |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to the output directory. |
Source code in src/mudm_tools/neuroglancer/annotation_writer.py
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
write_skeleton
¶
write_skeleton(
output_dir: str | Path,
segment_id: int,
morphology: NeuronMorphology,
*,
transform: Optional[AffineTransform] = None,
include_radius: bool = True,
include_type: bool = True,
segment_properties: Optional[str] = None,
) -> Path
Write a single skeleton segment to the precomputed directory.
Creates
{output_dir}/info — JSON info file {output_dir}/{segment_id} — binary skeleton data
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_dir
|
str | Path
|
Directory to write to (created if needed). |
required |
segment_id
|
int
|
Numeric ID for this segment. |
required |
morphology
|
NeuronMorphology
|
The neuron morphology data. |
required |
transform
|
Optional[AffineTransform]
|
Optional affine transform. |
None
|
include_radius
|
bool
|
Include radius attribute. |
True
|
include_type
|
bool
|
Include type attribute. |
True
|
segment_properties
|
Optional[str]
|
Optional path to segment_properties. |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to the output directory. |
Source code in src/mudm_tools/neuroglancer/skeleton_writer.py
build_skeleton_info
¶
build_skeleton_info(
*,
transform: Optional[AffineTransform] = None,
scale_um_to_nm: bool = False,
include_radius: bool = True,
include_type: bool = True,
segment_properties: Optional[str] = None,
) -> SkeletonInfo
Build a SkeletonInfo config for the info JSON file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transform
|
Optional[AffineTransform]
|
Optional affine transform to embed. |
None
|
scale_um_to_nm
|
bool
|
If True and no explicit transform, embed a 1000× scaling transform (micrometers → nanometers). Useful for SWC files whose coordinates are in µm. |
False
|
include_radius
|
bool
|
Include radius vertex attribute. |
True
|
include_type
|
bool
|
Include type vertex attribute. |
True
|
segment_properties
|
Optional[str]
|
Optional relative path to segment_properties dir. |
None
|
Returns:
| Type | Description |
|---|---|
SkeletonInfo
|
A SkeletonInfo model ready to serialize. |
Source code in src/mudm_tools/neuroglancer/skeleton_writer.py
neuron_to_skeleton_binary
¶
neuron_to_skeleton_binary(
morphology: NeuronMorphology,
*,
include_radius: bool = True,
include_type: bool = True,
) -> bytes
Encode a NeuronMorphology as Neuroglancer precomputed skeleton binary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
morphology
|
NeuronMorphology
|
The neuron morphology to encode. |
required |
include_radius
|
bool
|
Include per-vertex radius attribute. |
True
|
include_type
|
bool
|
Include per-vertex SWC type attribute. |
True
|
Returns:
| Type | Description |
|---|---|
bytes
|
Raw bytes in Neuroglancer skeleton binary format. |
Source code in src/mudm_tools/neuroglancer/skeleton_writer.py
affine_to_ng_transform
¶
Convert a 4×4 row-major affine to Neuroglancer's 12-element format.
Neuroglancer expects 12 floats representing the upper 3×4 sub-matrix in row-major order (3 rows of 4 values each): [r00, r01, r02, tx, r10, r11, r12, ty, r20, r21, r22, tz]
Internally, Neuroglancer loads these into a column-major mat4 and transposes, which produces the correct 4×4 affine.
Source code in src/mudm_tools/neuroglancer/skeleton_writer.py
write_segment_properties
¶
write_segment_properties(
output_dir: str | Path,
features: Sequence[MuDMFeature],
segment_ids: Sequence[int],
) -> Path
Write segment_properties info JSON to disk.
Creates {output_dir}/info with the segment properties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_dir
|
str | Path
|
Directory to write to (created if needed). |
required |
features
|
Sequence[MuDMFeature]
|
MuDM features. |
required |
segment_ids
|
Sequence[int]
|
Segment IDs corresponding to each feature. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to the output directory. |
Source code in src/mudm_tools/neuroglancer/properties_writer.py
features_to_segment_properties
¶
features_to_segment_properties(
features: Sequence[MuDMFeature],
segment_ids: Sequence[int],
) -> dict[str, Any]
Build segment_properties inline dict from MuDM features.
Each feature's properties dict is read. All unique property keys
across features become columns. Values are ordered to match
segment_ids.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
features
|
Sequence[MuDMFeature]
|
MuDM features with properties dicts. |
required |
segment_ids
|
Sequence[int]
|
Numeric segment IDs matching each feature. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A dict matching the |
Source code in src/mudm_tools/neuroglancer/properties_writer.py
write_mesh
¶
Write a single mesh segment to the precomputed directory.
Creates
{output_dir}/{segment_id} — binary mesh data {output_dir}/{segment_id}:0 — JSON fragment manifest
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_dir
|
str | Path
|
Directory to write to (created if needed). |
required |
segment_id
|
int
|
Numeric ID for this segment. |
required |
vertices
|
ndarray
|
Nx3 float32 vertex positions. |
required |
indices
|
ndarray
|
Mx3 uint32 triangle face indices. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to the binary mesh file. |
Source code in src/mudm_tools/neuroglancer/mesh_writer.py
write_mesh_info
¶
Write the Neuroglancer mesh info JSON file.
Creates {output_dir}/info with the legacy mesh type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_dir
|
str | Path
|
Directory to write to (created if needed). |
required |
segment_properties
|
Optional[str]
|
Optional relative path to segment_properties dir. |
None
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to the output directory. |
Source code in src/mudm_tools/neuroglancer/mesh_writer.py
mesh_to_binary
¶
Encode mesh data as Neuroglancer legacy mesh binary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vertices
|
ndarray
|
Nx3 float32 array of vertex positions. |
required |
indices
|
ndarray
|
Mx3 uint32 array of triangle face indices (or flat 1D). |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Raw bytes in Neuroglancer legacy mesh binary format. |
Source code in src/mudm_tools/neuroglancer/mesh_writer.py
decode_mesh_binary
¶
Decode Neuroglancer legacy mesh binary back to arrays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
Raw bytes in Neuroglancer legacy mesh binary format. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
(vertices, indices) — Nx3 float32 and Mx3 uint32 arrays. |
Source code in src/mudm_tools/neuroglancer/mesh_writer.py
fragments_to_mesh
¶
fragments_to_mesh(
fragments: Sequence[dict],
world_bounds: tuple[
float, float, float, float, float, float
],
) -> tuple[ndarray, ndarray]
Merge clipped fragments into a single mesh with world coordinates.
Takes fragment dicts (from the streaming pipeline) with keys:
xy, z, ring_lengths, geom_type — all in normalized
[0,1]^3 space — and unprojections them to world coordinates,
performing vertex deduplication.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fragments
|
Sequence[dict]
|
Sequence of fragment dicts with normalized geometry. |
required |
world_bounds
|
tuple[float, float, float, float, float, float]
|
(xmin, ymin, zmin, xmax, ymax, zmax) world bounds. |
required |
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
(vertices, indices) — Nx3 float32 positions and Mx3 uint32 indices. |
Source code in src/mudm_tools/neuroglancer/mesh_writer.py
points_to_annotation_binary
¶
points_to_annotation_binary(
points: Sequence[Tuple[float, float, float]],
annotation_ids: Sequence[int],
) -> bytes
Encode point annotations as Neuroglancer binary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
points
|
Sequence[Tuple[float, float, float]]
|
Sequence of (x, y, z) coordinates. |
required |
annotation_ids
|
Sequence[int]
|
Unique ID for each annotation. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Raw bytes in Neuroglancer annotation binary format. |
Source code in src/mudm_tools/neuroglancer/annotation_writer.py
lines_to_annotation_binary
¶
lines_to_annotation_binary(
lines: Sequence[
Tuple[float, float, float, float, float, float]
],
annotation_ids: Sequence[int],
) -> bytes
Encode line annotations as Neuroglancer binary.
Each line is (x1, y1, z1, x2, y2, z2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Sequence[Tuple[float, float, float, float, float, float]]
|
Sequence of 6-tuples (start_xyz + end_xyz). |
required |
annotation_ids
|
Sequence[int]
|
Unique ID for each annotation. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
Raw bytes in Neuroglancer annotation binary format. |
Source code in src/mudm_tools/neuroglancer/annotation_writer.py
build_skeleton_layer
¶
Build a Neuroglancer layer dict for a skeleton source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Layer display name. |
required |
source_url
|
str
|
|
required |
use_radius
|
bool
|
If True, include a skeleton shader that reads the
radius vertex attribute to set line width. Adds a
|
True
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Layer dict suitable for the viewer state |
Source code in src/mudm_tools/neuroglancer/state.py
build_annotation_layer
¶
Build a Neuroglancer layer dict for an annotation source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Layer display name. |
required |
source_url
|
str
|
|
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Layer dict suitable for the viewer state |
Source code in src/mudm_tools/neuroglancer/state.py
build_viewer_state
¶
build_viewer_state(
layers: List[dict[str, Any]],
position: Optional[List[float]] = None,
projection_scale: Optional[float] = None,
layout: str = "3d",
) -> dict[str, Any]
Build a complete Neuroglancer viewer state dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layers
|
List[dict[str, Any]]
|
List of layer dicts (from build_*_layer functions). |
required |
position
|
Optional[List[float]]
|
Optional 3D camera position [x, y, z] in nm. |
None
|
projection_scale
|
Optional[float]
|
Camera zoom (field of view in nm). Larger = more zoomed out. |
None
|
layout
|
str
|
Viewer layout. |
'3d'
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Viewer state dict that can be serialized to JSON. |
Source code in src/mudm_tools/neuroglancer/state.py
viewer_state_to_url
¶
viewer_state_to_url(
state: dict[str, Any],
base_url: str = "https://neuroglancer-demo.appspot.com",
) -> str
Encode a viewer state dict into a Neuroglancer URL.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
dict[str, Any]
|
Viewer state dict. |
required |
base_url
|
str
|
Base Neuroglancer instance URL. |
'https://neuroglancer-demo.appspot.com'
|
Returns:
| Type | Description |
|---|---|
str
|
Full URL with JSON-encoded fragment. |
Source code in src/mudm_tools/neuroglancer/state.py
MeshInfo
¶
Bases: BaseModel
Info JSON for a precomputed:// legacy mesh source.
SkeletonInfo
¶
Bases: BaseModel
Info JSON for a precomputed:// skeleton source.
VertexAttributeInfo
¶
Bases: BaseModel
A per-vertex attribute in a skeleton (e.g. radius, type).
AnnotationInfo
¶
Bases: BaseModel
Info JSON for a precomputed:// annotation source.
SegmentPropertiesInfo
¶
Bases: BaseModel
Info JSON for neuroglancer_segment_properties.
For the rest of the model classes (AnnotationDimension, AnnotationSpatialEntry, AnnotationPropertySpec, AnnotationRelationship, SegmentPropertiesInline, SegmentPropertyField), see the Python API reference.
Path 2: The scalable Rust mesh generator¶
For large mesh corpora, drive mudm_tools._rs.StreamingTileGenerator. You ingest geometry (OBJ files, Parquet meshes, or projected feature dicts), the generator accumulates octree-clipped fragments on disk, and a generate_* call emits the chosen Neuroglancer format. See the 3D Tiling guide for ingestion details.
Not autodoc-able
StreamingTileGenerator is a compiled Rust pyclass (mudm_tools._rs), so its methods cannot be introspected by mkdocstrings. The signatures below are transcribed by hand from the source.
Legacy mesh: generate_neuroglancer¶
def generate_neuroglancer(
self,
output_dir: str,
world_bounds: tuple[float, float, float, float, float, float], # xmin,ymin,zmin,xmax,ymax,zmax
) -> int
Emits a segment-centric neuroglancer_legacy_mesh source: one mesh per feature at max_zoom (the finest level). It writes output_dir/info (@type neuroglancer_legacy_mesh), a {segment_id} binary mesh, a {segment_id}:0 JSON fragment manifest, and segment_properties/info built from tags. Geometry is merged with float32-bit vertex dedup. Returns the number of segments written.
Multi-LOD Draco meshes: generate_neuroglancer_multilod¶
def generate_neuroglancer_multilod(
self,
output_dir: str,
world_bounds: tuple[float, float, float, float, float, float],
vertex_quantization_bits: int = 10,
max_memory_bytes: int = 0,
sharded: bool = False,
minishard_bits: int = 6,
shard_bits: int = 0,
) -> int
Emits a neuroglancer_multilod_draco source. Unlike the legacy path, this uses all zoom levels: LOD 0 = max_zoom (finest), LOD N = zoom 0 (coarsest). Fragment positions are sorted in Morton / Z-curve order. The info carries vertex_quantization_bits, an identity transform, lod_scale_multiplier 1.0, and a segment_properties reference. Returns the number of segments written.
| Parameter | Default | Notes |
|---|---|---|
output_dir |
— | Output directory |
world_bounds |
— | (xmin, ymin, zmin, xmax, ymax, zmax); degenerate axes default span to 1.0 |
vertex_quantization_bits |
10 |
Per-tile position quantization (qmax = 2^bits − 1) |
max_memory_bytes |
0 |
Per-path memory ceiling. 0 uses the generator's resolved self.max_memory_bytes. The ceiling derives a feature-bucket count k = min(ceil(est_resident_bytes / budget), 256); peak resident ≈ corpus/k. A huge ceiling yields k == 1 (whole-corpus, byte-identical path). |
sharded |
False |
When True, emit neuroglancer_uint64_sharded_v1 .shard files (see below) |
minishard_bits |
6 |
Sharding spec minishard_bits (used only when sharded=True) |
shard_bits |
0 |
Sharding spec shard_bits (used only when sharded=True) |
from mudm_tools._rs import StreamingTileGenerator, scan_obj_bounds
paths = ["mesh_a.obj", "mesh_b.obj"]
bounds = scan_obj_bounds(paths)
gen = StreamingTileGenerator(min_zoom=0, max_zoom=4)
gen.add_obj_files(paths, bounds, [{"name": "a"}, {"name": "b"}])
# Loose multi-LOD output (default)
n = gen.generate_neuroglancer_multilod("out/ng_multilod", bounds)
print(f"{n} segments written")
Loose vs. sharded layout¶
By default (sharded=False), the generator writes loose per-segment files: a {seg_id}.index binary manifest plus a {seg_id} file of concatenated Draco fragments. This read is feature-bucketed and memory-bounded.
With sharded=True, per-segment (manifest, fragment bytes) pairs are accumulated and packed into neuroglancer_uint64_sharded_v1 .shard files. The info file gains a sharding block (hash murmurhash3_x86_128, minishard_index_encoding raw, data_encoding raw). Loose per-segment files are not written in sharded mode.
Sharded mode holds the whole corpus in RAM
Sharded packing happens after the bucket loop, so sharded=True does not preserve the per-bucket memory bound — it holds the entire Neuroglancer mesh corpus in memory. Treat it as an opt-in deploy / object-store-scale path, and provision RAM accordingly. The default loose format keeps the memory bound.
Output structure reference¶
# write_skeleton (repeated per segment_id into one dir)
{output_dir}/
info # JSON, @type neuroglancer_skeletons
{segment_id} # u32 nverts, u32 nedges, f32 verts[N*3], u32 edges[E*2], [f32 radii[N]], [f32 types[N]]
seg_props/info # optional, from write_segment_properties
# write_annotations / to_neuroglancer
{output_dir}/ # to_neuroglancer makes point_annotations/ and/or line_annotations/ subdirs
info # JSON, @type neuroglancer_annotations_v1
by_id/ # empty dir (required by Neuroglancer)
spatial0/0_0_0 # u64 count, f32 coords[count*D] (D=3 point, 6 line), u64 ids[count]
# write_mesh_info + write_mesh (legacy_mesh)
{output_dir}/
info # JSON, @type neuroglancer_legacy_mesh
{segment_id} # u32 nverts, f32 verts[N*3], u32 idx[M*3]
{segment_id}:0 # JSON fragment manifest {"fragments": ["{segment_id}"]}
segment_properties/info # optional
# StreamingTileGenerator.generate_neuroglancer_multilod (multilod_draco)
{output_dir}/
info # JSON, @type neuroglancer_multilod_draco (+ "sharding" when sharded=True)
{seg_id}.index # loose mode only: binary manifest
{seg_id} # loose mode only: concatenated Draco fragments
*.shard # sharded=True only (neuroglancer_uint64_sharded_v1)
segment_properties/info
Serving for an external Neuroglancer client¶
Neuroglancer runs in the browser and fetches data over HTTP, so the server must send CORS headers (Access-Control-Allow-Origin: *). You have two options.
Option A: mudm-serve (/neuroglancer/ route)¶
The installed console script mudm-serve (mudm_tools.serve:main) serves precomputed files under a /neuroglancer/ route. A request to /neuroglancer/{pyramid_id}/... maps to {tiles_base}/{pyramid_id}/neuroglancer/... on disk, where tiles_base is the tiles directory you serve.
This is intended for an external Neuroglancer client — point a precomputed:// source at the served URL. See the CLI reference for the full mudm-serve options.
External viewer only
mudm-serve does not render Neuroglancer. Open the served precomputed:// source in a real Neuroglancer instance.
Option B: the standalone example servers¶
Both ship as runnable example modules and use Python's http.server with a CORS subclass.
# Auto-detect skeleton/annotation layers and print a viewer URL per export
uv run python -m mudm_tools.examples.neuroglancer_serve neuroglancer_output
neuroglancer_serve walks each subdirectory, reads its info @type to classify it (neuroglancer_skeletons → segmentation, neuroglancer_annotations_v1 → annotation), infers segment ids from the binary files, builds a viewer state, and prints a ready-to-open Neuroglancer URL.
| Flag | Default | Meaning |
|---|---|---|
directory |
— | Directory of precomputed data (positional) |
--port |
9000 |
Port to serve on |
--neuroglancer-url |
https://neuroglancer-demo.appspot.com |
Neuroglancer instance for the printed URLs |
See also¶
- 3D Tiling — how to ingest geometry into
StreamingTileGeneratorbefore callinggenerate_neuroglancer/generate_neuroglancer_multilod. - CLI reference —
mudm-serveoptions and the/neuroglancer/route. - Python API reference — the full
mudm_tools.neuroglancerwriter and model API.