neu_lib.skeleton¶
A skeleton as vertices and edges, in nm, zyx: Skeleton.
An edge list, never decomposed into branch paths, so any topology works: cycles, self-loops, thousands of disconnected components. It draws directly as line segments, in one buffer per body:
positions = to_xyz(skeleton.segments())
pygfx.Line(pygfx.Geometry(positions=positions), pygfx.LineSegmentMaterial(...))
Precomputed skeletons (vertices, edges, radii) and DVID’s SWC tables (nodes and parents) both map onto it directly.
Attributes¶
Classes¶
Vertices in nm (zyx), the edges between them, and optional per-vertex radii. |
Module Contents¶
- class neu_lib.skeleton.Skeleton¶
Vertices in nm (zyx), the edges between them, and optional per-vertex radii.
- crop(inside: InsideFn, *, keep_inside: bool = True, tolerance_nm: float = 8.0) Skeleton¶
Keep the part of the skeleton on one side of a region boundary.
insidetakes an(N, 3)zyx nm array and returns an(N,)bool array (seeneu_lib.predicates). An edge with one endpoint kept is bisected to withintolerance_nmand ends at a new vertex on the boundary, so branches stop at the region surface. Every kept vertex is retained, including ones left with no edges.Limitation: an edge whose endpoints are on the same side is assumed not to cross, so a region thinner than the edge spacing can be missed.
- exclude(inside: InsideFn, **kwargs) Skeleton¶
The complement of
crop()— drop what is inside the region.
- classmethod from_precomputed(vertices_xyz_nm: Any, edges: Any, radii_nm: Any = None, name: str | None = None) Skeleton¶
From xyz vertices, as the precomputed format stores them and
neu_vol.readback.read_body_skeletonreturns them, flipped to zyx.
- classmethod from_swc(table: Any, *, frame: neu_lib.frame.Frame, node_col: str = 'node', parent_col: str = 'parent', coord_cols: Sequence[str] = ('x', 'y', 'z'), radius_col: str | None = 'radius', name: str | None = None) Skeleton¶
From a node/parent table, DVID’s skeleton form.
coord_colsare read in the order given and then reversed, so the SWC default("x", "y", "z")becomes zyx. Coordinates are voxel indices, converted to nm withframe. A parent id absent from the table (SWC’s-1root, or a dangling reference) adds no edge; the result need not be a tree.
- segments() numpy.ndarray¶
(2M, 3)zyx nm, the two endpoints of each edge in turn: pass throughto_xyz()to draw withpygfx.LineSegmentMaterial.
- split_at(inside: InsideFn, *, tolerance_nm: float = 8.0) tuple[Skeleton, numpy.ndarray, numpy.ndarray]¶
Insert a vertex where each edge crosses a region boundary, keeping both sides.
Returns
(skeleton, inside, boundary): the skeleton with each crossing edge split in two, plus one bool per vertex for “in the region” and “is an inserted boundary vertex”. Original vertices keep their indices; boundary vertices are appended, on the inside, withintolerance_nmof the surface (the bisectioncrop()uses).The edge order is guaranteed, so per-edge data can follow the split: uncrossed edges in their original order, then one
(inside endpoint, boundary)edge per crossing edge, then one(boundary, outside endpoint)edge per crossing edge. Same limitation ascrop().
- property bbox: neu_lib.grid.BBox¶
- edges: numpy.ndarray¶
- name: str | None = None¶
- radii_nm: numpy.ndarray | None = None¶
- vertices_zyx_nm: numpy.ndarray¶
- neu_lib.skeleton.InsideFn¶