Branch#
- class braincell.Branch(lengths, radii_proximal, radii_distal, points_proximal=None, points_distal=None, type='custom')[source]#
Immutable geometry primitive representing an anatomical branch.
A
Branchstores segment-wise cable properties — lengths, proximal and distal radii, and optional 3-D point coordinates — for one contiguous stretch of neuronal morphology (soma, dendrite, axon, etc.).All geometric quantities are stored as
brainunitvalues and normalised tou.uminternally. Bare numeric inputs are rejected withTypeError; every value must carry explicit units.Branches are frozen dataclasses: once constructed their geometry cannot be changed. Use
Morphoto compose branches into a mutable morphology tree.- Parameters:
lengths (
Quantity[um]) – Per-segment lengths, shape(n_segments,). Each value must be>= 0; the total must be> 0.radii_proximal (
Quantity[um]) – Proximal radius of each segment, shape(n_segments,). Must be> 0.radii_distal (
Quantity[um]) – Distal radius of each segment, shape(n_segments,). Must be> 0.points_proximal (
Quantity[um]|None) – Proximal 3-D endpoint of each segment, shape(n_segments, 3). Must be provided together with points_distal or both set toNone.points_distal (
Quantity[um]|None) – Distal 3-D endpoint of each segment, shape(n_segments, 3). Must be provided together with points_proximal or both set toNone.type (
str) – Anatomical branch type. One of"soma","dendrite","axon","basal_dendrite","apical_dendrite", or"custom"(default).
- Raises:
TypeError – If any geometric input is a bare number without
brainunitunits.ValueError – If lengths is empty, total length is zero, array shapes are inconsistent, type is not in the allowed set, or point-derived lengths do not match lengths.
See also
Branch.from_lengthsPreferred constructor from segment lengths.
Branch.from_pointsPreferred constructor from 3-D point sequences.
MorphoMutable morphology tree that owns branches.
Notes
Prefer the factory classmethods
from_lengths()andfrom_points()over the raw constructor. The factories handleshared-radius expansion and automatically insert zero-length jump segments at radius discontinuities between adjacent segments.
Each segment is modelled as a truncated cone (frustum). Surface areas are computed with the lateral-surface formula \(A = \pi (r_0 + r_1) \sqrt{L^2 + (r_1 - r_0)^2}\)
and volumes with the frustum formula \(V = \frac{\pi L}{3} (r_0^2 + r_0 r_1 + r_1^2)\).
Examples
Create a branch from segment lengths and shared radii:
>>> import brainunit as u >>> from braincell import Branch >>> b = Branch.from_lengths( ... lengths=[10.0, 15.0, 20.0] * u.um, ... radii=[3.0, 2.5, 2.0, 1.5] * u.um, ... type="dendrite", ... ) >>> b.n_segments 3 >>> b.length 45.0 * umetre
Create a branch from 3-D coordinates:
>>> import numpy as np >>> pts = np.array([[0, 0, 0], [10, 0, 0], [10, 20, 0]]) * u.um >>> b = Branch.from_points( ... points=pts, ... radii=[2.0, 1.5, 1.0] * u.um, ... type="axon", ... ) >>> b.points is not None True
- property area: Quantity[um^2]#
Total lateral surface area (sum of segment areas).
- Returns:
Total surface area.
- Return type:
Quantity[u.um ** 2]
- property areas: Quantity[um^2]#
Lateral surface area of each segment (frustum formula).
- Returns:
Area array, shape
(n_segments,).- Return type:
Quantity[u.um ** 2]
Notes
Zero-length jump segments inserted at radius discontinuities by
_canonicalize_segmentscontribute a non-zero annular end-cap area \(\pi (r_0 + r_1) |r_1 - r_0|\). This is geometrically correctbut may be unexpected when iterating segment areas individually.
- property diam_arc_mean: Quantity[um]#
Return the arc-length-weighted mean diameter of this branch.
This is the branch-level diameter counterpart to
mean_radius: each segment contributes its average diameterr_proximal + r_distalweighted by segment arc length.- Returns:
Length-weighted average diameter.
- Return type:
Quantity[u.um]
- classmethod from_lengths(*, lengths, radii=None, radii_proximal=None, radii_distal=None, type=<object object>)[source]#
Create a branch from segment lengths and radii.
- Parameters:
lengths (
Quantity[um]) – Per-segment lengths, shape(n_segments,).radii (
Quantity[um]|None) – Shared radii at segment boundaries, shape(n_segments + 1,). Mutually exclusive with radii_proximal and radii_distal.radii_proximal (
Quantity[um]|None) – Proximal radius of each segment, shape(n_segments,). Must be provided together with radii_distal.radii_distal (
Quantity[um]|None) – Distal radius of each segment, shape(n_segments,). Must be provided together with radii_proximal.type (
str) – Branch type (default"custom"). Not accepted by typed subclasses such asSoma,Dendrite, etc.
- Returns:
New branch with no 3-D point geometry.
- Return type:
- Raises:
TypeError – If neither radii nor the pair (radii_proximal, radii_distal) is provided, or if both are provided simultaneously. Also raised if type is passed to a typed subclass.
ValueError – If array shapes are inconsistent or radius discontinuities exist.
See also
from_pointsCreate a branch from 3-D point coordinates.
Examples
>>> import brainunit as u >>> from braincell import Branch >>> b = Branch.from_lengths( ... lengths=[10.0, 20.0] * u.um, ... radii=[2.0, 1.5, 1.0] * u.um, ... type="dendrite", ... ) >>> b.n_segments 2
- classmethod from_points(*, points, radii=None, radii_proximal=None, radii_distal=None, type=<object object>)[source]#
Create a branch from ordered 3-D point coordinates.
Segment lengths are computed automatically from consecutive point distances. Warns if any pair of consecutive points coincide (producing zero-length segments).
- Parameters:
points (
Quantity[um]) – Ordered 3-D coordinates, shape(n_points, 3)withn_points >= 2.radii (
Quantity[um]|None) – Shared radii at each point, shape(n_points,). Mutually exclusive with radii_proximal and radii_distal.radii_proximal (
Quantity[um]|None) – Proximal radius of each segment, shape(n_points - 1,). Must be provided together with radii_distal.radii_distal (
Quantity[um]|None) – Distal radius of each segment, shape(n_points - 1,). Must be provided together with radii_proximal.type (
str) – Branch type (default"custom"). Not accepted by typed subclasses such asSoma,Dendrite, etc.
- Returns:
New branch with 3-D point geometry attached.
- Return type:
- Raises:
TypeError – If neither radii nor the pair (radii_proximal, radii_distal) is provided, or if both are provided simultaneously. Also raised if type is passed to a typed subclass.
ValueError – If points has fewer than two rows or array shapes are inconsistent.
- Warns:
UserWarning – If consecutive points coincide, producing zero-length segments.
See also
from_lengthsCreate a branch from segment lengths (no 3-D points).
Examples
>>> import brainunit as u >>> import numpy as np >>> from braincell import Branch >>> pts = np.array([[0, 0, 0], [10, 0, 0], [10, 20, 0]]) * u.um >>> b = Branch.from_points( ... points=pts, ... radii=[2.0, 1.5, 1.0] * u.um, ... type="axon", ... ) >>> b.n_segments 2 >>> b.points.shape (3, 3)
- property length: Quantity[um]#
Return the total length of this branch.
- Returns:
Sum of all segment lengths.
- Return type:
Quantity[u.um]
- classmethod load_checkpoint(path)[source]#
Load a branch from a braincell checkpoint file.
- Parameters:
path (str or os.PathLike) – Path to a
.bcmcheckpoint produced bysave_checkpoint().- Returns:
The reconstructed branch as the appropriate typed subclass (e.g.
Soma,Dendrite).- Return type:
- Raises:
TypeError – If called on a typed subclass (e.g.
Soma.load_checkpoint) and the saved branch type does not match the subclass type.CheckpointError – If the file is not a valid branch checkpoint.
See also
Branch.save_checkpointInverse operation.
Morpho.load_checkpointLoad a whole morphology tree.
Examples
>>> from braincell import Branch >>> branch = Branch.load_checkpoint("dend.bcm")
- property mean_radius: Quantity[um]#
Return the length-weighted mean radius of this branch.
Each segment contributes its average radius
0.5 * (r_proximal + r_distal)weighted by its length.- Returns:
Length-weighted average radius.
- Return type:
Quantity[u.um]
- property n_segments: int#
Return the number of segments in this branch.
- Returns:
Segment count, always
>= 1.- Return type:
- property points: Quantity[um] | None#
Shared 3-D points at segment boundaries when continuous.
- Returns:
Shared points array, shape
(n_segments + 1, 3), orNonefor branches created byfrom_lengths()(no point geometry).- Return type:
Quantity[u.um] or None
- Raises:
ValueError – If any adjacent boundary has
points_distal[i] != points_proximal[i+1].
Notes
For a single-segment branch the boundary check is vacuously satisfied (there are no inter-segment boundaries), so this property always succeeds regardless of whether the two endpoint coordinates coincide.
- property radii: Quantity[um]#
Shared radii at segment boundaries when continuous.
- Returns:
Shared radii array, shape
(n_segments + 1,).- Return type:
Quantity[u.um]
- Raises:
ValueError – If any adjacent boundary has
radii_distal[i] != radii_proximal[i+1].
Notes
For a single-segment branch the boundary check is vacuously satisfied (there are no inter-segment boundaries), so this property always succeeds even if the segment is tapered (
radii_proximal != radii_distal).
- save_checkpoint(path)[source]#
Write this branch to a braincell checkpoint file.
- Parameters:
path (str or os.PathLike) – Destination path.
.bcmis appended automatically when the supplied path has no suffix.- Returns:
The final path the checkpoint was written to.
- Return type:
Path
See also
Branch.load_checkpointInverse operation.
Morpho.save_checkpointPersist a whole morphology tree.
Examples
>>> import brainunit as u >>> from braincell import Branch >>> branch = Branch.from_lengths( ... lengths=[10.0, 15.0] * u.um, ... radii=[2.0, 1.5, 1.0] * u.um, ... type="dendrite", ... ) >>> branch.save_checkpoint("dend.bcm")
- vis2d(*, layout=None, shape=None, branch_type_colors=None, branch_type_edge_colors_2d=None, frustum_edge_linewidth_2d=None, backend=None, chooser=None, projection_plane='xy', return_plotter=False, show=True)[source]#
Visualize this branch in 2D.
Creates a temporary single-branch morphology and renders it using the existing 2D visualization pipeline.
- Parameters:
layout (
str|None) – 2-D layout choice:"projected","stem","balloon", or"radial_360". When omitted, uses the global 2-D default configured viabraincell.morph.vis.configure(...).shape (
str|None) – 2-D drawing shape:"line"or"frustum".branch_type_colors (
dict[str,object] |None) – Per-branch-type colour overrides for this call only. These colours drive both 2D line rendering and 2D frustum fills.branch_type_edge_colors_2d (
dict[str,object] |None) – Per-branch-type frustum border colour overrides for this call only.frustum_edge_linewidth_2d (
float|None) – Frustum border linewidth override for this call only.backend (
str|None) – Rendering backend name (e.g.,"matplotlib"). Auto-selected when None.chooser (BackendChooser or None) – Explicit backend chooser; overrides backend when given.
projection_plane (
str) – Projection plane forlayout="projected":"xy","xz", or"yz"(default"xy").return_plotter (
bool) – If True, return the backend plotter/axes object instead of displaying the figure.show (
bool) – If True (default), callmatplotlib.pyplot.show()after rendering. Set to False to suppress display (e.g., when embedding in a larger figure or running in tests).
- Returns:
The backend plotter/axes when return_plotter is True; otherwise the backend’s default display result.
- Return type:
- Raises:
ValueError – If
layout="projected"and the branch has no 3-D point geometry, or iflayout="projected"is combined withshape="frustum".
Examples
>>> import brainunit as u >>> from braincell import Branch >>> branch = Branch.from_lengths( ... lengths=[10.0, 15.0, 20.0] * u.um, ... radii=[3.0, 2.5, 2.0, 1.5] * u.um, ... type="dendrite", ... ) >>> branch.vis2d()
- vis3d(*, mode=None, backend=None, chooser=None, notebook=None, jupyter_backend=None, return_plotter=False, show=True)[source]#
Visualize this branch in 3D.
Creates a temporary single-branch morphology and renders it using the existing 3D visualization pipeline.
- Parameters:
mode (
str|None) – Visualization mode. When omitted, uses the global 3-D default configured viabraincell.morph.vis.configure(...). The initial default is"geometry".backend (
str|None) – Rendering backend name (e.g.,"pyvista"). Auto-selected when None.chooser (BackendChooser or None) – Explicit backend chooser; overrides backend when given.
notebook (
bool|None) – Enable notebook-specific rendering when True. Use this in Jupyter notebooks or notebook-based docs so the 3-D scene is embedded in the cell output; leave it false/omitted when you want the raw backend plotter in a script.jupyter_backend (
str|None) – Jupyter backend name for notebook rendering. Use"html"for static HTML docs and headless builds; use interactive server/client backends only in a live Jupyter session configured for them.return_plotter (
bool) – If True, return the backend plotter object instead of displaying the figure.show (
bool) – If True (default), callmatplotlib.pyplot.show()after rendering. Set to False to suppress display.
- Returns:
The backend plotter when return_plotter is True; otherwise the backend’s default display result.
- Return type:
- Raises:
ValueError – If the branch lacks complete 3-D point geometry.
- property volume: Quantity[um^3]#
Total volume (sum of segment volumes).
- Returns:
Total volume.
- Return type:
Quantity[u.um ** 3]
- property volumes: Quantity[um^3]#
Per-segment volumes (frustum formula).
- Returns:
Volume array, shape
(n_segments,).- Return type:
Quantity[u.um ** 3]