Skip to content

graph_utils

Match vertices of MeshNeuron to nodes of TreeNeuron.

PARAMETER DESCRIPTION
mesh
    MeshNeuron to match.

TYPE: MeshNeuron

skeleton
    Skeleton to match.

TYPE: TreeNeuron

RETURNS DESCRIPTION
np.ndarray

Array of skeleton node IDs for each vertex in the mesh.

Source code in navis/graph/graph_utils.py
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
def match_mesh_skeleton(mesh, skeleton):
    """Match vertices of MeshNeuron to nodes of TreeNeuron.

    Parameters
    ----------
    mesh :      MeshNeuron
                MeshNeuron to match.
    skeleton :  TreeNeuron
                Skeleton to match.

    Returns
    -------
    np.ndarray
                Array of skeleton node IDs for each vertex in the mesh.

    """
    if not isinstance(mesh, core.MeshNeuron):
        raise TypeError(f"Expected MeshNeuron, got {type(mesh)}")

    if not isinstance(skeleton, core.TreeNeuron):
        raise TypeError(f"Expected TreeNeuron, got {type(skeleton)}")

    # Generate a KDTree for the skeleton
    tree = graph.neuron2KDTree(skeleton)

    # Find closest node for each vertex
    dist, ix = tree.query(mesh.vertices, k=1)

    return skeleton.nodes.node_id.values[ix]

A skeleton's child -> parent edges as 0-based node indices.

The fastcore graph primitives all work in index space (0 .. n_nodes - 1) off a plain edge list, whereas navis works in node IDs - so anything wiring one to the other needs this.

RETURNS DESCRIPTION
edges

Roots have no parent and simply contribute no edge.

TYPE: (E, 2) int64 array

node_ids

The node ID for each index, i.e. the inverse mapping.

TYPE: (N, ) array

Source code in navis/graph/graph_utils.py
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
def skeleton_edges(x: "core.TreeNeuron"):
    """A skeleton's child -> parent edges as 0-based node *indices*.

    The fastcore graph primitives all work in index space (`0 .. n_nodes - 1`)
    off a plain edge list, whereas navis works in node IDs - so anything wiring
    one to the other needs this.

    Returns
    -------
    edges :     (E, 2) int64 array
                Roots have no parent and simply contribute no edge.
    node_ids :  (N, ) array
                The node ID for each index, i.e. the inverse mapping.

    """
    node_ids = x.nodes.node_id.values
    parent_ids = x.nodes.parent_id.values
    n_nodes = len(node_ids)

    if not n_nodes:
        return np.zeros((0, 2), dtype=np.int64), node_ids

    id2ix = pd.Series(np.arange(n_nodes), index=node_ids)
    par_ix = id2ix.reindex(parent_ids).values
    has_parent = ~np.isnan(par_ix)

    edges = np.stack(
        [np.arange(n_nodes)[has_parent], par_ix[has_parent].astype(np.int64)], axis=1
    )
    return edges, node_ids