Skip to content

Commit

Permalink
Some proposals
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien-berchet committed Apr 25, 2024
1 parent eeaefcb commit eebd2f0
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 33 deletions.
12 changes: 9 additions & 3 deletions neurom/core/morphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ def __repr__(self):
class Morphology:
"""Class representing a simple morphology."""

def __init__(self, morphio_morph, name=None, process_subtrees=False):
def __init__(self, morphio_morph, name=None, *, process_subtrees=False):
"""Morphology constructor.
Args:
Expand All @@ -563,9 +563,15 @@ def to_morphio(self):
"""Returns the morphio morphology object."""
return self._morphio_morph

def copy(self):
def copy(self, mutable=None):
"""Returns a shallow copy of the morphio morphology object."""
return Morphology(self.to_morphio(), name=self.name, process_subtrees=self.process_subtrees)
if mutable is False:
morph = morphio.Morphology(self.to_morphio())
elif mutable is True:
morph = morphio.mut.Morphology(self.to_morphio())
else:
morph = self.to_morphio().__class__(self.to_morphio())
return Morphology(morph, name=self.name, process_subtrees=self.process_subtrees)

@property
def neurites(self):
Expand Down
18 changes: 16 additions & 2 deletions neurom/core/population.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Population:
"""

def __init__(
self, files, name='Population', ignored_exceptions=(), cache=False, process_subtrees=False
self, files, name='Population', ignored_exceptions=(), cache=False, mutable=None, process_subtrees=False
):
"""Construct a morphology population.
Expand All @@ -67,6 +67,9 @@ def __init__(
will be loaded everytime it is accessed within the population. Which is good when
population is big. If true then all morphs will be loaded upon the construction
and kept in memory.
mutable (bool): Can force mutability/immutability by setting it to True or False, while
None uses the default behavior.
process_subtrees (bool): enable mixed tree processing if set to True
Notes:
symlinks in paths are not resolved.
Expand All @@ -76,6 +79,7 @@ def __init__(

self._files = _resolve_if_morphology_paths(files)

self._mutable = mutable
self._process_subtrees = process_subtrees

if cache:
Expand All @@ -85,6 +89,16 @@ def _reset_cache(self):
"""Reset the internal cache."""
self._files = [self._load_file(f) for f in self._files if f is not None]

@property
def mutable(self):
"""The mutability status of the morphologies."""
return self._mutable

@mutable.setter
def mutable(self, value):
self._mutable = value
self._reset_cache()

@property
def process_subtrees(self):
"""Enable mixed tree processing if set to True."""
Expand Down Expand Up @@ -116,7 +130,7 @@ def _load_file(self, f):
new_morph.process_subtrees = self.process_subtrees
return new_morph
try:
return neurom.load_morphology(f, process_subtrees=self.process_subtrees)
return neurom.load_morphology(f, mutable=self.mutable, process_subtrees=self.process_subtrees)
except (NeuroMError, MorphioError) as e:
if isinstance(e, self._ignored_exceptions):
L.info('Ignoring exception "%s" for file %s', e, f.name)
Expand Down
45 changes: 20 additions & 25 deletions neurom/core/soma.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,24 @@ def __str__(self):
)


def soma_center(soma):
"""Calculate soma center."""
def get_morphio_soma(obj):
"""Get the MorphIO soma from the given object."""
if hasattr(obj, "soma"):
input_soma = obj.soma
else:
input_soma = obj

if hasattr(soma, "to_morphio"):
morphio_soma = soma.to_morphio()
if hasattr(input_soma, "to_morphio"):
morphio_soma = input_soma.to_morphio()
else:
morphio_soma = soma
morphio_soma = input_soma

return morphio_soma


def soma_center(soma):
"""Calculate soma center."""
morphio_soma = get_morphio_soma(soma)

def _first_point(morphio_soma):
"""Return the first point."""
Expand All @@ -236,11 +247,7 @@ def _centroid(soma):

def soma_radius(soma):
"""Calculate soma radius."""

if hasattr(soma, "to_morphio"):
morphio_soma = soma.to_morphio()
else:
morphio_soma = soma
morphio_soma = get_morphio_soma(soma)

def _soma_single_point_radius(morphio_soma):
"""Return first radius."""
Expand Down Expand Up @@ -280,11 +287,7 @@ def _soma_simple_contour_radius(morphio_soma):
return soma_algo(morphio_soma)

def soma_area(soma):

if hasattr(soma, "to_morphio"):
morphio_soma = soma.to_morphio()
else:
morphio_soma = soma
morphio_soma = get_morphio_soma(soma)

def _soma_single_point_area(morphio_soma):
return 4. * math.pi * soma_radius(morphio_soma)**2
Expand Down Expand Up @@ -323,11 +326,7 @@ def _soma_three_point_cylinders_area(morphio_soma):

def soma_volume(soma):
"""Calculate soma volume."""

if hasattr(soma, "to_morphio"):
morphio_soma = soma.to_morphio()
else:
morphio_soma = soma
morphio_soma = get_morphio_soma(soma)

def _soma_single_point_volume(morphio_soma):
return 4.0 / 3 * math.pi * soma_radius(morphio_soma)**3
Expand Down Expand Up @@ -365,11 +364,7 @@ def _soma_three_point_cylinders_volume(morphio_soma):

def soma_overlaps(soma, points, exclude_boundary=False):
"""Check if soma overlaps with points."""

if hasattr(soma, "to_morphio"):
morphio_soma = soma.to_morphio()
else:
morphio_soma = soma
morphio_soma = get_morphio_soma(soma)

def _soma_undefined_overlaps(morphio_soma, points, exclude_boundary):
points = np.atleast_2d(np.asarray(points, dtype=np.float64))
Expand Down
10 changes: 7 additions & 3 deletions neurom/io/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def _get_file(stream, extension):
return temp_file


def load_morphology(morph, reader=None, mutable=None, process_subtrees=False):
def load_morphology(morph, reader=None, *, mutable=None, process_subtrees=False):
"""Build section trees from a morphology or a h5, swc or asc file.
Args:
Expand All @@ -137,6 +137,7 @@ def load_morphology(morph, reader=None, mutable=None, process_subtrees=False):
morphology is loaded, then it will be immutable by default.
reader (str): Optional, must be provided if morphology is a stream to
specify the file format (asc, swc, h5)
process_subtrees (bool): enable mixed tree processing if set to True
Returns:
A Morphology object
Expand Down Expand Up @@ -181,7 +182,7 @@ def load_morphology(morph, reader=None, mutable=None, process_subtrees=False):


def load_morphologies(
morphs, name=None, ignored_exceptions=(), cache=False, process_subtrees=False
morphs, name=None, ignored_exceptions=(), cache=False, mutable=None, process_subtrees=False
):
"""Create a population object.
Expand All @@ -195,6 +196,9 @@ def load_morphologies(
ignored_exceptions (tuple): NeuroM and MorphIO exceptions that you want to ignore when
loading morphologies
cache (bool): whether to cache the loaded morphologies in memory
mutable (bool): Can force mutability/immutability by setting it to True or False, while
None uses the default behavior.
process_subtrees (bool): enable mixed tree processing if set to True
Returns:
Population: population object
Expand All @@ -205,4 +209,4 @@ def load_morphologies(
else:
files = morphs
name = name or 'Population'
return Population(files, name, ignored_exceptions, cache, process_subtrees=process_subtrees)
return Population(files, name, ignored_exceptions, cache, mutable=mutable, process_subtrees=process_subtrees)

0 comments on commit eebd2f0

Please sign in to comment.