Skip to content
This repository was archived by the owner on Feb 26, 2025. It is now read-only.

Commit 0b16883

Browse files
Feat: Use MorphIO by default and fallbacks to internal loader in case of failure
1 parent 6bc9bdd commit 0b16883

4 files changed

Lines changed: 69 additions & 28 deletions

File tree

tests/test_neuron_conversion.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
from numpy import testing as npt
99

1010
from tmd.io import conversion as tested
11+
from tmd.io.io import _load_neuron_morphio
1112
from tmd.io.io import load_neuron
12-
from tmd.io.io import load_neuron_from_morphio
1313

1414
_path = os.path.dirname(os.path.abspath(__file__))
1515
DATA_PATH = os.path.join(_path, "data")
@@ -168,11 +168,11 @@ def test_neuron_building_consistency__h5():
168168
path = f"{DATA_PATH}/valid/C010398B-P2.h5"
169169

170170
neuron1 = load_neuron(path)
171-
neuron2 = load_neuron_from_morphio(path)
171+
neuron2 = _load_neuron_morphio(path)
172172

173173
_assert_neurons_equal(neuron1, neuron2)
174174

175-
neuron2 = load_neuron_from_morphio(morphio.Morphology(path))
175+
neuron2 = _load_neuron_morphio(morphio.Morphology(path))
176176

177177
_assert_neurons_equal(neuron1, neuron2)
178178

@@ -182,10 +182,10 @@ def test_neuron_building_consistency__swc():
182182
path = f"{DATA_PATH}/valid/C010398B-P2.CNG.swc"
183183

184184
neuron1 = load_neuron(path)
185-
neuron2 = load_neuron_from_morphio(path)
185+
neuron2 = _load_neuron_morphio(path)
186186

187187
_assert_neurons_equal(neuron1, neuron2)
188188

189-
neuron2 = load_neuron_from_morphio(morphio.Morphology(path))
189+
neuron2 = _load_neuron_morphio(morphio.Morphology(path))
190190

191191
_assert_neurons_equal(neuron1, neuron2)

tmd/Neuron/Neuron.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ def append_tree(self, new_tree, tree_types):
9292
"""
9393
if isinstance(new_tree, Tree.Tree):
9494

95-
if int(np.median(new_tree.t)) in tree_types.keys():
96-
neurite_type = tree_types[int(np.median(new_tree.t))]
95+
tree_type_key = int(np.median(new_tree.t))
96+
if tree_type_key in tree_types.keys():
97+
neurite_type = tree_types[tree_type_key]
9798
else:
9899
neurite_type = "undefined"
99100
getattr(self, neurite_type).append(new_tree)

tmd/io/conversion.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import numpy as np
2121

22+
from tmd.Neuron import Neuron
2223
from tmd.Soma.Soma import Soma
2324
from tmd.Tree import Tree
2425

@@ -130,3 +131,14 @@ def convert_morphio_trees(morphio_neuron):
130131
t=t[tree_beg:tree_end],
131132
p=p[tree_beg:tree_end],
132133
)
134+
135+
136+
def convert_morphio_neuron(morph, tree_types, name=""):
137+
"""Convert a MorphIO morphology into a Neuron object."""
138+
neuron = Neuron.Neuron()
139+
neuron.name = name
140+
neuron.set_soma(convert_morphio_soma(morph.soma))
141+
for tree in convert_morphio_trees(morph):
142+
neuron.append_tree(tree, tree_types)
143+
144+
return neuron

tmd/io/io.py

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
from scipy import sparse as sp
2424
from scipy.sparse import csgraph as cs
2525

26-
from tmd.io.conversion import convert_morphio_soma
27-
from tmd.io.conversion import convert_morphio_trees
26+
from tmd.io.conversion import convert_morphio_neuron
2827
from tmd.io.h5 import read_h5
2928
from tmd.io.swc import SWC_DCT
3029
from tmd.io.swc import read_swc
@@ -75,7 +74,7 @@ def redefine_types(user_types=None):
7574
return final_tree_types
7675

7776

78-
def load_neuron(
77+
def _load_neuron_internal(
7978
input_file, line_delimiter="\n", soma_type=None, user_tree_types=None, remove_duplicates=True
8079
):
8180
"""I/O method to load an swc or h5 file into a Neuron object."""
@@ -140,7 +139,7 @@ def load_neuron(
140139
return neuron
141140

142141

143-
def load_neuron_from_morphio(path_or_obj, user_tree_types=None):
142+
def _load_neuron_morphio(path_or_obj, user_tree_types=None):
144143
"""Create Neuron object from morphio object or from path loaded via morphio.
145144
146145
Supported file formats: h5, swc, asc.
@@ -164,20 +163,58 @@ def load_neuron_from_morphio(path_or_obj, user_tree_types=None):
164163
# MorphIO does not support naming of objects yet.
165164
filename = ""
166165

167-
neuron = Neuron.Neuron()
168-
neuron.name = filename
169-
neuron.set_soma(convert_morphio_soma(obj.soma))
170-
for tree in convert_morphio_trees(obj):
171-
neuron.append_tree(tree, tree_types)
166+
return convert_morphio_neuron(obj, tree_types, filename)
172167

173-
return neuron
174168

169+
def load_neuron(
170+
input_file, user_tree_types=None, *, line_delimiter="\n", soma_type=None, remove_duplicates=True
171+
):
172+
"""I/O method to load an 'asc', 'h5' or 'swc' file into a Neuron object.
175173
176-
def load_population(neurons, user_tree_types=None, name=None, use_morphio=False):
174+
Args:
175+
input_file (Union[str, morphio.Morphology]):
176+
Filepath or morphio object
177+
178+
Returns:
179+
neuron (Neuron): tmd Neuron object
180+
181+
"""
182+
ext = os.path.splitext(input_file)[-1][1:]
183+
if ext not in ("h5", "swc", "asc"):
184+
raise ValueError("The file extension must be in ['asc', 'h5', 'swc']")
185+
186+
try:
187+
return _load_neuron_morphio(input_file, user_tree_types=user_tree_types)
188+
except Exception as morphio_exc:
189+
try:
190+
if ext not in ("h5", "swc"):
191+
raise ValueError("The internal loader can only read '*.h5' and '*.swc' files.")
192+
neuron = _load_neuron_internal(
193+
input_file,
194+
line_delimiter=line_delimiter,
195+
soma_type=soma_type,
196+
user_tree_types=user_tree_types,
197+
remove_duplicates=remove_duplicates,
198+
)
199+
warnings.warn(
200+
f"The file {input_file} was loaded using the internal loader because of a MorphIO "
201+
"failure."
202+
)
203+
return neuron
204+
except Exception as exc:
205+
raise exc from morphio_exc
206+
207+
208+
def load_population(neurons, user_tree_types=None, name=None, use_morphio=None):
177209
"""Load all data of recognised format (swc, h5) into a Population object.
178210
179211
Takes as input a directory or a list of files to load.
180212
"""
213+
if use_morphio is not None:
214+
warnings.warn(
215+
"The 'use_morphio' parameter is deprecated as the internal loader is not only used "
216+
"when MorphIO fails."
217+
)
181218
if isinstance(neurons, (list, tuple)):
182219
files = neurons
183220
name = name if name is not None else "Population"
@@ -198,16 +235,7 @@ def load_population(neurons, user_tree_types=None, name=None, use_morphio=False)
198235

199236
for filename in files:
200237
try:
201-
ext = os.path.splitext(filename)[-1][1:]
202-
if not use_morphio:
203-
assert ext in ("h5", "swc")
204-
pop.append_neuron(load_neuron(filename, user_tree_types=user_tree_types))
205-
else:
206-
assert ext in ("h5", "swc", "asc")
207-
pop.append_neuron(
208-
load_neuron_from_morphio(filename, user_tree_types=user_tree_types)
209-
)
210-
238+
pop.append_neuron(load_neuron(filename, user_tree_types=user_tree_types))
211239
except AssertionError as exc:
212240
error_msg = "{} is not a valid h5, swc or asc file. If asc set use_morphio to True."
213241
raise Warning(error_msg.format(filename)) from exc

0 commit comments

Comments
 (0)