Skip to content
31 changes: 22 additions & 9 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ learn more!
``TreeNeurons``, ``MeshNeurons``, ``VoxelNeurons`` and ``Dotprops`` are neuron
classes. ``NeuronLists`` are containers thereof.

| Class | Description |
|------|------|
| [`navis.TreeNeuron`][] | Skeleton representation of a neuron. |
| [`navis.MeshNeuron`][] | Meshes with vertices and faces. |
| [`navis.VoxelNeuron`][] | 3D images (e.g. from confocal stacks). |
| [`navis.Dotprops`][] | Point cloud + vector representations, used for NBLAST. |
| [`navis.NeuronList`][] | Containers for neurons. |
| Class | Description |
|-------------------------|---------------------------------------------------------|
| [`navis.TreeNeuron`][] | Skeleton representation of a neuron. |
| [`navis.MeshNeuron`][] | Meshes with vertices and faces. |
| [`navis.VoxelNeuron`][] | 3D images (e.g. from confocal stacks). |
| [`navis.Dotprops`][] | Point cloud + vector representations, used for NBLAST. |
| [`navis.NeuronList`][] | Containers for neurons. |

### General Neuron methods

Expand Down Expand Up @@ -89,6 +89,7 @@ to all neurons:
| `Neuron.type` | {{ autosummary("navis.BaseNeuron.type") }} |
| `Neuron.soma` | {{ autosummary("navis.BaseNeuron.soma") }} |
| `Neuron.bbox` | {{ autosummary("navis.BaseNeuron.bbox") }} |
| `Neuron.is_masked` | {{ autosummary("navis.BaseNeuron.is_masked") }} |

!!! note

Expand Down Expand Up @@ -119,6 +120,8 @@ this neuron type. Note that most of them are simply short-hands for the other
| [`TreeNeuron.reroot()`][navis.TreeNeuron.reroot] | {{ autosummary("navis.TreeNeuron.reroot") }} |
| [`TreeNeuron.resample()`][navis.TreeNeuron.resample] | {{ autosummary("navis.TreeNeuron.resample") }} |
| [`TreeNeuron.snap()`][navis.TreeNeuron.snap] | {{ autosummary("navis.TreeNeuron.snap") }} |
| [`TreeNeuron.mask()`][navis.TreeNeuron.mask] | {{ autosummary("navis.TreeNeuron.mask") }} |
| [`TreeNeuron.unmask()`][navis.TreeNeuron.unmask] | {{ autosummary("navis.TreeNeuron.unmask") }} |

In addition, a [`navis.TreeNeuron`][] has a range of different properties:

Expand Down Expand Up @@ -146,7 +149,6 @@ In addition, a [`navis.TreeNeuron`][] has a range of different properties:
| [`TreeNeuron.vertices`][navis.TreeNeuron.vertices] | {{ autosummary("navis.TreeNeuron.vertices") }} |
| [`TreeNeuron.volume`][navis.TreeNeuron.volume] | {{ autosummary("navis.TreeNeuron.volume") }} |


#### Skeleton utility functions

| Function | Description |
Expand All @@ -158,7 +160,6 @@ In addition, a [`navis.TreeNeuron`][] has a range of different properties:
| [`navis.graph.skeleton_adjacency_matrix()`][navis.graph.skeleton_adjacency_matrix] | {{ autosummary("navis.graph.skeleton_adjacency_matrix") }} |



### Mesh neurons

Properties specific to [`navis.MeshNeuron`][]:
Expand All @@ -178,6 +179,8 @@ Methods specific to [`navis.MeshNeuron`][]:
| [`MeshNeuron.skeletonize()`][navis.MeshNeuron.skeletonize] | {{ autosummary("navis.MeshNeuron.skeletonize") }} |
| [`MeshNeuron.snap()`][navis.MeshNeuron.snap] | {{ autosummary("navis.MeshNeuron.snap") }} |
| [`MeshNeuron.validate()`][navis.MeshNeuron.validate] | {{ autosummary("navis.MeshNeuron.validate") }} |
| [`MeshNeuron.mask()`][navis.MeshNeuron.mask] | {{ autosummary("navis.MeshNeuron.mask") }} |
| [`MeshNeuron.unmask()`][navis.MeshNeuron.unmask] | {{ autosummary("navis.MeshNeuron.unmask") }} |


### Voxel neurons
Expand Down Expand Up @@ -215,6 +218,8 @@ These are methods and properties specific to [Dotprops][navis.Dotprops]:
| [`Dotprops.alpha`][navis.Dotprops.alpha] | {{ autosummary("navis.Dotprops.alpha") }} |
| [`Dotprops.to_skeleton()`][navis.Dotprops.to_skeleton] | {{ autosummary("navis.Dotprops.to_skeleton") }} |
| [`Dotprops.snap()`][navis.Dotprops.snap] | {{ autosummary("navis.Dotprops.snap") }} |
| [`Dotprops.mask()`][navis.Dotprops.mask] | {{ autosummary("navis.Dotprops.mask") }} |
| [`Dotprops.unmask()`][navis.Dotprops.unmask] | {{ autosummary("navis.Dotprops.unmask") }} |

### Converting between types

Expand Down Expand Up @@ -575,6 +580,14 @@ Functions to export neurons.
| [`navis.write_precomputed()`][navis.write_precomputed] | {{ autosummary("navis.write_precomputed") }} |
| [`navis.write_parquet()`][navis.write_parquet] | {{ autosummary("navis.write_parquet") }} |

## Masking

Functions and classes for masking:

| Function/Class | Description |
|----------------|-------------|
| [`navis.NeuronMask`][navis.NeuronMask] | {{ autosummary("navis.NeuronMask") }} |

## Utility

Various utility functions.
Expand Down
15 changes: 13 additions & 2 deletions navis/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,22 @@
from .dotprop import Dotprops
from .voxel import VoxelNeuron
from .neuronlist import NeuronList
from .masking import NeuronMask
from .core_utils import make_dotprops, to_neuron_space, NeuronProcessor

from typing import Union

NeuronObject = Union[NeuronList, TreeNeuron, BaseNeuron, MeshNeuron]

__all__ = ['Volume', 'Neuron', 'BaseNeuron', 'TreeNeuron', 'MeshNeuron',
'Dotprops', 'VoxelNeuron', 'NeuronList', 'make_dotprops']
__all__ = [
"Volume",
"Neuron",
"BaseNeuron",
"TreeNeuron",
"MeshNeuron",
"NeuronMask",
"Dotprops",
"VoxelNeuron",
"NeuronList",
"make_dotprops",
]
118 changes: 117 additions & 1 deletion navis/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@


def Neuron(
x: Union[nx.DiGraph, str, pd.DataFrame, "TreeNeuron", "MeshNeuron"], **metadata
x: Union[nx.DiGraph, str, pd.DataFrame, "TreeNeuron", "MeshNeuron"], # noqa: F821
**metadata, # noqa: F821
):
"""Constructor for Neuron objects. Depending on the input, either a
`TreeNeuron` or a `MeshNeuron` is returned.
Expand Down Expand Up @@ -195,6 +196,9 @@ class BaseNeuron(UnitObject):
#: Core data table(s) used to calculate hash
CORE_DATA = []

#: Property used to calculate length of neuron
_LENGTH_DATA = None

def __init__(self, **kwargs):
# Set a random ID -> may be replaced later
self.id = uuid.uuid4()
Expand Down Expand Up @@ -303,6 +307,14 @@ def __isub__(self, other):
"""Subtraction with assignment (-=)."""
return self.__sub__(other, copy=False)

def __len__(self):
if self._LENGTH_DATA is None:
return None
# Deal with potential empty neurons
if not hasattr(self, self._LENGTH_DATA):
return 0
return len(getattr(self, self._LENGTH_DATA))

def _repr_html_(self):
frame = self.summary().to_frame()
frame.columns = [""]
Expand Down Expand Up @@ -652,8 +664,13 @@ def copy(self, deepcopy=False) -> "BaseNeuron":

return x

def view(self) -> "BaseNeuron":
"""Create a view of the neuron without copying data."""
raise NotImplementedError(f"View not implemented for neuron of type {type(self)}.")

def summary(self, add_props=None) -> pd.Series:
"""Get a summary of this neuron."""

# Do not remove the list -> otherwise we might change the original!
props = list(self.SUMMARY_PROPS)

Expand All @@ -674,6 +691,11 @@ def summary(self, add_props=None) -> pd.Series:
warnings.simplefilter("ignore")
s = pd.Series([getattr(self, at, "NA") for at in props], index=props)

# Show mask status
if self.is_masked:
if "masked" not in s.index:
s["masked"] = True

return s

def plot2d(self, **kwargs):
Expand Down Expand Up @@ -721,6 +743,100 @@ def plot3d(self, **kwargs):

return plot3d(core.NeuronList(self, make_copy=False), **kwargs)

@property
def is_masked(self):
"""Test if neuron is masked.

See Also
--------
[`navis.BaseNeuron.mask`][]
Mask neuron.
[`navis.BaseNeuron.unmask`][]
Remove mask from neuron.
[`navis.NeuronMask`][]
Context manager for masking neurons.
"""
return hasattr(self, "_masked_data")

def mask(self, mask):
"""Mask neuron.

Implementation details depend on the neuron type (see below).

See Also
--------
[`navis.TreeNeuron.mask`][]
Mask skeleton.
[`navis.MeshNeuron.mask`][]
Mask mesh.
[`navis.Dotprops.mask`][]
Mask dotprops.

"""
raise NotImplementedError(
f"Masking not implemented for neuron of type {type(self)}."
)

def unmask(self):
"""Unmask neuron.

Returns the neuron to its original state before masking.

Returns
-------
self

See Also
--------
[`Neuron.is_masked`][navis.BaseNeuron.is_masked]
Check if neuron. is masked.
[`Neuron.mask`][navis.BaseNeuron.unmask]
Mask neuron.
[`navis.NeuronMask`][]
Context manager for masking neurons.

"""
if not self.is_masked:
raise ValueError("Neuron is not masked.")

for k, v in self._masked_data.items():
if hasattr(self, k):
setattr(self, k, v)

delattr(self, "_mask")
delattr(self, "_masked_data")
self._clear_temp_attr()

return self

def apply_mask(self, inplace=False):
"""Apply mask to neuron.

This will effectively make the mask permanent.

Parameters
----------
inplace : bool
If True will apply mask in-place. If False
will return a copy and the original neuron
will remain masked.

Returns
-------
Neuron
Neuron with mask applied.

"""
if not self.is_masked:
raise ValueError("Neuron is not masked.")

n = self if inplace else self.copy()

delattr(n, "_mask")
delattr(n, "_masked_data")

return n

def map_units(
self,
units: Union[pint.Unit, str],
Expand Down
Loading
Loading