Skip to content

Commit 925ee70

Browse files
authored
Merge pull request #132 from navis-org/skeleton_delayed_graph
Proposal: delay graph generation for skeletons
2 parents bb6c34c + 8d2dd8b commit 925ee70

File tree

1 file changed

+67
-3
lines changed

1 file changed

+67
-3
lines changed

navis/graph/graph_utils.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,9 @@ def _edge_count_to_root_old(x: 'core.TreeNeuron') -> dict:
340340

341341
@utils.map_neuronlist(desc='Classifying', allow_parallel=True)
342342
@utils.lock_neuron
343-
def classify_nodes(x: 'core.NeuronObject',
344-
inplace: bool = True
345-
) -> Optional['core.NeuronObject']:
343+
def _classify_nodes_old(x: 'core.NeuronObject',
344+
inplace: bool = True
345+
) -> Optional['core.NeuronObject']:
346346
"""Classify neuron's nodes into end nodes, branches, slabs or root.
347347
348348
Adds ``'type'`` column to ``x.nodes``.
@@ -414,6 +414,70 @@ def classify_nodes(x: 'core.NeuronObject',
414414
return x
415415

416416

417+
418+
@utils.map_neuronlist(desc='Classifying', allow_parallel=True)
419+
@utils.lock_neuron
420+
def classify_nodes(x: 'core.NeuronObject',
421+
categorical=True,
422+
inplace: bool = True
423+
) -> Optional['core.NeuronObject']:
424+
"""Classify neuron's nodes into end nodes, branches, slabs or root.
425+
426+
Adds ``'type'`` column to ``x.nodes`` table.
427+
428+
Parameters
429+
----------
430+
x : TreeNeuron | NeuronList
431+
Neuron(s) whose nodes to classify.
432+
categorical : bool
433+
If True (default), will use categorical data type which takes
434+
up much less memory at a small run-time overhead.
435+
inplace : bool, optional
436+
If ``False``, nodes will be classified on a copy which is then
437+
returned leaving the original neuron unchanged.
438+
439+
Returns
440+
-------
441+
TreeNeuron/List
442+
443+
Examples
444+
--------
445+
>>> import navis
446+
>>> nl = navis.example_neurons(2)
447+
>>> _ = navis.graph.classify_nodes(nl, inplace=True)
448+
449+
"""
450+
if not inplace:
451+
x = x.copy()
452+
453+
if not isinstance(x, core.TreeNeuron):
454+
raise TypeError(f'Expected TreeNeuron(s), got "{type(x)}"')
455+
456+
# At this point x is TreeNeuron
457+
x: core.TreeNeuron
458+
459+
# Make sure there are nodes to classify
460+
if not x.nodes.empty:
461+
x.nodes['type'] = 'slab'
462+
x.nodes.loc[~x.nodes.node_id.isin(x.nodes.parent_id), 'type'] = 'end'
463+
bp = x.nodes.parent_id.value_counts()
464+
bp = bp[bp > 1].index.values
465+
x.nodes.loc[x.nodes.node_id.isin(bp), 'type'] = 'branch'
466+
x.nodes.loc[x.nodes.parent_id < 0, 'type'] = 'root'
467+
else:
468+
x.nodes['type'] = None
469+
470+
# Turn into categorical data - saves tons of memory
471+
# Note that we have to make sure all categories are set even if they
472+
# don't exist (e.g. if a neuron has no branch points)
473+
if categorical:
474+
cat_types = CategoricalDtype(categories=["end", "branch", "root", "slab"],
475+
ordered=False)
476+
x.nodes['type'] = x.nodes['type'].astype(cat_types)
477+
478+
return x
479+
480+
417481
# only this combination will return a single bool
418482
@overload
419483
def distal_to(x: 'core.TreeNeuron',

0 commit comments

Comments
 (0)