Skip to content

Data Layer Classes

Data layer classes represent different geometric and topological views of neuromorphological data. Each layer type is optimized for specific types of analysis while maintaining a consistent interface.

Overview

Layer Type Purpose Key Features
SkeletonLayer Tree-structured representations Hierarchical analysis, pathfinding, root-based operations
GraphLayer General graph connectivity Shortest paths, spatial queries, flexible topology
MeshLayer 3D surface geometry Surface area, face connectivity, mesh operations
PointCloudLayer Sparse annotations Lightweight markers, flexible metadata

SkeletonLayer

Specialized for tree-structured neuronal representations with hierarchical analysis capabilities.

SkeletonLayer

SkeletonLayer(name: str, vertices: Union[ndarray, DataFrame], edges: Union[ndarray, DataFrame], spatial_columns: Optional[list] = None, root: Optional[int] = None, *, vertex_index: Optional[Union[str, ndarray]] = None, features: Optional[Union[dict, DataFrame]] = None, morphsync: MorphSync = None, linkage: Optional[dict] = None, inherited_properties: Optional[dict] = None)

Bases: GraphLayer

Methods:

  • distance_between

    Get the distance between two sets of vertices in the skeleton.

  • path_between

    Get the shortest path between two vertices in the skeleton.

  • get_feature

    Get a feature array from the features DataFrame.

  • add_feature

    Add a new vertex feature to the layer.

  • drop_features

    Drop features from the DataFrame.

  • map_features_to_layer

    Map features from one layer to another.

  • map_index_to_layer

    Map each vertex index from the current layer to a single index in the specified layer.

  • map_region_to_layer

    Map each vertex index from the current layer to the specified layer.

  • map_index_to_layer_region

    Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

  • map_mask_to_layer

    Map a boolean mask from the current layer to the specified layer.

  • apply_mask

    Apply a mask on the current layer. Returns a new object with the masked morphsync.

  • copy

    Create a deep copy of the current object.

  • mask_context

    Context manager to temporarily apply a mask via the current layer.

  • get_unmapped_vertices

    Identify vertices in this layer that have no mapping to specified target layers.

  • mask_out_unmapped

    Create a new object with unmapped vertices removed.

  • describe

    Generate a compact description of the layer including vertices, features, and links.

  • loc

    Passthrough to layer.nodes.loc

  • iloc

    Passthrough to layer.nodes.iloc

  • proximity_mapping

    Get a DataFrame of all vertices within a certain distance of each other.

  • reroot

    Reroot to a new index. Important: that this will reset any inherited properties from an unmasked skeleton!

  • distance_to_root

    Get the distance to the root for each vertex in the skeleton, or for a subset of vertices.

  • hops_to_root

    Distance to root in number of hops between vertices. Always works on the base graph, whether the root is masked out or not.

  • child_vertices

    Get mapping from vertices to their child nodes.

  • downstream_vertices

    Get all vertices downstream of a specified vertex

  • cable_length

    The net cable length of the subgraph formed by given vertices. If no vertices are provided, the entire graph is used.

  • lowest_common_ancestor

    Get the lowest common ancestor of two vertices in the skeleton.

  • cover_paths_specific

    Get cover paths starting from specific source vertices.

  • segments_capped

    Get segments that are capped at a maximum length.

  • expand_to_segment

    For each vertex in vertices, get the corresponding segment.

  • map_annotations_to_feature

    Aggregates a point annotation to a feature on the layer based on a maximum proximity.

Attributes:

edges property

edges: ndarray

Get the edges of the layer in dataframe indices.

edge_df property

edge_df: DataFrame

Get the edges of the layer as a DataFrame.

edges_positional property

edges_positional: ndarray

Get the edges of the layer in positional indices.

csgraph property

csgraph: csr_matrix

Get the compressed sparse graph representation of the layer with Euclidean edge weights.

csgraph_binary property

csgraph_binary: csr_matrix

Get the unweighted compressed sparse graph representation of the layer.

csgraph_undirected property

csgraph_undirected: csr_matrix

Get the undirected compressed sparse graph representation of the layer with Euclidean edge weights.

csgraph_binary_undirected property

csgraph_binary_undirected: csr_matrix

Get the unweighted and undirected compressed sparse graph representation of the layer.

name property

name: str

Layer name.

layer property

layer: Facet

Get the morphsync layer associated with the data layer.

vertices property

vertices: ndarray

Get the Nx3 vertex positions of the data layer.

vertex_df property

vertex_df: DataFrame

Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

vertex_index property

vertex_index: ndarray

Get vertex indices as a numpy array.

vertex_index_map property

vertex_index_map: dict

Get a dictionary mapping vertex indices to their positional indices.

nodes property

nodes: DataFrame

Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

spatial_columns property

spatial_columns: list

Get the list of column names associated with the x, y, and z positions.

feature_names property

feature_names: list

Get the list of column names associated with features (non-spatial columns).

features property

features: DataFrame

Get the features DataFrame.

n_vertices property

n_vertices: int

Get the number of vertices in the data layer.

bbox property

bbox: array

Get the axis-aligned bounding box (min, max) of the data layer's vertices.

kdtree property

kdtree: KDTree

Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

half_edge_length property

half_edge_length: ndarray

Get the sum length of half-edges from a vertices to all parents and children.

Returns:

  • ndarray

    Array of half-edge lengths for each vertex.

root property

root: Optional[int]

Get the root node index.

Returns:

  • Optional[int]

    Root node index, or None if no root is set.

root_positional property

root_positional: Optional[int]

Get the root node positional index.

Returns:

  • Optional[int]

    Root node positional index, or None if no root is set.

root_location property

root_location: Optional[ndarray]

Get the spatial coordinates of the root node.

Returns:

  • Optional[ndarray]

    3D coordinates of the root node, or None if no root is set.

parent_node_array property

parent_node_array: ndarray

Get the parent node array for the skeleton, or -1 for a missing parent.

branch_points property

branch_points: ndarray

List of branch points of the skeleton based on vertex index

branch_points_positional property

branch_points_positional: ndarray

List of branch points of the skeleton based on positional index

end_points property

end_points: ndarray

List of end points of the skeleton based on vertex index

end_points_positional property

end_points_positional: ndarray

List of end points of the skeleton based on positional index

end_points_undirected property

end_points_undirected: ndarray

List of end points of the skeleton based on vertex index potentially including root if a leaf node

end_points_undirected_positional property

end_points_undirected_positional: ndarray

List of end points of the skeleton based on positional index potentially including root if a leaf node

branch_points_undirected property

branch_points_undirected: ndarray

List of branch points of the skeleton based on vertex index potentially including root if a leaf node

branch_points_undirected_positional property

branch_points_undirected_positional: ndarray

List of branch points of the skeleton based on positional index potentially including root if a leaf node

n_end_points property

n_end_points: int

Number of end points in the skeleton

n_branch_points property

n_branch_points: int

Number of branch points in the skeleton

topo_points property

topo_points: ndarray

All vertices not along a segment: branch points, end points, and root node

topo_points_positional property

topo_points_positional: ndarray

All vertices not along a segment: branch points, end points, and root node

n_topo_points property

n_topo_points: int

Number of topological points in the skeleton

parentless_nodes property

parentless_nodes: ndarray

List of nodes by vertex index that do not have any parents, including any root node.

parentless_nodes_positional property

parentless_nodes_positional: ndarray

List of nodes by positional index that do not have any parents, including any root node.

as_tuple property

as_tuple: Tuple[ndarray, ndarray]

Get the vertices and (positional) edges of the graph as a tuple, which is a common input to many functions.

cover_paths property

cover_paths: List[ndarray]

A collection of unbranched paths from each end point toward the root. Each path ends when it hits a vertex that's already been visited in a previous path. Paths are represented in dataframe indices.

cover_paths_positional property

cover_paths_positional: List[ndarray]

A collection of unbranched paths from each end point toward the root. Each path ends when it hits a vertex that's already been visited in a previous path. Paths are represented in positional indices.

segments_positional property

segments_positional: List[ndarray]

Get the segments of the layer, a list of arrays where each array represents an unbranched span from end point or branch point to the upstring branch point or root (non-inclusive). Segments are presented in positional indices.

Returns:

  • List[ndarray]

    List of segment arrays in positional indices.

segments property

segments: List[ndarray]

Get the segments of the layer, a list of arrays where each array represents an unbranched span from end point or branch point to the upstring branch point or root (non-inclusive). Segments are presented in dataframe indices.

segments_plus_positional property

segments_plus_positional: List[ndarray]

Segments plus their parent node in positional indices.

Returns:

  • List[ndarray]

    List of segment arrays including parent nodes in positional indices.

segments_plus property

segments_plus: List[ndarray]

Segments plus their parent node in dataframe indices.

Returns:

  • List[ndarray]

    List of segment arrays including parent nodes in dataframe indices.

segment_map property

segment_map: ndarray

Get the mapping from each vertex to its segment index

distance_between

distance_between(sources: Optional[ndarray] = None, targets: Optional[ndarray] = None, as_positional=False, limit: Optional[float] = None) -> ndarray

Get the distance between two sets of vertices in the skeleton.

Parameters:

  • sources (Optional[ndarray], default: None ) –

    The source vertices. If None, all vertices are used.

  • targets (Optional[ndarray], default: None ) –

    The target vertices. If None, all vertices are used.

  • as_positional

    Whether the input vertices are positional (i.e., masks or indices). Must be the same for sources and targets.

  • limit (Optional[float], default: None ) –

    The maximum distance to consider in the graph distance lookup. If None, no limit is applied. Distances above this will be set to infinity.

Returns:

  • ndarray

    The distance between each source and target vertex, of dimensions len(sources) x len(targets).

path_between

path_between(source: int, target: int, as_positional=False, as_vertices=False) -> ndarray

Get the shortest path between two vertices in the skeleton.

Parameters:

  • source (int) –

    The source vertex.

  • target (int) –

    The target vertex.

  • as_positional

    Whether the input vertices are positional (i.e., masks or indices). Must be the same for sources and targets.

  • as_vertices

    Whether to return the path as vertex IDs or 3d positions.

Returns:

  • ndarray

    The shortest path between each source and target vertex, indices if as_positional is False, or nx3 array if as_vertices is True.

get_feature

get_feature(key: str) -> ndarray

Get a feature array from the features DataFrame.

Parameters:

  • key (str) –

    Column name of the feature to retrieve.

Returns:

  • ndarray

    Array of feature values for all vertices.

add_feature

add_feature(feature: Union[list, ndarray, dict, DataFrame], name: Optional[str] = None) -> Self

Add a new vertex feature to the layer.

Parameters:

  • feature (Union[list, ndarray, dict, DataFrame]) –

    The feature data to add. If an array or list, it should follow the vertex order.

  • name (Optional[str], default: None ) –

    The name of the feature column (required if feature is a list or np.ndarray).

Returns:

  • Self

    The updated DataLayer instance.

drop_features

drop_features(features: Union[str, list]) -> Self

Drop features from the DataFrame.

Parameters:

  • features (Union[str, list]) –

    The feature column name or list of names to drop.

Returns:

  • Self

    The updated DataLayer instance.

map_features_to_layer

map_features_to_layer(features: Union[str, list], layer: str, agg: Union[str, dict] = 'mean') -> DataFrame

Map features from one layer to another.

Parameters:

  • features (Union[str, list]) –

    The features to map from the source layer.

  • layer (str) –

    The target layer to map the features to.

  • agg (Union[str, dict], default: 'mean' ) –

    The aggregation method to use when mapping the features. This can take anything pandas groupby.agg takes, as well as "majority" which will is a majority vote across the mapped indices via the stats.mode function.

Returns:

  • DataFrame

    The mapped features for the target layer. Vertices with no mapping will have NaN values.

map_index_to_layer

map_index_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False, validate: bool = False) -> ndarray

Map each vertex index from the current layer to a single index in the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source index to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

  • validate (bool, default: False ) –

    Whether to raise an error is the mapping is ambiguous, i.e. it is not clear which target index to use.

Returns:

  • ndarray

    The mapped indices in the target layer. There will be exactly one target index for each source index, no matter how many viable target indices there are. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_region_to_layer

map_region_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> ndarray

Map each vertex index from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • ndarray

    All mapped indices in the target layer. Not necessarily the same length as the source indices, because it maps a region to another region. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_index_to_layer_region

map_index_to_layer_region(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> dict

Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • dict

    A dictionary mapping each source index to a list of all mapped target indices.

map_mask_to_layer

map_mask_to_layer(layer: str, mask: Optional[ndarray] = None) -> ndarray

Map a boolean mask from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • mask (Optional[ndarray], default: None ) –

    The boolean mask to map from. If None, all vertices are used.

Returns:

  • ndarray

    The mapped boolean mask in the target layer. There may be multiple target indices for each source index, depending on the region mapping. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

apply_mask

apply_mask(mask: ndarray, as_positional: bool = False, self_only: bool = False) -> Union[Self, Cell]

Apply a mask on the current layer. Returns a new object with the masked morphsync. If the object is associated with a CellSync, a new CellSync will be created, otherwise a new object of the same class will be returned.

Properties

mask: np.ndarray The mask to apply, either in boolean, vertex index, or positional index form. as_positional: bool If providing indices, specify if they are positional indices (True) or vertex indices (False). self_only: bool If True, only apply the mask to the current object and not to any associated CellSync.

Returns:

  • masked_object Union[Self, "CellSync"]

    Either a new object of the same class or a new CellSync will be returned.

copy

copy() -> Self

Create a deep copy of the current object.

Returns:

  • Union[Self, Cell]

    A new object of the same class without the CellSync.

mask_context

mask_context(mask: ndarray) -> Generator[Self, None, None]

Context manager to temporarily apply a mask via the current layer.

Parameters:

  • mask (ndarray) –

    The mask to apply, either in boolean, vertex index, or positional index form.

Yields:

  • Self

    A new object of the same class with the mask applied.

Example

with cell.skeleton.mask_context(mask) as masked_cell: masked_path_length = masked_cell.mesh.surface_area()

get_unmapped_vertices

get_unmapped_vertices(target_layers: Optional[Union[str, List[str]]] = None) -> ndarray

Identify vertices in this layer that have no mapping to specified target layers.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

Returns:

  • ndarray

    Vertices in this layer that have null mappings to any of the target layers.

mask_out_unmapped

mask_out_unmapped(target_layers: Optional[Union[str, List[str]]] = None, self_only: bool = False) -> Union[Self, Cell]

Create a new object with unmapped vertices removed.

This function identifies vertices that have null mappings to specified target layers and creates a masked version of the object with those vertices removed.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

  • self_only (bool, default: False ) –

    If True, only apply mask to current layer. If False, apply to entire Cell. Default False.

Returns:

  • Union[Self, Cell]

    New object with unmapped vertices removed.

Examples:

>>> # Remove skeleton vertices that don't map to mesh
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh")
>>> # Remove vertices that don't map to multiple layers
>>> clean_skeleton = skeleton.mask_out_unmapped(["mesh", "annotations"])
>>> # Clean up only the current layer, not the whole cell
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh", self_only=True)
>>> # Remove vertices that don't map to ANY other layer
>>> clean_skeleton = skeleton.mask_out_unmapped()

describe

describe() -> None

Generate a compact description of the layer including vertices, features, and links.

Provides information about: - Layer name and type - Vertex count (and edges/faces for applicable layer types) - feature names - Links to other layers

Returns:

  • None

    Always returns None (prints formatted text)

loc

loc(key: Union[str, List[str], ndarray]) -> DataFrame

Passthrough to layer.nodes.loc

iloc

iloc(key: Union[int, List[int], ndarray]) -> DataFrame

Passthrough to layer.nodes.iloc

proximity_mapping

proximity_mapping(distance_threshold: float, chunk_size: int = 1000, agg_direction: Literal['undirected', 'upstream', 'downstream'] = 'undirected') -> DataFrame

Get a DataFrame of all vertices within a certain distance of each other.

Parameters:

  • distance_threshold (float) –

    Maximum distance to consider for proximity.

  • chunk_size (int, default: 1000 ) –

    Size of processing chunks for memory efficiency. Default 1000.

  • agg_direction (Literal['undirected', 'upstream', 'downstream'], default: 'undirected' ) –

    Direction along the skeleton to consider for proximity. Options are 'undirected', 'upstream', 'downstream'. "undirected" considers all neighbors within the distance threshold. "upstream" considers only neighbors towards the root. "downstream" considers only neighbors away from the root. Default is 'undirected'.

Returns:

  • DataFrame

    DataFrame with columns 'idx' and 'prox_idx' indicating pairs of proximal vertices.

reroot

reroot(new_root: int, as_positional=False) -> Self

Reroot to a new index. Important: that this will reset any inherited properties from an unmasked skeleton!

Parameters:

  • new_root (int) –

    The new root index to set.

  • as_positional

    Whether the new root is a positional index. If False, the new root is treated as a vertex feature.

Returns:

distance_to_root

distance_to_root(vertices: Optional[ndarray] = None, as_positional=False) -> ndarray

Get the distance to the root for each vertex in the skeleton, or for a subset of vertices. Always uses the original skeleton topology, so that root is inherited from the original root even if it is currently masked out. E.g. if you mask an axon only, you can still get distance to the root soma even if the soma is not in your current object.

Parameters:

  • vertices (Optional[ndarray], default: None ) –

    The vertices to get the distance from the root for. If None, all vertices are used.

  • as_positional (bool, default: False ) –

    If True, the vertices are treated as positional indices. If False, they are treated as vertex features.

Returns:

  • ndarray

    The distance from the root for each vertex.

hops_to_root

hops_to_root(vertices: Optional[ndarray] = None, as_positional=False) -> ndarray

Distance to root in number of hops between vertices. Always works on the base graph, whether the root is masked out or not.

Parameters:

  • vertices (Optional[ndarray], default: None ) –

    The vertices to get the distance from the root for. If None, all vertices are used.

  • as_positional (bool, default: False ) –

    If True, the vertices are treated as positional indices. If False, they are treated as vertex features.

Returns:

  • ndarray

    The distance from the root for each vertex.

child_vertices

child_vertices(vertices=None, as_positional=False) -> dict

Get mapping from vertices to their child nodes.

Parameters:

  • vertices (Union[ndarray, List[int]], default: None ) –

    The vertices to get the child nodes for.

  • as_positional (bool, default: False ) –

    Whether the vertices are positional indices. If False, they are treated as vertex features.

Returns:

  • dict

    A dictionary mapping each vertex to its child nodes.

downstream_vertices

downstream_vertices(vertex, inclusive=False, as_positional=False) -> ndarray

Get all vertices downstream of a specified vertex

Parameters:

  • vertex (Union[int, ndarray]) –

    The vertex to get the downstream vertices for.

  • inclusive

    Whether to include the specified vertex in the downstream vertices.

  • as_positional (bool, default: False ) –

    Whether the vertex is a positional index. If False, it is treated as a vertex feature.

Returns:

  • ndarray

    The downstream vertices, following the same mode as the as_positional parameter.

cable_length

cable_length(vertices: Optional[Union[list, ndarray]] = None, as_positional=False) -> float

The net cable length of the subgraph formed by given vertices. If no vertices are provided, the entire graph is used.

Parameters:

  • vertices (Optional[Union[list, ndarray]], default: None ) –

    The vertices to include in the subgraph. If None, the entire graph is used.

  • as_positional (bool, default: False ) –

    Whether the vertices are positional indices. If False, they are treated as vertex features.

Returns:

  • float

    The net cable length of the subgraph.

lowest_common_ancestor

lowest_common_ancestor(u: int, v: int, as_positional=False) -> Optional[int]

Get the lowest common ancestor of two vertices in the skeleton.

Parameters:

  • u (int) –

    The first vertex.

  • v (int) –

    The second vertex.

  • as_positional (bool, default: False ) –

    Whether the vertices are positional indices. If False, they are treated as vertex features.

Returns:

  • Optional[int]

    The lowest common ancestor of the two vertices, or None if not found.

cover_paths_specific

cover_paths_specific(sources: Union[ndarray, list], as_positional: bool = False) -> List[ndarray]

Get cover paths starting from specific source vertices.

Parameters:

  • sources (Union[ndarray, list]) –

    The source vertices to start the cover paths from.

  • as_positional (bool, default: False ) –

    Whether the sources are positional indices. If False, they are treated as vertex features.

Returns:

  • list

    A list of cover paths, each path is a list of vertex indices, ordered as the typical cover_paths method.

segments_capped

segments_capped(max_length: float, positional: bool = True) -> List[ndarray]

Get segments that are capped at a maximum length.

Parameters:

  • max_length (float) –

    The maximum length of each segment.

  • positional (bool, default: True ) –

    Whether to return segments in positional indices. Default True.

expand_to_segment

expand_to_segment(vertices: Union[ndarray, List[int]], as_positional: bool = False) -> List[ndarray]

For each vertex in vertices, get the corresponding segment.

Parameters:

  • vertices (Union[ndarray, List[int]]) –

    Vertices to expand to their segments.

  • as_positional (bool, default: False ) –

    Whether vertices are positional indices. Default False.

Returns:

  • List[ndarray]

    List of segments corresponding to input vertices.

map_annotations_to_feature

map_annotations_to_feature(annotation: str, distance_threshold: float, agg: Union[Literal['count', 'density'], dict] = 'count', chunk_size: int = 1000, validate: bool = False, agg_direction: Literal['undirected', 'upstream', 'downstream'] = 'undirected') -> Union[Series, DataFrame]

Aggregates a point annotation to a feature on the layer based on a maximum proximity.

Parameters:

  • annotation (str) –

    The name of the annotation to project.

  • distance_threshold (float) –

    The maximum distance to consider for projecting annotations.

  • agg (Union[Literal['count', 'density'], dict], default: 'count' ) –

    The aggregation method to use. Can be "count", or a dict specifying custom aggregations on the annotations properties as per the groupby.agg method. * "count" returns how many annotations are within the given radius. * "density" returns the count of annotations divided by the subgraph path length measured in half-edge-lengths per vertex. * To make a new feature called "aggregate_feature" that is the median "size" of a point annotation, it would be {"aggregate_feature": ('size', 'median')}. Multiple features can be specified at the same time in this manner.

  • chunk_size (int, default: 1000 ) –

    The size of chunks to process at a time, which limits memory consumption. Defaults to 1000.

Returns:

  • Series or DataFrame

    A series (with 'count' or 'density') or dataframe (with dictionary agg) containing the projected annotation values for each vertex.

Key Properties for Tree Analysis

  • root, root_location: Root node identification and coordinates
  • parent_node_array: Parent relationships defining tree structure
  • branch_points, end_points: Topological feature identification
  • segments, cover_paths: Path-based decomposition of tree structure
  • distance_to_root(), cable_length(): Distance measurements along tree paths

Usage Example

# Access tree structure
skeleton = cell.skeleton
root_pos = skeleton.root_location
branch_nodes = skeleton.branch_points

# Analyze tree topology  
distances = skeleton.distance_to_root([10, 20, 30])
subtree = skeleton.downstream_vertices(branch_node_id)

# Path analysis
path = skeleton.path_between(source_id, target_id)
total_length = skeleton.cable_length(path)

# Segment-based analysis
segment_id = skeleton.segment_map[vertex_id]
full_segment = skeleton.segments[segment_id]

GraphLayer

General-purpose graph representation for spatial connectivity analysis.

GraphLayer

GraphLayer(name: str, vertices: Union[ndarray, DataFrame], edges: Union[ndarray, DataFrame], spatial_columns: Optional[list] = None, *, vertex_index: Optional[Union[str, ndarray]] = None, features: Optional[Union[dict, DataFrame]] = None, morphsync: MorphSync = None, linkage: Optional[Link] = None, existing: bool = False)

Bases: PointMixin, EdgeMixin

Methods:

  • distance_between

    Get the distance between two sets of vertices in the skeleton.

  • path_between

    Get the shortest path between two vertices in the skeleton.

  • get_feature

    Get a feature array from the features DataFrame.

  • add_feature

    Add a new vertex feature to the layer.

  • drop_features

    Drop features from the DataFrame.

  • map_features_to_layer

    Map features from one layer to another.

  • map_index_to_layer

    Map each vertex index from the current layer to a single index in the specified layer.

  • map_region_to_layer

    Map each vertex index from the current layer to the specified layer.

  • map_index_to_layer_region

    Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

  • map_mask_to_layer

    Map a boolean mask from the current layer to the specified layer.

  • apply_mask

    Apply a mask on the current layer. Returns a new object with the masked morphsync.

  • copy

    Create a deep copy of the current object.

  • mask_context

    Context manager to temporarily apply a mask via the current layer.

  • get_unmapped_vertices

    Identify vertices in this layer that have no mapping to specified target layers.

  • mask_out_unmapped

    Create a new object with unmapped vertices removed.

  • describe

    Generate a compact description of the layer including vertices, features, and links.

  • loc

    Passthrough to layer.nodes.loc

  • iloc

    Passthrough to layer.nodes.iloc

  • proximity_mapping

    Get a DataFrame of all vertices within a certain distance of each other.

  • map_annotations_to_feature

    Aggregate a point annotation to a feature on the layer.

Attributes:

  • edges (ndarray) –

    Get the edges of the layer in dataframe indices.

  • edge_df (DataFrame) –

    Get the edges of the layer as a DataFrame.

  • edges_positional (ndarray) –

    Get the edges of the layer in positional indices.

  • csgraph (csr_matrix) –

    Get the compressed sparse graph representation of the layer with Euclidean edge weights.

  • csgraph_binary (csr_matrix) –

    Get the unweighted compressed sparse graph representation of the layer.

  • csgraph_undirected (csr_matrix) –

    Get the undirected compressed sparse graph representation of the layer with Euclidean edge weights.

  • csgraph_binary_undirected (csr_matrix) –

    Get the unweighted and undirected compressed sparse graph representation of the layer.

  • name (str) –

    Layer name.

  • layer (Facet) –

    Get the morphsync layer associated with the data layer.

  • vertices (ndarray) –

    Get the Nx3 vertex positions of the data layer.

  • vertex_df (DataFrame) –

    Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

  • vertex_index (ndarray) –

    Get vertex indices as a numpy array.

  • vertex_index_map (dict) –

    Get a dictionary mapping vertex indices to their positional indices.

  • nodes (DataFrame) –

    Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

  • spatial_columns (list) –

    Get the list of column names associated with the x, y, and z positions.

  • feature_names (list) –

    Get the list of column names associated with features (non-spatial columns).

  • features (DataFrame) –

    Get the features DataFrame.

  • n_vertices (int) –

    Get the number of vertices in the data layer.

  • bbox (array) –

    Get the axis-aligned bounding box (min, max) of the data layer's vertices.

  • kdtree (KDTree) –

    Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

  • half_edge_length (ndarray) –

    Get the sum length of half-edges from a vertices to all parents and children.

edges property

edges: ndarray

Get the edges of the layer in dataframe indices.

edge_df property

edge_df: DataFrame

Get the edges of the layer as a DataFrame.

edges_positional property

edges_positional: ndarray

Get the edges of the layer in positional indices.

csgraph property

csgraph: csr_matrix

Get the compressed sparse graph representation of the layer with Euclidean edge weights.

csgraph_binary property

csgraph_binary: csr_matrix

Get the unweighted compressed sparse graph representation of the layer.

csgraph_undirected property

csgraph_undirected: csr_matrix

Get the undirected compressed sparse graph representation of the layer with Euclidean edge weights.

csgraph_binary_undirected property

csgraph_binary_undirected: csr_matrix

Get the unweighted and undirected compressed sparse graph representation of the layer.

name property

name: str

Layer name.

layer property

layer: Facet

Get the morphsync layer associated with the data layer.

vertices property

vertices: ndarray

Get the Nx3 vertex positions of the data layer.

vertex_df property

vertex_df: DataFrame

Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

vertex_index property

vertex_index: ndarray

Get vertex indices as a numpy array.

vertex_index_map property

vertex_index_map: dict

Get a dictionary mapping vertex indices to their positional indices.

nodes property

nodes: DataFrame

Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

spatial_columns property

spatial_columns: list

Get the list of column names associated with the x, y, and z positions.

feature_names property

feature_names: list

Get the list of column names associated with features (non-spatial columns).

features property

features: DataFrame

Get the features DataFrame.

n_vertices property

n_vertices: int

Get the number of vertices in the data layer.

bbox property

bbox: array

Get the axis-aligned bounding box (min, max) of the data layer's vertices.

kdtree property

kdtree: KDTree

Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

half_edge_length property

half_edge_length: ndarray

Get the sum length of half-edges from a vertices to all parents and children.

Returns:

  • ndarray

    Array of half-edge lengths for each vertex.

distance_between

distance_between(sources: Optional[ndarray] = None, targets: Optional[ndarray] = None, as_positional=False, limit: Optional[float] = None) -> ndarray

Get the distance between two sets of vertices in the skeleton.

Parameters:

  • sources (Optional[ndarray], default: None ) –

    The source vertices. If None, all vertices are used.

  • targets (Optional[ndarray], default: None ) –

    The target vertices. If None, all vertices are used.

  • as_positional

    Whether the input vertices are positional (i.e., masks or indices). Must be the same for sources and targets.

  • limit (Optional[float], default: None ) –

    The maximum distance to consider in the graph distance lookup. If None, no limit is applied. Distances above this will be set to infinity.

Returns:

  • ndarray

    The distance between each source and target vertex, of dimensions len(sources) x len(targets).

path_between

path_between(source: int, target: int, as_positional=False, as_vertices=False) -> ndarray

Get the shortest path between two vertices in the skeleton.

Parameters:

  • source (int) –

    The source vertex.

  • target (int) –

    The target vertex.

  • as_positional

    Whether the input vertices are positional (i.e., masks or indices). Must be the same for sources and targets.

  • as_vertices

    Whether to return the path as vertex IDs or 3d positions.

Returns:

  • ndarray

    The shortest path between each source and target vertex, indices if as_positional is False, or nx3 array if as_vertices is True.

get_feature

get_feature(key: str) -> ndarray

Get a feature array from the features DataFrame.

Parameters:

  • key (str) –

    Column name of the feature to retrieve.

Returns:

  • ndarray

    Array of feature values for all vertices.

add_feature

add_feature(feature: Union[list, ndarray, dict, DataFrame], name: Optional[str] = None) -> Self

Add a new vertex feature to the layer.

Parameters:

  • feature (Union[list, ndarray, dict, DataFrame]) –

    The feature data to add. If an array or list, it should follow the vertex order.

  • name (Optional[str], default: None ) –

    The name of the feature column (required if feature is a list or np.ndarray).

Returns:

  • Self

    The updated DataLayer instance.

drop_features

drop_features(features: Union[str, list]) -> Self

Drop features from the DataFrame.

Parameters:

  • features (Union[str, list]) –

    The feature column name or list of names to drop.

Returns:

  • Self

    The updated DataLayer instance.

map_features_to_layer

map_features_to_layer(features: Union[str, list], layer: str, agg: Union[str, dict] = 'mean') -> DataFrame

Map features from one layer to another.

Parameters:

  • features (Union[str, list]) –

    The features to map from the source layer.

  • layer (str) –

    The target layer to map the features to.

  • agg (Union[str, dict], default: 'mean' ) –

    The aggregation method to use when mapping the features. This can take anything pandas groupby.agg takes, as well as "majority" which will is a majority vote across the mapped indices via the stats.mode function.

Returns:

  • DataFrame

    The mapped features for the target layer. Vertices with no mapping will have NaN values.

map_index_to_layer

map_index_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False, validate: bool = False) -> ndarray

Map each vertex index from the current layer to a single index in the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source index to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

  • validate (bool, default: False ) –

    Whether to raise an error is the mapping is ambiguous, i.e. it is not clear which target index to use.

Returns:

  • ndarray

    The mapped indices in the target layer. There will be exactly one target index for each source index, no matter how many viable target indices there are. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_region_to_layer

map_region_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> ndarray

Map each vertex index from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • ndarray

    All mapped indices in the target layer. Not necessarily the same length as the source indices, because it maps a region to another region. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_index_to_layer_region

map_index_to_layer_region(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> dict

Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • dict

    A dictionary mapping each source index to a list of all mapped target indices.

map_mask_to_layer

map_mask_to_layer(layer: str, mask: Optional[ndarray] = None) -> ndarray

Map a boolean mask from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • mask (Optional[ndarray], default: None ) –

    The boolean mask to map from. If None, all vertices are used.

Returns:

  • ndarray

    The mapped boolean mask in the target layer. There may be multiple target indices for each source index, depending on the region mapping. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

apply_mask

apply_mask(mask: ndarray, as_positional: bool = False, self_only: bool = False) -> Union[Self, Cell]

Apply a mask on the current layer. Returns a new object with the masked morphsync. If the object is associated with a CellSync, a new CellSync will be created, otherwise a new object of the same class will be returned.

Properties

mask: np.ndarray The mask to apply, either in boolean, vertex index, or positional index form. as_positional: bool If providing indices, specify if they are positional indices (True) or vertex indices (False). self_only: bool If True, only apply the mask to the current object and not to any associated CellSync.

Returns:

  • masked_object Union[Self, "CellSync"]

    Either a new object of the same class or a new CellSync will be returned.

copy

copy() -> Self

Create a deep copy of the current object.

Returns:

  • Union[Self, Cell]

    A new object of the same class without the CellSync.

mask_context

mask_context(mask: ndarray) -> Generator[Self, None, None]

Context manager to temporarily apply a mask via the current layer.

Parameters:

  • mask (ndarray) –

    The mask to apply, either in boolean, vertex index, or positional index form.

Yields:

  • Self

    A new object of the same class with the mask applied.

Example

with cell.skeleton.mask_context(mask) as masked_cell: masked_path_length = masked_cell.mesh.surface_area()

get_unmapped_vertices

get_unmapped_vertices(target_layers: Optional[Union[str, List[str]]] = None) -> ndarray

Identify vertices in this layer that have no mapping to specified target layers.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

Returns:

  • ndarray

    Vertices in this layer that have null mappings to any of the target layers.

mask_out_unmapped

mask_out_unmapped(target_layers: Optional[Union[str, List[str]]] = None, self_only: bool = False) -> Union[Self, Cell]

Create a new object with unmapped vertices removed.

This function identifies vertices that have null mappings to specified target layers and creates a masked version of the object with those vertices removed.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

  • self_only (bool, default: False ) –

    If True, only apply mask to current layer. If False, apply to entire Cell. Default False.

Returns:

  • Union[Self, Cell]

    New object with unmapped vertices removed.

Examples:

>>> # Remove skeleton vertices that don't map to mesh
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh")
>>> # Remove vertices that don't map to multiple layers
>>> clean_skeleton = skeleton.mask_out_unmapped(["mesh", "annotations"])
>>> # Clean up only the current layer, not the whole cell
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh", self_only=True)
>>> # Remove vertices that don't map to ANY other layer
>>> clean_skeleton = skeleton.mask_out_unmapped()

describe

describe() -> None

Generate a compact description of the layer including vertices, features, and links.

Provides information about: - Layer name and type - Vertex count (and edges/faces for applicable layer types) - feature names - Links to other layers

Returns:

  • None

    Always returns None (prints formatted text)

loc

loc(key: Union[str, List[str], ndarray]) -> DataFrame

Passthrough to layer.nodes.loc

iloc

iloc(key: Union[int, List[int], ndarray]) -> DataFrame

Passthrough to layer.nodes.iloc

proximity_mapping

proximity_mapping(distance_threshold: float, chunk_size: int = 1000, agg_direction: Literal['undirected', 'upstream', 'downstream'] = 'undirected') -> DataFrame

Get a DataFrame of all vertices within a certain distance of each other.

Parameters:

  • distance_threshold (float) –

    Maximum distance to consider for proximity.

  • chunk_size (int, default: 1000 ) –

    Size of processing chunks for memory efficiency. Default 1000.

  • agg_direction (Literal['undirected', 'upstream', 'downstream'], default: 'undirected' ) –

    Direction along the skeleton to consider for proximity. Options are 'undirected', 'upstream', 'downstream'. "undirected" considers all neighbors within the distance threshold. "upstream" considers only neighbors towards the root. "downstream" considers only neighbors away from the root. Default is 'undirected'.

Returns:

  • DataFrame

    DataFrame with columns 'idx' and 'prox_idx' indicating pairs of proximal vertices.

map_annotations_to_feature

map_annotations_to_feature(annotation: str, distance_threshold: float, agg: Union[str, dict] = 'count', chunk_size: int = 1000, validate: bool = False) -> Union[Series, DataFrame]

Aggregate a point annotation to a feature on the layer.

Parameters:

  • annotation (str) –

    The name of the annotation layer to aggregate.

  • distance_threshold (float) –

    Maximum distance to consider for aggregation.

  • agg (Union[str, dict], default: 'count' ) –

    Aggregation method. Can be 'count' or dict of aggregation functions. Default 'count'.

  • chunk_size (int, default: 1000 ) –

    Size of processing chunks for memory efficiency. Default 1000.

  • validate (bool, default: False ) –

    Whether to validate mapping consistency. Default False.

  • agg_direction (str) –

    Direction along the skeleton to consider for aggregation. Options are 'undirected', 'upstream', 'downstream'. "undirected" considers all neighbors within the distance threshold. "upstream" considers only neighbors towards the root. "downstream" considers only neighbors away from the root. Default is 'undirected'.

Returns:

  • Union[Series, DataFrame]

    Aggregated annotation values. Series for 'count', DataFrame for dict aggregations.

Key Properties for Graph Analysis

  • csgraph, csgraph_binary: Compressed sparse graph representations
  • edges, edges_positional: Edge connectivity in different index formats
  • kdtree: Spatial indexing for efficient nearest neighbor queries
  • distance_between(), path_between(): Graph-based distance and pathfinding

Usage Example

# Graph connectivity
graph = cell.graph
adjacency = graph.csgraph_binary
edge_list = graph.edges

# Spatial queries using KDTree
tree = graph.kdtree
nearest_ids = tree.query(query_points, k=5)

# Distance calculations
distances = graph.distance_between(
    sources=[1, 2, 3], 
    targets=[10, 20, 30],
    limit=1000  # Maximum search distance
)

# Pathfinding
path = graph.path_between(source_id, target_id)

MeshLayer

3D triangulated mesh representation for surface-based analysis.

MeshLayer

MeshLayer(name: str, vertices: Union[ndarray, DataFrame], faces: Union[ndarray, DataFrame], spatial_columns: Optional[list] = None, *, vertex_index: Optional[Union[str, ndarray]] = None, features: Optional[Union[dict, DataFrame]] = None, morphsync: MorphSync = None, linkage: Optional[Link] = None, existing: bool = False)

Bases: FaceMixin, PointMixin

Methods:

  • get_feature

    Get a feature array from the features DataFrame.

  • add_feature

    Add a new vertex feature to the layer.

  • drop_features

    Drop features from the DataFrame.

  • map_features_to_layer

    Map features from one layer to another.

  • map_index_to_layer

    Map each vertex index from the current layer to a single index in the specified layer.

  • map_region_to_layer

    Map each vertex index from the current layer to the specified layer.

  • map_index_to_layer_region

    Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

  • map_mask_to_layer

    Map a boolean mask from the current layer to the specified layer.

  • apply_mask

    Apply a mask on the current layer. Returns a new object with the masked morphsync.

  • copy

    Create a deep copy of the current object.

  • mask_context

    Context manager to temporarily apply a mask via the current layer.

  • get_unmapped_vertices

    Identify vertices in this layer that have no mapping to specified target layers.

  • mask_out_unmapped

    Create a new object with unmapped vertices removed.

  • describe

    Generate a compact description of the layer including vertices, features, and links.

  • loc

    Passthrough to layer.nodes.loc

  • iloc

    Passthrough to layer.nodes.iloc

  • surface_area

    Calculate the surface area of the mesh, or a subset of vertices.

Attributes:

  • name (str) –

    Layer name.

  • layer (Facet) –

    Get the morphsync layer associated with the data layer.

  • vertices (ndarray) –

    Get the Nx3 vertex positions of the data layer.

  • vertex_df (DataFrame) –

    Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

  • vertex_index (ndarray) –

    Get vertex indices as a numpy array.

  • vertex_index_map (dict) –

    Get a dictionary mapping vertex indices to their positional indices.

  • nodes (DataFrame) –

    Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

  • spatial_columns (list) –

    Get the list of column names associated with the x, y, and z positions.

  • feature_names (list) –

    Get the list of column names associated with features (non-spatial columns).

  • features (DataFrame) –

    Get the features DataFrame.

  • n_vertices (int) –

    Get the number of vertices in the data layer.

  • bbox (array) –

    Get the axis-aligned bounding box (min, max) of the data layer's vertices.

  • kdtree (KDTree) –

    Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

  • faces_positional (ndarray) –

    Return the triangle face indices of the mesh in positional indices.

  • faces (ndarray) –

    Return the triangle face indices of the mesh in raw indices.

  • as_trimesh (Trimesh) –

    Return the mesh as a trimesh.Trimesh object. Note that Trimesh works entirely in positional vertices.

  • as_tuple (Tuple[ndarray, ndarray]) –

    Tuple of (vertices, faces_positional) expected by many mesh-processing algorithms.

  • edges (ndarray) –

    Return the edge indices of the mesh in raw indices. Note that for each connected vertex pair u,v, there are both edges (u,v) and (v,u).

  • edges_positional (ndarray) –

    Return the edge indices of the mesh in positional indices. Note that for each connected vertex pair u,v, there are both edges (u,v) and (v,u).

  • csgraph (csr_matrix) –

    Generate a compressed sparse graph representation of the mesh as a network.

name property

name: str

Layer name.

layer property

layer: Facet

Get the morphsync layer associated with the data layer.

vertices property

vertices: ndarray

Get the Nx3 vertex positions of the data layer.

vertex_df property

vertex_df: DataFrame

Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

vertex_index property

vertex_index: ndarray

Get vertex indices as a numpy array.

vertex_index_map property

vertex_index_map: dict

Get a dictionary mapping vertex indices to their positional indices.

nodes property

nodes: DataFrame

Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

spatial_columns property

spatial_columns: list

Get the list of column names associated with the x, y, and z positions.

feature_names property

feature_names: list

Get the list of column names associated with features (non-spatial columns).

features property

features: DataFrame

Get the features DataFrame.

n_vertices property

n_vertices: int

Get the number of vertices in the data layer.

bbox property

bbox: array

Get the axis-aligned bounding box (min, max) of the data layer's vertices.

kdtree property

kdtree: KDTree

Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

faces_positional property

faces_positional: ndarray

Return the triangle face indices of the mesh in positional indices.

faces property

faces: ndarray

Return the triangle face indices of the mesh in raw indices.

as_trimesh property

as_trimesh: Trimesh

Return the mesh as a trimesh.Trimesh object. Note that Trimesh works entirely in positional vertices.

as_tuple property

as_tuple: Tuple[ndarray, ndarray]

Tuple of (vertices, faces_positional) expected by many mesh-processing algorithms.

edges property

edges: ndarray

Return the edge indices of the mesh in raw indices. Note that for each connected vertex pair u,v, there are both edges (u,v) and (v,u).

edges_positional property

edges_positional: ndarray

Return the edge indices of the mesh in positional indices. Note that for each connected vertex pair u,v, there are both edges (u,v) and (v,u).

csgraph property

csgraph: csr_matrix

Generate a compressed sparse graph representation of the mesh as a network.

get_feature

get_feature(key: str) -> ndarray

Get a feature array from the features DataFrame.

Parameters:

  • key (str) –

    Column name of the feature to retrieve.

Returns:

  • ndarray

    Array of feature values for all vertices.

add_feature

add_feature(feature: Union[list, ndarray, dict, DataFrame], name: Optional[str] = None) -> Self

Add a new vertex feature to the layer.

Parameters:

  • feature (Union[list, ndarray, dict, DataFrame]) –

    The feature data to add. If an array or list, it should follow the vertex order.

  • name (Optional[str], default: None ) –

    The name of the feature column (required if feature is a list or np.ndarray).

Returns:

  • Self

    The updated DataLayer instance.

drop_features

drop_features(features: Union[str, list]) -> Self

Drop features from the DataFrame.

Parameters:

  • features (Union[str, list]) –

    The feature column name or list of names to drop.

Returns:

  • Self

    The updated DataLayer instance.

map_features_to_layer

map_features_to_layer(features: Union[str, list], layer: str, agg: Union[str, dict] = 'mean') -> DataFrame

Map features from one layer to another.

Parameters:

  • features (Union[str, list]) –

    The features to map from the source layer.

  • layer (str) –

    The target layer to map the features to.

  • agg (Union[str, dict], default: 'mean' ) –

    The aggregation method to use when mapping the features. This can take anything pandas groupby.agg takes, as well as "majority" which will is a majority vote across the mapped indices via the stats.mode function.

Returns:

  • DataFrame

    The mapped features for the target layer. Vertices with no mapping will have NaN values.

map_index_to_layer

map_index_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False, validate: bool = False) -> ndarray

Map each vertex index from the current layer to a single index in the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source index to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

  • validate (bool, default: False ) –

    Whether to raise an error is the mapping is ambiguous, i.e. it is not clear which target index to use.

Returns:

  • ndarray

    The mapped indices in the target layer. There will be exactly one target index for each source index, no matter how many viable target indices there are. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_region_to_layer

map_region_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> ndarray

Map each vertex index from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • ndarray

    All mapped indices in the target layer. Not necessarily the same length as the source indices, because it maps a region to another region. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_index_to_layer_region

map_index_to_layer_region(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> dict

Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • dict

    A dictionary mapping each source index to a list of all mapped target indices.

map_mask_to_layer

map_mask_to_layer(layer: str, mask: Optional[ndarray] = None) -> ndarray

Map a boolean mask from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • mask (Optional[ndarray], default: None ) –

    The boolean mask to map from. If None, all vertices are used.

Returns:

  • ndarray

    The mapped boolean mask in the target layer. There may be multiple target indices for each source index, depending on the region mapping. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

apply_mask

apply_mask(mask: ndarray, as_positional: bool = False, self_only: bool = False) -> Union[Self, Cell]

Apply a mask on the current layer. Returns a new object with the masked morphsync. If the object is associated with a CellSync, a new CellSync will be created, otherwise a new object of the same class will be returned.

Properties

mask: np.ndarray The mask to apply, either in boolean, vertex index, or positional index form. as_positional: bool If providing indices, specify if they are positional indices (True) or vertex indices (False). self_only: bool If True, only apply the mask to the current object and not to any associated CellSync.

Returns:

  • masked_object Union[Self, "CellSync"]

    Either a new object of the same class or a new CellSync will be returned.

copy

copy() -> Self

Create a deep copy of the current object.

Returns:

  • Union[Self, Cell]

    A new object of the same class without the CellSync.

mask_context

mask_context(mask: ndarray) -> Generator[Self, None, None]

Context manager to temporarily apply a mask via the current layer.

Parameters:

  • mask (ndarray) –

    The mask to apply, either in boolean, vertex index, or positional index form.

Yields:

  • Self

    A new object of the same class with the mask applied.

Example

with cell.skeleton.mask_context(mask) as masked_cell: masked_path_length = masked_cell.mesh.surface_area()

get_unmapped_vertices

get_unmapped_vertices(target_layers: Optional[Union[str, List[str]]] = None) -> ndarray

Identify vertices in this layer that have no mapping to specified target layers.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

Returns:

  • ndarray

    Vertices in this layer that have null mappings to any of the target layers.

mask_out_unmapped

mask_out_unmapped(target_layers: Optional[Union[str, List[str]]] = None, self_only: bool = False) -> Union[Self, Cell]

Create a new object with unmapped vertices removed.

This function identifies vertices that have null mappings to specified target layers and creates a masked version of the object with those vertices removed.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

  • self_only (bool, default: False ) –

    If True, only apply mask to current layer. If False, apply to entire Cell. Default False.

Returns:

  • Union[Self, Cell]

    New object with unmapped vertices removed.

Examples:

>>> # Remove skeleton vertices that don't map to mesh
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh")
>>> # Remove vertices that don't map to multiple layers
>>> clean_skeleton = skeleton.mask_out_unmapped(["mesh", "annotations"])
>>> # Clean up only the current layer, not the whole cell
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh", self_only=True)
>>> # Remove vertices that don't map to ANY other layer
>>> clean_skeleton = skeleton.mask_out_unmapped()

describe

describe() -> None

Generate a compact description of the layer including vertices, features, and links.

Provides information about: - Layer name and type - Vertex count (and edges/faces for applicable layer types) - feature names - Links to other layers

Returns:

  • None

    Always returns None (prints formatted text)

loc

loc(key: Union[str, List[str], ndarray]) -> DataFrame

Passthrough to layer.nodes.loc

iloc

iloc(key: Union[int, List[int], ndarray]) -> DataFrame

Passthrough to layer.nodes.iloc

surface_area

surface_area(vertices: Optional[ndarray] = None, as_positional: bool = True, inclusive: bool = False) -> float

Calculate the surface area of the mesh, or a subset of vertices.

Parameters:

  • vertices (Optional[ndarray], default: None ) –

    Vertex indices to calculate surface area for. If None, uses entire mesh.

  • as_positional (bool, default: True ) –

    Whether the input vertices are positional indices or vertex indices. Default True.

  • inclusive (bool, default: False ) –

    Whether to include faces that are covered by any vertex (True) or only those fully covered (False). Default False.

Returns:

  • float

    The surface area of the mesh or the subset of vertices.

Key Properties for Mesh Analysis

  • faces, faces_positional: Triangle face connectivity
  • as_trimesh: Integration with trimesh library
  • surface_area(): Surface area calculations for vertex regions
  • edges: Edge connectivity derived from face topology

Usage Example

# Mesh geometry
mesh = cell.mesh
triangles = mesh.faces_positional
vertices = mesh.vertices

# Surface analysis
total_area = mesh.surface_area()
vertex_areas = mesh.surface_area([1, 2, 3])

# Mesh connectivity
edge_graph = mesh.csgraph  # Graph from mesh edges
mesh_obj = mesh.as_trimesh  # trimesh.Trimesh object

# Export formats
vertices_array, faces_array = mesh.as_tuple

PointCloudLayer

Lightweight point-based annotations and sparse markers.

PointCloudLayer

PointCloudLayer(name: str, vertices: Union[ndarray, DataFrame], spatial_columns: Optional[list] = None, *, vertex_index: Optional[Union[str, ndarray]] = None, features: Optional[Union[dict, DataFrame]] = None, morphsync: MorphSync = None, linkage: Optional[dict] = None, existing: bool = False)

Bases: PointMixin

Methods:

  • get_feature

    Get a feature array from the features DataFrame.

  • add_feature

    Add a new vertex feature to the layer.

  • drop_features

    Drop features from the DataFrame.

  • map_features_to_layer

    Map features from one layer to another.

  • map_index_to_layer

    Map each vertex index from the current layer to a single index in the specified layer.

  • map_region_to_layer

    Map each vertex index from the current layer to the specified layer.

  • map_index_to_layer_region

    Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

  • map_mask_to_layer

    Map a boolean mask from the current layer to the specified layer.

  • apply_mask

    Apply a mask on the current layer. Returns a new object with the masked morphsync.

  • copy

    Create a deep copy of the current object.

  • mask_context

    Context manager to temporarily apply a mask via the current layer.

  • get_unmapped_vertices

    Identify vertices in this layer that have no mapping to specified target layers.

  • mask_out_unmapped

    Create a new object with unmapped vertices removed.

  • describe

    Generate a compact description of the layer including vertices, features, and links.

  • loc

    Passthrough to layer.nodes.loc

  • iloc

    Passthrough to layer.nodes.iloc

  • distance_to_root

    Get the distance to the root for each vertex in the point cloud along the skeleton, or for a subset of vertices.

  • distance_between

    Get the distance between each pair of vertices in the point cloud along the skeleton.

  • filter

    Filter point cloud by a mask on a specific layer.

Attributes:

  • name (str) –

    Layer name.

  • layer (Facet) –

    Get the morphsync layer associated with the data layer.

  • vertices (ndarray) –

    Get the Nx3 vertex positions of the data layer.

  • vertex_df (DataFrame) –

    Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

  • vertex_index (ndarray) –

    Get vertex indices as a numpy array.

  • vertex_index_map (dict) –

    Get a dictionary mapping vertex indices to their positional indices.

  • nodes (DataFrame) –

    Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

  • spatial_columns (list) –

    Get the list of column names associated with the x, y, and z positions.

  • feature_names (list) –

    Get the list of column names associated with features (non-spatial columns).

  • features (DataFrame) –

    Get the features DataFrame.

  • n_vertices (int) –

    Get the number of vertices in the data layer.

  • bbox (array) –

    Get the axis-aligned bounding box (min, max) of the data layer's vertices.

  • kdtree (KDTree) –

    Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

  • layer_name (str) –

    Get the name of the layer.

name property

name: str

Layer name.

layer property

layer: Facet

Get the morphsync layer associated with the data layer.

vertices property

vertices: ndarray

Get the Nx3 vertex positions of the data layer.

vertex_df property

vertex_df: DataFrame

Get the Nx3 vertex positions of the data layer as an indexed DataFrame.

vertex_index property

vertex_index: ndarray

Get vertex indices as a numpy array.

vertex_index_map property

vertex_index_map: dict

Get a dictionary mapping vertex indices to their positional indices.

nodes property

nodes: DataFrame

Get the complete DataFrame of vertices and all associated data, including both spatial columns and features.

spatial_columns property

spatial_columns: list

Get the list of column names associated with the x, y, and z positions.

feature_names property

feature_names: list

Get the list of column names associated with features (non-spatial columns).

features property

features: DataFrame

Get the features DataFrame.

n_vertices property

n_vertices: int

Get the number of vertices in the data layer.

bbox property

bbox: array

Get the axis-aligned bounding box (min, max) of the data layer's vertices.

kdtree property

kdtree: KDTree

Get the KDTree for the data layer's vertices for efficient spatial queries. See scipy.spatial.KDTree for documentation.

layer_name property

layer_name: str

Get the name of the layer.

get_feature

get_feature(key: str) -> ndarray

Get a feature array from the features DataFrame.

Parameters:

  • key (str) –

    Column name of the feature to retrieve.

Returns:

  • ndarray

    Array of feature values for all vertices.

add_feature

add_feature(feature: Union[list, ndarray, dict, DataFrame], name: Optional[str] = None) -> Self

Add a new vertex feature to the layer.

Parameters:

  • feature (Union[list, ndarray, dict, DataFrame]) –

    The feature data to add. If an array or list, it should follow the vertex order.

  • name (Optional[str], default: None ) –

    The name of the feature column (required if feature is a list or np.ndarray).

Returns:

  • Self

    The updated DataLayer instance.

drop_features

drop_features(features: Union[str, list]) -> Self

Drop features from the DataFrame.

Parameters:

  • features (Union[str, list]) –

    The feature column name or list of names to drop.

Returns:

  • Self

    The updated DataLayer instance.

map_features_to_layer

map_features_to_layer(features: Union[str, list], layer: str, agg: Union[str, dict] = 'mean') -> DataFrame

Map features from one layer to another.

Parameters:

  • features (Union[str, list]) –

    The features to map from the source layer.

  • layer (str) –

    The target layer to map the features to.

  • agg (Union[str, dict], default: 'mean' ) –

    The aggregation method to use when mapping the features. This can take anything pandas groupby.agg takes, as well as "majority" which will is a majority vote across the mapped indices via the stats.mode function.

Returns:

  • DataFrame

    The mapped features for the target layer. Vertices with no mapping will have NaN values.

map_index_to_layer

map_index_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False, validate: bool = False) -> ndarray

Map each vertex index from the current layer to a single index in the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source index to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

  • validate (bool, default: False ) –

    Whether to raise an error is the mapping is ambiguous, i.e. it is not clear which target index to use.

Returns:

  • ndarray

    The mapped indices in the target layer. There will be exactly one target index for each source index, no matter how many viable target indices there are. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_region_to_layer

map_region_to_layer(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> ndarray

Map each vertex index from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • ndarray

    All mapped indices in the target layer. Not necessarily the same length as the source indices, because it maps a region to another region. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

map_index_to_layer_region

map_index_to_layer_region(layer: str, source_index: Optional[ndarray] = None, as_positional: bool = False) -> dict

Map each vertex index from the current layer to a list of all appropriate vertices in the target layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • source_index (Optional[ndarray], default: None ) –

    The source indices to map from. If None, all vertices are used. Can also be a boolean array.

  • as_positional (bool, default: False ) –

    Whether to treat source_index and mapped index as positional (i_th element of the array) or as a dataframe index.

Returns:

  • dict

    A dictionary mapping each source index to a list of all mapped target indices.

map_mask_to_layer

map_mask_to_layer(layer: str, mask: Optional[ndarray] = None) -> ndarray

Map a boolean mask from the current layer to the specified layer.

Parameters:

  • layer (str) –

    The target layer to map the index to.

  • mask (Optional[ndarray], default: None ) –

    The boolean mask to map from. If None, all vertices are used.

Returns:

  • ndarray

    The mapped boolean mask in the target layer. There may be multiple target indices for each source index, depending on the region mapping. If as_positional is True, the mapping is based on the position of the vertices not the dataframe index.

apply_mask

apply_mask(mask: ndarray, as_positional: bool = False, self_only: bool = False) -> Union[Self, Cell]

Apply a mask on the current layer. Returns a new object with the masked morphsync. If the object is associated with a CellSync, a new CellSync will be created, otherwise a new object of the same class will be returned.

Properties

mask: np.ndarray The mask to apply, either in boolean, vertex index, or positional index form. as_positional: bool If providing indices, specify if they are positional indices (True) or vertex indices (False). self_only: bool If True, only apply the mask to the current object and not to any associated CellSync.

Returns:

  • masked_object Union[Self, "CellSync"]

    Either a new object of the same class or a new CellSync will be returned.

copy

copy() -> Self

Create a deep copy of the current object.

Returns:

  • Union[Self, Cell]

    A new object of the same class without the CellSync.

mask_context

mask_context(mask: ndarray) -> Generator[Self, None, None]

Context manager to temporarily apply a mask via the current layer.

Parameters:

  • mask (ndarray) –

    The mask to apply, either in boolean, vertex index, or positional index form.

Yields:

  • Self

    A new object of the same class with the mask applied.

Example

with cell.skeleton.mask_context(mask) as masked_cell: masked_path_length = masked_cell.mesh.surface_area()

get_unmapped_vertices

get_unmapped_vertices(target_layers: Optional[Union[str, List[str]]] = None) -> ndarray

Identify vertices in this layer that have no mapping to specified target layers.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

Returns:

  • ndarray

    Vertices in this layer that have null mappings to any of the target layers.

mask_out_unmapped

mask_out_unmapped(target_layers: Optional[Union[str, List[str]]] = None, self_only: bool = False) -> Union[Self, Cell]

Create a new object with unmapped vertices removed.

This function identifies vertices that have null mappings to specified target layers and creates a masked version of the object with those vertices removed.

Parameters:

  • target_layers (Optional[Union[str, List[str]]], default: None ) –

    Target layer name(s) to check mappings against. If None, checks all other layers in the morphsync object except the current layer.

  • self_only (bool, default: False ) –

    If True, only apply mask to current layer. If False, apply to entire Cell. Default False.

Returns:

  • Union[Self, Cell]

    New object with unmapped vertices removed.

Examples:

>>> # Remove skeleton vertices that don't map to mesh
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh")
>>> # Remove vertices that don't map to multiple layers
>>> clean_skeleton = skeleton.mask_out_unmapped(["mesh", "annotations"])
>>> # Clean up only the current layer, not the whole cell
>>> clean_skeleton = skeleton.mask_out_unmapped("mesh", self_only=True)
>>> # Remove vertices that don't map to ANY other layer
>>> clean_skeleton = skeleton.mask_out_unmapped()

describe

describe() -> None

Generate a compact description of the layer including vertices, features, and links.

Provides information about: - Layer name and type - Vertex count (and edges/faces for applicable layer types) - feature names - Links to other layers

Returns:

  • None

    Always returns None (prints formatted text)

loc

loc(key: Union[str, List[str], ndarray]) -> DataFrame

Passthrough to layer.nodes.loc

iloc

iloc(key: Union[int, List[int], ndarray]) -> DataFrame

Passthrough to layer.nodes.iloc

distance_to_root

distance_to_root(vertices: Optional[ndarray] = None, as_positional: bool = False) -> ndarray

Get the distance to the root for each vertex in the point cloud along the skeleton, or for a subset of vertices.

Parameters:

  • vertices (Optional[ndarray], default: None ) –

    The vertices to get the distance to the root for. If None, all vertices are used.

  • as_positional (bool, default: False ) –

    If True, the vertices are treated as positional indices. If False, they are treated as vertex features. By default False.

Returns:

  • ndarray

    The distance to the root for each vertex.

distance_between

distance_between(vertices: Optional[ndarray] = None, as_positional: bool = False, via: Literal['skeleton', 'graph', 'mesh'] = 'skeleton', limit: Optional[float] = None) -> ndarray

Get the distance between each pair of vertices in the point cloud along the skeleton.

Parameters:

  • vertices (Optional[ndarray], default: None ) –

    The vertices to get the distance between. If None, all vertices are used.

  • as_positional (bool, default: False ) –

    If True, the vertices are treated as positional indices. If False, they are treated as vertex features. By default False.

  • via (Literal['skeleton', 'graph', 'mesh'], default: 'skeleton' ) –

    The method to use for calculating distances. Can be "skeleton", "graph", or "mesh". Default is "skeleton".

  • limit (Optional[float], default: None ) –

    The maximum distance to consider when calculating distances. If None, no limit is applied.

Returns:

  • ndarray

    The distance between each pair of vertices.

filter

filter(mask: ndarray, layer: str) -> DataFrame

Filter point cloud by a mask on a specific layer.

Parameters:

  • mask (ndarray) –

    The mask to filter by. Either an explicit mask array or a boolean mask.

  • layer (str) –

    The layer that the mask is associated with.

Returns:

  • DataFrame

    The dataframe filtered by the mask.

Usage Example

# Point annotations
synapses = cell.annotations["pre_syn"]
locations = synapses.vertices
synapse_count = len(synapses)

# Link to other layers via mapping
mapped_skeleton_ids = synapses.map_index_to_layer("skeleton")
distances_to_root = synapses.distance_to_root()

# Filter annotations
active_synapses = synapses.filter(activity_mask, layer="skeleton")

Common Layer Operations

All layer types share a consistent interface for common operations:

Spatial Operations

# All layers support transformations
layer.transform(transform_matrix, inplace=False)
layer.transform(custom_function, inplace=True)

# Bounding box calculation
bbox_min, bbox_max = layer.bbox

# Spatial indexing (available for all layers with vertices)
tree = layer.kdtree

Data Management

# feature management
layer.add_feature(values, name="new_feature")
feature_data = layer.get_feature("existing_feature") 
all_features = layer.features  # DataFrame with all features

# Masking and filtering
masked_layer = layer.apply_mask(boolean_mask)
subset = layer.apply_mask([1, 5, 10, 15])  # Vertex IDs

# Copy operations
layer_copy = layer.copy()

Index Management

# Flexible indexing support
vertex_ids = layer.vertex_index        # DataFrame indices  
n_vertices = layer.n_vertices           # Total count
vertices_array = layer.vertices         # (N, 3) coordinate array

# Convert between index types
positional_idx = layer._convert_to_positional([100, 200, 300])
vertex_ids = layer.vertex_index[positional_idx]

Cross-Layer Mapping

# Map data between layers
target_values = layer.map_index_to_layer("target_layer_name")
region_mapping = layer.map_region_to_layer("target_layer_name")

# feature propagation with aggregation
aggregated = layer.map_features_to_layer(
    features=["synapse_count", "activity"],
    layer="skeleton", 
    agg={"synapse_count": "sum", "activity": "mean"}
)

# Boolean mask mapping  
skeleton_mask = graph_layer.map_mask_to_layer("skeleton", boolean_mask)

Advanced Usage Patterns

Multi-Layer Analysis Pipeline

# Chain operations across layers
cell = ossify.load_cell("neuron.osy")

# 1. Filter skeleton by compartment  
axon_mask = cell.skeleton.get_feature("is_axon")
axon_cell = cell.apply_mask("skeleton", axon_mask)

# 2. Map synapses to axon skeleton
with axon_cell.mask_context("skeleton", axon_mask) as masked:
    synapse_mapping = masked.annotations["pre_syn"].map_index_to_layer("skeleton")

# 3. Analyze synapse density along axon
density = masked.skeleton.map_annotations_to_feature(
    "pre_syn", 
    distance_threshold=500,
    agg="count"
)

Custom Layer Properties

class CustomAnalysis:
    def __init__(self, skeleton):
        self.skeleton = skeleton

    @property  
    def branch_angles(self):
        \"\"\"Calculate angles at branch points\"\"\"
        angles = []
        for bp in self.skeleton.branch_points:
            children = self.skeleton.child_vertices([bp])
            # Calculate angles between child branches
            # ... angle calculation logic
        return np.array(angles)

    @property
    def tortuosity(self):
        \"\"\"Path tortuosity for each segment\"\"\"
        tortuosities = []
        for segment in self.skeleton.segments:
            path_length = self.skeleton.cable_length(segment) 
            euclidean = np.linalg.norm(
                self.skeleton.vertices[segment[-1]] - 
                self.skeleton.vertices[segment[0]]
            )
            tortuosities.append(path_length / euclidean)
        return np.array(tortuosities)

# Usage
analysis = CustomAnalysis(cell.skeleton)
angles = analysis.branch_angles
tortuous_segments = analysis.tortuosity > 1.5

Layer Design Principles

Consistent Interface: All layers implement the same core methods for transformations, masking, and feature management.

Efficient Storage: Layers use appropriate data structures (sparse matrices, KDTrees) optimized for their specific use cases.

Cross-Layer Integration: The Link system enables seamless data flow between different geometric representations.

Performance Optimization

  • Spatial Queries: Use kdtree property for fast nearest neighbor searches
  • Graph Operations: Leverage csgraph for efficient pathfinding and connectivity analysis
  • Memory Management: Use mask_context() for temporary operations without copying data
  • Batch Operations: Process multiple vertices/faces together rather than iterating