neu_glance.state

Assemble a viewer state, encode it into a URL, and read one back.

Neuroglancer keeps its whole state in the URL fragment, so a link is the state. A wrong dimensions block still loads, with every layer in the wrong place, so it is derived from the volume’s recorded voxel size rather than assumed. The fragment (after #!) is never sent to a server, but a large inline annotation layer makes a long link (see LONG_URL).

Pure: build_state() takes plain layer dicts and never reads a store.

Attributes

Exceptions

StateProblem

A state or layer could not be read, or would not be well formed.

Functions

annotation_extent(layers) → tuple[tuple, tuple] | None

(extent_zyx, offset_zyx) covering the inline annotations in layers.

build_state(layers, *[, voxel_size_zyx, units, ...]) → tuple[dict, str | None]

A viewer state. Coordinates are given zyx and written xyz.

colored_last(layers) → list[Any]

layers with every layer carrying segmentColors moved to the end, in order.

colors_by_property(properties, keys, *[, seed]) → tuple[dict[str, str], dict[str, Any]]

({segment_id: "#rrggbb"}, report): each segment coloured by the first of keys

default_view(extent_zyx[, offset_zyx]) → tuple[list, float, float]

(centre_zyx, cross_section_scale, projection_scale) framing a whole volume.

load_layer(path[, read_bytes]) → list[dict]

A layer (or a whole state's worth of layers) from a JSON file.

load_state(source[, read_bytes]) → dict

An existing state, from a neuroglancer URL or a JSON file.

merge_into(base, layers, *[, layout, position_zyx, ...]) → tuple[dict, list[str]]

base with layers appended. Returns the state and any notes worth printing.

parse_url(url) → dict

The state back out of a neuroglancer URL, for inspecting or editing one.

split_segment_layer(state, layer, *[, segments, ...]) → tuple[dict, dict[str, str], list[str]]

One layer per segment, so each can be shown, coloured or FADED on its own.

state_url(state[, viewer]) → str

<viewer>#!<url-encoded state>.

subset_layers(state, layer, subsets, *[, colors, ...]) → tuple[dict, dict[str, str], list[str]]

One layer per NAMED SET of segments. Returns (state, {set: layer_name}, notes).

unique_names(existing, layers) → list[str]

Rename, in place, each of layers whose name existing or an earlier one of

Module Contents

exception neu_glance.state.StateProblem

Bases: RuntimeError

A state or layer could not be read, or would not be well formed.

Initialize self. See help(type(self)) for accurate signature.

neu_glance.state.annotation_extent(layers: Sequence[dict]) → tuple[tuple, tuple] | None

(extent_zyx, offset_zyx) covering the inline annotations in layers.

For framing a state with no volume, e.g. one built from a bounding-box layer file.

neu_glance.state.build_state(layers: Sequence[dict], *, voxel_size_zyx=None, units: str | None = None, position_zyx: Sequence[float] | None = None, layout: str = '4panel', cross_section_scale: float | None = None, projection_scale: float | None = None, selected: str | None = None, show_slices: bool | None = None, projection_orientation: Sequence[float] | None = None, frame: tuple | None = None) → tuple[dict, str | None]

A viewer state. Coordinates are given zyx and written xyz.

projection_orientation is the 3D view’s quaternion as neuroglancer writes it (projectionOrientation, x, y, z, w).

dimensions comes from voxel_size_zyx and units, and must agree with the layers or nothing lines up. frame, an (extent_zyx, offset_zyx) pair, fills in whichever of the position and the two zooms are not given (default_view()).

show_slices=False hides the cross-section planes inside the 3D panel, useful for meshes and skeletons; the 2D panels need layout="3d" instead. None leaves the viewer’s default (shown).

Layers carrying segmentColors go last (colored_last()).

neu_glance.state.colored_last(layers: Sequence[Any]) → list[Any]

layers with every layer carrying segmentColors moved to the end, in order.

Neuroglancer restores layers in order and dispatches a change per stated colour; past ~20k colours that outlasts the URL-hash debounce (400 ms), which then serializes the state mid-restore, and an annotation layer not yet restored throws from toJSON. The colour layer is reported as unparseable and dropped (seen in Chrome). Last, every other layer is restored before its colours are applied.

neu_glance.state.colors_by_property(properties: Mapping[str, Any], keys: Sequence[str], *, seed: int = 0) → tuple[dict[str, str], dict[str, Any]]

({segment_id: "#rrggbb"}, report): each segment coloured by the first of keys it has a value for, for a segmentation layer’s segmentColors.

properties is what neu_glance.sources.read_segment_properties() returns. A key is label, or a tag facet (col or col:, taking the value after the colon), or a bare flag tag (glia). A segment with several values for a facet takes the first. Each key:value gets a fixed colour (neu_glance.shaders.value_color()), so a value is the same colour in every state. Segments with no value keep their hash colour.

neu_glance.state.default_view(extent_zyx: Sequence[float], offset_zyx: Sequence[float] = (0, 0, 0)) → tuple[list, float, float]

(centre_zyx, cross_section_scale, projection_scale) framing a whole volume.

Without these, neuroglancer opens at the origin corner at one voxel per pixel, a view of a large volume’s empty edge. Both scales are in voxels: per pixel for the cross sections, across the viewport for the projection.

neu_glance.state.load_layer(path: str, read_bytes=None) → list[dict]

A layer (or a whole state’s worth of layers) from a JSON file.

Accepts a bare layer object, a list of layers, or a full state (whose layers are taken), as neu-glance bboxes and neu-glance annotate write either.

neu_glance.state.load_state(source: str, read_bytes=None) → dict

An existing state, from a neuroglancer URL or a JSON file.

An http(s):// source is always treated as a URL, so a link that lost its #! (bash expands ! inside double quotes) fails as a broken URL rather than as “no such file”.

neu_glance.state.merge_into(base: Mapping[str, Any], layers: Sequence[dict], *, layout: str | None = None, position_zyx: Sequence[float] | None = None, cross_section_scale: float | None = None, projection_scale: float | None = None, selected: str | None = None, show_slices: bool | None = None, projection_orientation: Sequence[float] | None = None) → tuple[dict, list[str]]

base with layers appended. Returns the state and any notes worth printing.

  • Layers carrying segmentColors go last (colored_last()).

  • The base’s dimensions, position and zooms are kept unless overridden here, so adding a layer does not move the view.

  • Layer names stay unique: neuroglancer keys layers by name, so a clashing incoming layer is renamed with a -2 suffix, and the rename is reported.

neu_glance.state.parse_url(url: str) → dict

The state back out of a neuroglancer URL, for inspecting or editing one.

neu_glance.state.split_segment_layer(state: Mapping[str, Any], layer: str, *, segments: Sequence[Any] | None = None, names: Mapping[str, str] | None = None, name_template: str = '{layer} {segment}', object_alpha: float | None = None) → tuple[dict, dict[str, str], list[str]]

One layer per segment, so each can be shown, coloured or FADED on its own.

Returns (state, {segment_id: layer_name}, notes).

Neuroglancer has no per-segment alpha (objectAlpha belongs to the layer), so fading one neuron while its neighbour stays needs one layer per neuron. The copies share the source, and the viewer fetches each mesh once however many layers name it.

Each copy is the original layer verbatim, then overridden, so its other settings carry over. Colours are unchanged: an explicit segmentColors entry is kept (for that segment only), and an unlisted segment’s hash colour depends only on colorSeed and its id, both preserved.

  • A !-prefixed (starred, hidden) id is not split; it stays on the original.

  • The original layer is kept, emptied and hidden, because selectedLayer, linkedSegmentationLayer or a tool palette may name it, and a dangling name resolves to nothing silently. A synapse layer filtering on it now filters on an empty set; re-point it at a copy if needed.

  • The copies replace the original in place, since neuroglancer draws in layer order.

Segment ids stay strings: a uint64 through a JSON number is rounded.

neu_glance.state.state_url(state: Mapping[str, Any], viewer: str = DEFAULT_VIEWER) → str

<viewer>#!<url-encoded state>.

Percent-encoded, so the quotes and braces survive chat clients, wikis and shells.

neu_glance.state.subset_layers(state: Mapping[str, Any], layer: str, subsets: Mapping[str, Sequence[Any]], *, colors: Mapping[str, str] | None = None, object_alpha: float | None = None, name_template: str = '{subset}') → tuple[dict, dict[str, str], list[str]]

One layer per NAMED SET of segments. Returns (state, {set: layer_name}, notes).

Like split_segment_layer(), but one layer per set, for fading whole populations. A set’s colour (colors) is its segmentDefaultColor. The inherited segmentColors is dropped, since any entry in it would override the default for that body. The original layer is kept, emptied and hidden, and the copies replace it in place, as in split_segment_layer().

neu_glance.state.unique_names(existing: Sequence[Any], layers: Sequence[dict]) → list[str]

Rename, in place, each of layers whose name existing or an earlier one of layers already has, with a -2 suffix. Returns a note per rename.

neu_glance.state.DEFAULT_VIEWER = 'https://neuroglancer-demo.appspot.com/'
neu_glance.state.FIT_MARGIN = 1.15
neu_glance.state.LAYOUTS = ('4panel', 'xy', 'yz', 'xz', 'xy-3d', 'yz-3d', 'xz-3d', '3d')
neu_glance.state.LONG_URL = 8000
neu_glance.state.NOMINAL_VIEWPORT_PX = 1000