Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace iter_* methods by properties in core objects and improve iter_segments #1054

Merged
merged 5 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
Version 4.0.0
-------------

- Replace ``iter_*`` methods by properties in core objects and improve ``iter_segments``. (#1054)
- NeuriteType extended to allow mixed type declarations as tuple of ints. (#1071)
- All features return built-in types (#1064)
- Morphology class also allows mutable morphio objects to be passed explicitly. (#1049)
Expand Down
21 changes: 21 additions & 0 deletions doc/source/migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ The following modules have been deprecated:
- ``neurom/check/neuron_checks.py`` (use ``neurom/check/morphology_checks.py``)
- ``neurom/viewer.py`` (use ``from neurom.view import plot_[morph|morph3d|dendrogram]``)

New and deprecated methods in core classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``neurom.core.morphology.Neurite.iter_sections()`` has been deprecated. It is now possible to
access lower scale elements of any core class using properties:

- ``neurom.core.morphology.Section.segments``
- ``neurom.core.morphology.Section.points``
- ``neurom.core.morphology.Neurite.sections``
- ``neurom.core.morphology.Neurite.segments``
- ``neurom.core.morphology.Neurite.points``
- ``neurom.core.morphology.Morphology.neurites``
- ``neurom.core.morphology.Morphology.sections``
- ``neurom.core.morphology.Morphology.segments``
- ``neurom.core.morphology.Morphology.points``

Note that these properties return all elements in a list. It is possible to use
``neurom.core.morphology.iter_neurites()``, ``neurom.core.morphology.iter_sections()``,
``neurom.core.morphology.iter_segments()`` and ``neurom.core.morphology.iter_points()`` to get a
generator or to filter the elements.

Breaking changes in Morphology class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion examples/radius_of_gyration.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def main():
print(
[
(
sum(len(s.points) - 1 for s in nrte.iter_sections()),
sum(len(s.points) - 1 for s in nrte.sections),
radius_of_gyration(nrte),
nrte.type,
)
Expand Down
5 changes: 3 additions & 2 deletions neurom/check/morphtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

from neurom import morphmath as mm
from neurom.core.dataformat import COLS
from neurom.core.morphology import iter_sections
from neurom.morphmath import principal_direction_extent


Expand All @@ -47,7 +48,7 @@ def is_monotonic(neurite, tol):
Returns:
True if neurite monotonic
"""
for node in neurite.iter_sections():
for node in iter_sections(neurite):
# check that points in section satisfy monotonicity
sec = node.points
for point_id in range(len(sec) - 1):
Expand Down Expand Up @@ -171,7 +172,7 @@ def is_inside_cylinder(seg1, seg2):
return not is_in_the_same_verse(seg1, seg2) and is_seg1_overlapping_with_seg2(seg1, seg2)

# filter out single segment sections
section_itr = (sec for sec in neurite.iter_sections() if sec.points.shape[0] > 2)
section_itr = (sec for sec in iter_sections(neurite) if sec.points.shape[0] > 2)
for sec in section_itr:
# group each section's points intro triplets
segment_pairs = list(filter(is_not_zero_seg, pair(sec.points)))
Expand Down
50 changes: 32 additions & 18 deletions neurom/core/morphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ def __hash__(self):
"""Hash of its id."""
return self.id

@property
def segments(self):
"""The array of all segments of the neurite."""
return list(iter_segments(self))

@property
def points(self):
"""Returns the section list of points the NeuroM way (points + radius)."""
Expand Down Expand Up @@ -325,7 +330,11 @@ def iter_sections(


def iter_segments(
obj, neurite_filter=None, neurite_order=NeuriteIter.FileOrder, section_filter=None
obj,
neurite_filter=None,
neurite_order=NeuriteIter.FileOrder,
section_filter=None,
section_iterator=Section.ipreorder,
):
"""Return an iterator to the segments in a collection of neurites.

Expand All @@ -336,6 +345,12 @@ def iter_segments(
- NeuriteIter.FileOrder: order of appearance in the file
- NeuriteIter.NRN: NRN simulator order: soma -> axon -> basal -> apical
section_filter: optional section level filter
section_iterator: section iteration order within a given neurite. Must be one of:
Section.ipreorder: Depth-first pre-order iteration of tree nodes
Section.ipostorder: Depth-first post-order iteration of tree nodes
Section.iupstream: Iterate from a tree node to the root nodes
Section.ibifurcation_point: Iterator to bifurcation points
Section.ileaf: Iterator to all leaves of a tree

Note:
This is a convenience function provided for generic access to
Expand All @@ -347,6 +362,7 @@ def iter_segments(
if isinstance(obj, Section)
else iter_sections(
obj,
iterator_type=section_iterator,
neurite_filter=neurite_filter,
neurite_order=neurite_order,
section_filter=section_filter,
Expand Down Expand Up @@ -443,6 +459,16 @@ def subtree_types(self):

return subtree_types

@property
def sections(self):
"""The array of all sections."""
return list(iter_sections(self))

@property
def segments(self):
"""The array of all segments of the neurite."""
return list(iter_segments(self))

@property
def points(self):
"""Array with all the points in this neurite.
Expand Down Expand Up @@ -492,23 +518,6 @@ def is_heterogeneous(self) -> bool:
"""Returns true if the neurite consists of more that one section types."""
return self.morphio_root_node.is_heterogeneous()

def iter_sections(self, order=Section.ipreorder, neurite_order=NeuriteIter.FileOrder):
eleftherioszisis marked this conversation as resolved.
Show resolved Hide resolved
"""Iteration over section nodes.

Arguments:
order: section iteration order within a given neurite. Must be one of:
Section.ipreorder: Depth-first pre-order iteration of tree nodes
Section.ipostorder: Depth-first post-order iteration of tree nodes
Section.iupstream: Iterate from a tree node to the root nodes
Section.ibifurcation_point: Iterator to bifurcation points
Section.ileaf: Iterator to all leaves of a tree

neurite_order: order upon which neurites should be iterated. Values:
- NeuriteIter.FileOrder: order of appearance in the file
- NeuriteIter.NRN: NRN simulator order: soma -> axon -> basal -> apical
"""
return iter_sections(self, iterator_type=order, neurite_order=neurite_order)

def __eq__(self, other):
"""If root node ids and types are equal."""
return (
Expand Down Expand Up @@ -572,6 +581,11 @@ def sections(self):
"""The array of all sections, excluding the soma."""
return list(iter_sections(self))

@property
def segments(self):
"""The array of all segments of the sections."""
return list(iter_segments(self))

@property
def points(self):
"""Returns the list of points."""
Expand Down
6 changes: 1 addition & 5 deletions neurom/features/morphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,7 @@ def max_radial_distance(morph, origin=None, neurite_type=NeuriteType.all):

@feature(shape=(...,))
def section_radial_distances(morph, origin=None, neurite_type=NeuriteType.all):
"""Section radial distances.

The iterator_type can be used to select only terminal sections (ileaf)
or only bifurcations (ibifurcation_point).
"""
"""Section radial distances."""
origin = morph.soma.center if origin is None else origin

return list(
Expand Down
Loading
Loading