diff --git a/neurom/features/morphology.py b/neurom/features/morphology.py index c36525c2..fc0175fe 100644 --- a/neurom/features/morphology.py +++ b/neurom/features/morphology.py @@ -59,7 +59,7 @@ from neurom.core.types import NeuriteType from neurom.exceptions import NeuroMError from neurom.features import feature, NameSpace, neurite as nf, section as sf -from neurom.utils import str_to_plane +from neurom.utils import str_to_plane, flatten from neurom.morphmath import convex_hull @@ -115,15 +115,77 @@ def soma_radius(morph): @feature(shape=()) def max_radial_distance(morph, origin=None, neurite_type=NeuriteType.all, use_subtrees=False): """Get the maximum radial distances of the termination sections.""" + origin = morph.soma.center if origin is None else origin + term_radial_distances = _map_neurites( partial(nf.max_radial_distance, origin=origin), - morph, - neurite_type=neurite_type, - use_subtrees=use_subtrees, + morph, neurite_type, use_subtrees ) return max(term_radial_distances) if term_radial_distances else 0. +@feature(shape=(...,)) +def section_radial_distances(morph, origin=None, neurite_type=NeuriteType.all, use_subtrees=False): + """Section radial distances. + + The iterator_type can be used to select only terminal sections (ileaf) + or only bifurcations (ibifurcation_point). + """ + origin = morph.soma.center if origin is None else origin + + return list(flatten(_map_neurites( + partial(nf.section_radial_distances, origin=origin), + morph=morph, + neurite_type=neurite_type, + use_subtrees=use_subtrees, + ))) + + +@feature(shape=(...,)) +def section_term_radial_distances( + morph, origin=None, neurite_type=NeuriteType.all, use_subtrees=False +): + """Get the radial distances of the termination sections.""" + origin = morph.soma.center if origin is None else origin + + return list(flatten(_map_neurites( + partial(nf.section_term_radial_distances, origin=origin), + morph=morph, + neurite_type=neurite_type, + use_subtrees=use_subtrees + ))) + + +@feature(shape=(...,)) +def section_bif_radial_distances( + morph, origin=None, neurite_type=NeuriteType.all, use_subtrees=False +): + """Get the radial distances of the bifurcation sections.""" + origin = morph.soma.center if origin is None else origin + + return list(flatten(_map_neurites( + partial(nf.section_bif_radial_distances, origin=origin), + morph=morph, + neurite_type=neurite_type, + use_subtrees=use_subtrees, + ))) + + +@feature(shape=(...,)) +def segment_radial_distances( + morph, origin=None, neurite_type=NeuriteType.all, use_subtrees=False +): + """Ger the radial distances of the segments.""" + origin = morph.soma.center if origin is None else origin + + return list(flatten(_map_neurites( + partial(nf.segment_radial_distances, origin=origin), + morph=morph, + neurite_type=neurite_type, + use_subtrees=use_subtrees, + ))) + + @feature(shape=(...,)) def number_of_sections_per_neurite(morph, neurite_type=NeuriteType.all, use_subtrees=False): """List of numbers of sections per neurite.""" diff --git a/neurom/features/neurite.py b/neurom/features/neurite.py index 7c972779..2669f67f 100644 --- a/neurom/features/neurite.py +++ b/neurom/features/neurite.py @@ -81,15 +81,6 @@ def homogeneous_filter(section): return list(map(fun, filter(filt, iterator_type(neurite.root_node)))) -@feature(shape=()) -def max_radial_distance(neurite, origin=None, section_type=NeuriteType.all): - """Get the maximum radial distances of the termination sections.""" - term_radial_distances = section_term_radial_distances( - neurite, origin=origin, section_type=section_type - ) - return max(term_radial_distances) if term_radial_distances else 0. - - @feature(shape=()) def number_of_segments(neurite, section_type=NeuriteType.all): """Number of segments.""" @@ -423,34 +414,48 @@ def diameter_power_relations(neurite, method='first', section_type=NeuriteType.a ) +def _radial_distances(neurite, origin, iterator_type, section_type): + + if origin is None: + origin = neurite.root_node.points[0] + + return _map_sections( + partial(sf.section_radial_distance, origin=origin), + neurite=neurite, + iterator_type=iterator_type, + section_type=section_type + ) + + @feature(shape=(...,)) -def section_radial_distances( - neurite, origin=None, iterator_type=Section.ipreorder, section_type=NeuriteType.all -): +def section_radial_distances(neurite, origin=None, section_type=NeuriteType.all): """Section radial distances. The iterator_type can be used to select only terminal sections (ileaf) or only bifurcations (ibifurcation_point). """ - pos = neurite.root_node.points[0] if origin is None else origin - return _map_sections(partial(sf.section_radial_distance, origin=pos), - neurite, - iterator_type, - section_type=section_type) + return _radial_distances(neurite, origin, Section.ipreorder, section_type) @feature(shape=(...,)) def section_term_radial_distances(neurite, origin=None, section_type=NeuriteType.all): """Get the radial distances of the termination sections.""" - return section_radial_distances(neurite, origin, Section.ileaf, section_type=section_type) + return _radial_distances(neurite, origin, Section.ileaf, section_type) + + +@feature(shape=()) +def max_radial_distance(neurite, origin=None, section_type=NeuriteType.all): + """Get the maximum radial distances of the termination sections.""" + term_radial_distances = section_term_radial_distances( + neurite, origin=origin, section_type=section_type + ) + return max(term_radial_distances) if term_radial_distances else 0. @feature(shape=(...,)) def section_bif_radial_distances(neurite, origin=None, section_type=NeuriteType.all): """Get the radial distances of the bf sections.""" - return section_radial_distances( - neurite, origin, Section.ibifurcation_point, section_type=section_type - ) + return _radial_distances(neurite, origin, Section.ibifurcation_point, section_type) @feature(shape=(...,)) diff --git a/tests/features/test_get_features.py b/tests/features/test_get_features.py index 65ab30d5..8f48c912 100644 --- a/tests/features/test_get_features.py +++ b/tests/features/test_get_features.py @@ -112,23 +112,23 @@ def test_number_of_sections(): def test_max_radial_distance(): assert_allclose( features.get('max_radial_distance', POP), - [99.58945832, 94.43342439, 1053.77939245]) + [99.62086, 94.43019, 1072.9137]) assert_allclose( features.get('max_radial_distance', POP, neurite_type=NeuriteType.all), - [99.58945832, 94.43342439, 1053.77939245]) + [99.62086, 94.43019, 1072.9137]) assert_allclose( features.get('max_radial_distance', POP, neurite_type=NeuriteType.axon), - [82.442545, 82.442545, 1053.779392]) + [82.52528, 82.44438, 1072.9137]) assert_allclose( features.get('max_radial_distance', POP, neurite_type=NeuriteType.basal_dendrite), - [94.43342563, 94.43342439, 207.56977859]) + [94.36033, 94.43019, 209.92587]) assert_allclose( - features.get('max_radial_distance', NRN), 99.58945832) + features.get('max_radial_distance', NRN), 99.62086) assert_allclose( - features.get('max_radial_distance', NRN, neurite_type=NeuriteType.all), 99.58945832) + features.get('max_radial_distance', NRN, neurite_type=NeuriteType.all), 99.62086) assert_allclose(features.get( - 'max_radial_distance', NRN, neurite_type=NeuriteType.apical_dendrite), 99.589458) + 'max_radial_distance', NRN, neurite_type=NeuriteType.apical_dendrite), 99.62086) assert_allclose( features.get('max_radial_distance', NRN.neurites), @@ -771,7 +771,19 @@ def test_section_strahler_orders(): def test_section_bif_radial_distances(): + + # the feature applied on morph calculates radial distance from soma trm_rads = features.get('section_bif_radial_distances', NRN, neurite_type=nm.AXON) + + assert_allclose( + trm_rads, + [8.92228 , 16.825268, 23.152378, 30.262894, 36.71048 , + 44.049297, 52.00228 , 59.510105, 66.33529 , 74.134636] + ) + + # the feature applied per neurite calculates radial distance from root + trm_rads = features.get('section_bif_radial_distances', NRN.neurites[3]) + assert_allclose(trm_rads, [8.842008561870646, 16.7440421479104, @@ -786,7 +798,25 @@ def test_section_bif_radial_distances(): def test_section_term_radial_distances(): + trm_rads = features.get('section_term_radial_distances', NRN, neurite_type=nm.APICAL_DENDRITE) + + print(trm_rads) + assert_allclose(trm_rads, + [16.258472, + 26.040075, + 33.35425 , + 42.755745, + 52.41365 , + 59.476284, + 67.11225 , + 80.00984 , + 87.13672 , + 97.284706, + 99.62086 ]) + + apical = NRN.neurites[0] + trm_rads = features.get('section_term_radial_distances', apical, section_type=nm.APICAL_DENDRITE) assert_allclose(trm_rads, [16.22099879395879, 25.992977561564082, diff --git a/tests/test_mixed.py b/tests/test_mixed.py index fe05b9fc..00d4187d 100644 --- a/tests/test_mixed.py +++ b/tests/test_mixed.py @@ -245,7 +245,7 @@ def population(mixed_morph): return Population([mixed_morph, mixed_morph]) -def _assert_feature_equal(values, expected_values): +def _assert_feature_equal(values, expected_values, per_neurite=False): def innermost_value(iterable): while isinstance(iterable, collections.abc.Iterable): @@ -260,24 +260,34 @@ def innermost_value(iterable): a, b, err_msg=f"ACTUAL: {a}\nDESIRED: {b}", verbose=False ) - # handle empty lists because allclose always passes in that case. - # See: https://github.com/numpy/numpy/issues/11071 - if isinstance(values, collections.abc.Iterable): - if isinstance(expected_values, collections.abc.Iterable): - if isinstance(innermost_value(values), (float, np.floating)): - npt.assert_allclose(values, expected_values, atol=1e-5) + def check(values, expected_values): + # handle empty lists because allclose always passes in that case. + # See: https://github.com/numpy/numpy/issues/11071 + if isinstance(values, collections.abc.Iterable): + if isinstance(expected_values, collections.abc.Iterable): + if isinstance(innermost_value(values), (float, np.floating)): + npt.assert_allclose(values, expected_values, atol=1e-5) + else: + assert_equal(values, expected_values) else: assert_equal(values, expected_values) else: - assert_equal(values, expected_values) - else: - if isinstance(expected_values, collections.abc.Iterable): - assert_equal(values, expected_values) - else: - if isinstance(values, (float, np.floating)): - npt.assert_allclose(values, expected_values, atol=1e-5) - else: + if isinstance(expected_values, collections.abc.Iterable): assert_equal(values, expected_values) + else: + if isinstance(values, (float, np.floating)): + npt.assert_allclose(values, expected_values, atol=1e-5) + else: + assert_equal(values, expected_values) + + if per_neurite: + + assert len(values) == len(expected_values) + for neurite_values, expected_neurite_values in zip(values, expected_values): + check(neurite_values, expected_neurite_values) + else: + check(values, expected_values) + def _dispatch_features(features, mode=None): @@ -401,19 +411,19 @@ def _morphology_features(mode): # with subtrees AoD subtrees are considered separately and the distance is calculated # from their respective roots. [1, 4] is the furthest point in this case "kwargs": {"neurite_type": NeuriteType.all}, - "expected_wout_subtrees": 3.741657, - "expected_with_subtrees": 3.316625, + "expected_wout_subtrees": 4.472136, + "expected_with_subtrees": 4.472136, }, { # with a global origin, AoD axon subtree [2, 4] is always furthest from soma "kwargs": {"neurite_type": NeuriteType.all, "origin": np.array([0., 0., 0.])}, - "expected_wout_subtrees": 4.47213595499958, - "expected_with_subtrees": 4.47213595499958, + "expected_wout_subtrees": 4.472136, + "expected_with_subtrees": 4.472136, }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite}, - "expected_wout_subtrees": 3.741657, - "expected_with_subtrees": 3.316625, + "expected_wout_subtrees": 4.472136, + "expected_with_subtrees": 4.24264, }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite, "origin": np.array([0., 0., 0.])}, @@ -424,7 +434,7 @@ def _morphology_features(mode): { "kwargs": {"neurite_type": NeuriteType.axon}, "expected_wout_subtrees": 0.0, - "expected_with_subtrees": 2.44949, + "expected_with_subtrees": 4.472136, }, { "kwargs": {"neurite_type": NeuriteType.axon, "origin": np.array([0., 0., 0.])}, @@ -1154,35 +1164,35 @@ def _morphology_features(mode): # the root of the subtree is considered "kwargs": {"neurite_type": NeuriteType.all}, "expected_wout_subtrees": - [1. , 2. , 2.236068, 2.236068, 1.414214] + - [1.414214, 3.162278, 3.316625, 3.316625] + - [2.828427, 3.605551, 3.605551, 3.741657, 3.741657] + - [1., 2., 2.236068, 2.236068, 1.414214], + [2., 3., 3.162278, 3.162278, 2.236068] + + [2.236068, 4.123106, 4.24264 , 4.24264] + + [3.605551, 4.472136, 4.24264 , 4.358899, 4.358899] + + [2., 3., 3.162278, 3.162278, 2.236068], "expected_with_subtrees": - [1. , 2. , 2.236068, 2.236068, 1.414214] + - [1.414214, 3.162278, 3.316625, 3.316625] + - [1.414214, 2.236068, 2.236068, 2.44949 , 2.44949] + - [1., 2., 2.236068, 2.236068, 1.414214], + [2., 3., 3.162278, 3.162278, 2.236068] + + [2.236068, 4.123106, 4.24264 , 4.24264] + + [3.605551, 4.472136, 4.24264 , 4.358899, 4.358899] + + [2., 3., 3.162278, 3.162278, 2.236068], }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite}, "expected_wout_subtrees": - [1. , 2. , 2.236068, 2.236068, 1.414214] + - [1.414214, 3.162278, 3.316625, 3.316625] + - [2.828427, 3.605551, 3.605551, 3.741657, 3.741657], + [2., 3., 3.162278, 3.162278, 2.236068] + + [2.236068, 4.123106, 4.24264 , 4.24264] + + [3.605551, 4.472136, 4.24264 , 4.358899, 4.358899], "expected_with_subtrees": - [1. , 2. , 2.236068, 2.236068, 1.414214] + - [1.414214, 3.162278, 3.316625, 3.316625], + [2., 3., 3.162278, 3.162278, 2.236068] + + [2.236068, 4.123106, 4.24264 , 4.24264], }, { "kwargs": {"neurite_type": NeuriteType.axon}, "expected_wout_subtrees": [], - "expected_with_subtrees": [1.414214, 2.236068, 2.236068, 2.44949 , 2.44949], + "expected_with_subtrees": [3.605551, 4.472136, 4.24264 , 4.358899, 4.358899], }, { "kwargs": {"neurite_type": NeuriteType.apical_dendrite}, - "expected_wout_subtrees": [1., 2., 2.236068, 2.236068, 1.414214], - "expected_with_subtrees": [1., 2., 2.236068, 2.236068, 1.414214], + "expected_wout_subtrees": [2., 3., 3.162278, 3.162278, 2.236068], + "expected_with_subtrees": [2., 3., 3.162278, 3.162278, 2.236068], } ], @@ -1190,35 +1200,35 @@ def _morphology_features(mode): { "kwargs": {"neurite_type": NeuriteType.all}, "expected_wout_subtrees": - [2.236068, 2.236068, 1.414214] + - [3.316625, 3.316625] + - [3.605551, 3.741657, 3.741657] + - [2.236068, 2.236068, 1.414214], + [3.162278, 3.162278, 2.236068] + + [4.24264 , 4.24264] + + [4.472136, 4.358899, 4.358899] + + [3.162278, 3.162278, 2.236068], "expected_with_subtrees": - [2.236068, 2.236068, 1.414214] + - [3.316625, 3.316625] + - [2.236068, 2.44949 , 2.44949] + - [2.236068, 2.236068, 1.414214], + [3.162278, 3.162278, 2.236068] + + [4.24264 , 4.24264] + + [4.472136, 4.358899, 4.358899] + + [3.162278, 3.162278, 2.236068], }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite}, "expected_wout_subtrees": - [2.236068, 2.236068, 1.414214] + - [3.316625, 3.316625] + - [3.605551, 3.741657, 3.741657], + [3.162278, 3.162278, 2.236068] + + [4.24264 , 4.24264] + + [4.472136, 4.358899, 4.358899], "expected_with_subtrees": - [2.236068, 2.236068, 1.414214] + - [3.316625, 3.316625], + [3.162278, 3.162278, 2.236068] + + [4.24264 , 4.24264], }, { "kwargs": {"neurite_type": NeuriteType.axon}, "expected_wout_subtrees": [], - "expected_with_subtrees": [2.236068, 2.44949 , 2.44949], + "expected_with_subtrees": [4.472136, 4.358899, 4.358899], }, { "kwargs": {"neurite_type": NeuriteType.apical_dendrite}, - "expected_wout_subtrees": [2.236068, 2.236068, 1.414214], - "expected_with_subtrees": [2.236068, 2.236068, 1.414214], + "expected_wout_subtrees": [3.162278, 3.162278, 2.236068], + "expected_with_subtrees": [3.162278, 3.162278, 2.236068], } ], @@ -1229,25 +1239,25 @@ def _morphology_features(mode): # heterogeneous forks are not valid forking points "kwargs": {"neurite_type": NeuriteType.all}, "expected_wout_subtrees": - [1., 2., 1.414214, 3.162278, 2.828427, 3.605551, 1., 2.], + [2., 3., 2.236068, 4.123106, 3.605551, 4.24264 , 2., 3.], "expected_with_subtrees": - [1., 2., 3.162278, 1.414214, 2.236068, 1., 2.], + [2., 3., 4.123106, 3.605551, 4.24264 , 2., 3.], }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite}, "expected_wout_subtrees": - [1., 2., 1.414214, 3.162278, 2.828427, 3.605551], - "expected_with_subtrees": [1., 2., 3.162278], + [2., 3., 2.236068, 4.123106, 3.605551, 4.24264], + "expected_with_subtrees": [2., 3., 4.123106], }, { "kwargs": {"neurite_type": NeuriteType.axon}, "expected_wout_subtrees": [], - "expected_with_subtrees": [1.414214, 2.236068], + "expected_with_subtrees": [3.605551, 4.24264], }, { "kwargs": {"neurite_type": NeuriteType.apical_dendrite}, - "expected_wout_subtrees": [1., 2.], - "expected_with_subtrees": [1., 2.], + "expected_wout_subtrees": [2., 3.], + "expected_with_subtrees": [2., 3.], } ], "section_end_distances": [ @@ -1602,35 +1612,35 @@ def _morphology_features(mode): # the root of the subtree is considered "kwargs": {"neurite_type": NeuriteType.all}, "expected_wout_subtrees": - [0.5, 1.5, 2.061553, 2.061553, 1.118034] + - [0.707107, 2.236068, 3.201562, 3.201562] + - [2.12132 , 3.201562, 3.201562, 3.640055, 3.640055] + - [0.5, 1.5, 2.061553, 2.061553, 1.118034], + [1.5, 2.5, 3.041381, 3.041381, 2.061553] + + [1.581139, 3.162278, 4.153312, 4.153312] + + [2.915476, 4.031129, 3.905125, 4.272002, 4.272002] + + [1.5, 2.5, 3.041381, 3.041381, 2.061553], "expected_with_subtrees": - [0.5, 1.5, 2.061553, 2.061553, 1.118034] + - [0.707107, 2.236068, 3.201562, 3.201562] + - [0.707107, 1.802776, 1.802776, 2.291288, 2.291288] + - [0.5, 1.5, 2.061553, 2.061553, 1.118034], + [1.5, 2.5, 3.041381, 3.041381, 2.061553] + + [1.581139, 3.162278, 4.153312, 4.153312] + + [2.915476, 4.031129, 3.905125, 4.272002, 4.272002] + + [1.5, 2.5, 3.041381, 3.041381, 2.061553], }, { "kwargs": {"neurite_type": NeuriteType.basal_dendrite}, "expected_wout_subtrees": - [0.5, 1.5, 2.061553, 2.061553, 1.118034] + - [0.707107, 2.236068, 3.201562, 3.201562] + - [2.12132 , 3.201562, 3.201562, 3.640055, 3.640055], + [1.5, 2.5, 3.041381, 3.041381, 2.061553] + + [1.581139, 3.162278, 4.153312, 4.153312] + + [2.915476, 4.031129, 3.905125, 4.272002, 4.272002], "expected_with_subtrees": - [0.5, 1.5, 2.061553, 2.061553, 1.118034] + - [0.707107, 2.236068, 3.201562, 3.201562], + [1.5, 2.5, 3.041381, 3.041381, 2.061553] + + [1.581139, 3.162278, 4.153312, 4.153312], }, { "kwargs": {"neurite_type": NeuriteType.axon}, "expected_wout_subtrees": [], - "expected_with_subtrees": [0.707107, 1.802776, 1.802776, 2.291288, 2.291288], + "expected_with_subtrees": [2.915476, 4.031129, 3.905125, 4.272002, 4.272002], }, { "kwargs": {"neurite_type": NeuriteType.apical_dendrite}, - "expected_wout_subtrees": [0.5, 1.5, 2.061553, 2.061553, 1.118034], - "expected_with_subtrees": [0.5, 1.5, 2.061553, 2.061553, 1.118034], + "expected_wout_subtrees": [1.5, 2.5, 3.041381, 3.041381, 2.061553], + "expected_with_subtrees": [1.5, 2.5, 3.041381, 3.041381, 2.061553], }, ], "segment_midpoints": [ @@ -2180,6 +2190,142 @@ def _neurite_features(): "expected": [np.nan, np.nan, 0.2356194583819102], }, ], + "section_radial_distances": [ + { + "kwargs": {"section_type": NeuriteType.all}, + "expected": [ + [1.0, 2.0, 2.236068, 2.236068, 1.4142135], + [1.4142135, 3.1622777, 3.3166249, 3.3166249, 2.828427, 3.6055512, 3.6055512, 3.7416575, 3.7416575], + [1.0, 2.0, 2.236068, 2.236068, 1.4142135], + ], + }, + { + "kwargs": {"section_type": NeuriteType.basal_dendrite}, + "expected": [ + [1.0, 2.0, 2.236068, 2.236068, 1.4142135], + [1.414214, 3.162278, 3.316625, 3.316625], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.axon}, + "expected": [ + [], + [2.828427, 3.605551, 3.605551, 3.741657, 3.741657], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.apical_dendrite}, + "expected": [ + [], + [], + [1., 2., 2.236068, 2.236068, 1.414214], + ], + }, + ], + "section_bif_radial_distances": [ + { + "kwargs": {"section_type": NeuriteType.all}, + "expected": [ + [1., 2.], + [1.414214, 3.162278, 2.828427, 3.605551], + [1., 2.], + ], + }, + { + "kwargs": {"section_type": NeuriteType.basal_dendrite}, + "expected": [ + [1., 2.], + [3.162278], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.axon}, + "expected": [ + [], + [2.828427, 3.605551], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.apical_dendrite}, + "expected": [ + [], + [], + [1., 2.], + ], + }, + ], + "section_term_radial_distances": [ + { + "kwargs": {"section_type": NeuriteType.all}, + "expected": [ + [2.236068, 2.236068, 1.414214], + [3.316625, 3.316625, 3.605551, 3.741657, 3.741657], + [2.236068, 2.236068, 1.414214], + ], + }, + { + "kwargs": {"section_type": NeuriteType.basal_dendrite}, + "expected": [ + [2.236068, 2.236068, 1.414214], + [3.316625, 3.316625], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.axon}, + "expected": [ + [], + [3.605551, 3.741657, 3.741657], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.apical_dendrite}, + "expected": [ + [], + [], + [2.236068, 2.236068, 1.414214], + ], + }, + ], + "segment_radial_distances": [ + { + "kwargs": {"section_type": NeuriteType.all}, + "expected": [ + [0.5 , 1.5 , 2.061553, 2.061553, 1.118034], + [0.707107, 2.236068, 3.201562, 3.201562, 2.12132 , 3.201562, 3.201562, 3.640055, 3.640055], + [0.5 , 1.5 , 2.061553, 2.061553, 1.118034], + ], + }, + { + "kwargs": {"section_type": NeuriteType.basal_dendrite}, + "expected": [ + [0.5 , 1.5 , 2.061553, 2.061553, 1.118034], + [0.707107, 2.236068, 3.201562, 3.201562], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.axon}, + "expected": [ + [], + [2.12132 , 3.201562, 3.201562, 3.640055, 3.640055], + [], + ], + }, + { + "kwargs": {"section_type": NeuriteType.apical_dendrite}, + "expected": [ + [], + [], + [0.5 , 1.5 , 2.061553, 2.061553, 1.118034], + ], + }, + ] } # features that exist in both the neurite and morphology level, which indicates a different @@ -2189,7 +2335,7 @@ def _neurite_features(): ) assert not features_not_tested, ( - "The following morphology tests need to be included in the tests:\n\n" + + "The following morphology tests need to be included in the mixed neurite tests:\n\n" + "\n".join(sorted(features_not_tested)) + "\n" ) @@ -2201,4 +2347,4 @@ def test_morphology__neurite_features(feature_name, kwargs, expected, mixed_morp with warnings.catch_warnings(): warnings.simplefilter("ignore") values = get(feature_name, mixed_morph.neurites, **kwargs) - _assert_feature_equal(values, expected) + _assert_feature_equal(values, expected, per_neurite=True)