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 Branch stores 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 brainunit values and normalised to u.um internally. Bare numeric inputs are rejected with TypeError; every value must carry explicit units.

Branches are frozen dataclasses: once constructed their geometry cannot be changed. Use Morpho to 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 to None.

  • 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 to None.

  • 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 brainunit units.

  • 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_lengths

Preferred constructor from segment lengths.

Branch.from_points

Preferred constructor from 3-D point sequences.

Morpho

Mutable morphology tree that owns branches.

Notes

Prefer the factory classmethods from_lengths() and from_points() over the raw constructor. The factories handle

shared-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_segments contribute a non-zero annular end-cap area \(\pi (r_0 + r_1) |r_1 - r_0|\). This is geometrically correct

but 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 diameter r_proximal + r_distal weighted 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 as Soma, Dendrite, etc.

Returns:

New branch with no 3-D point geometry.

Return type:

Branch

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_points

Create 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) with n_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 as Soma, Dendrite, etc.

Returns:

New branch with 3-D point geometry attached.

Return type:

Branch

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_lengths

Create 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 .bcm checkpoint produced by save_checkpoint().

Returns:

The reconstructed branch as the appropriate typed subclass (e.g. Soma, Dendrite).

Return type:

Branch

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_checkpoint

Inverse operation.

Morpho.load_checkpoint

Load 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:

int

property points: Quantity[um] | None#

Shared 3-D points at segment boundaries when continuous.

Returns:

Shared points array, shape (n_segments + 1, 3), or None for branches created by from_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. .bcm is 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_checkpoint

Inverse operation.

Morpho.save_checkpoint

Persist 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 via braincell.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 for layout="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), call matplotlib.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:

object

Raises:

ValueError – If layout="projected" and the branch has no 3-D point geometry, or if layout="projected" is combined with shape="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 via braincell.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), call matplotlib.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:

object

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]