From a29cfaaccd7c9175f4d26d1c8151745250de01f1 Mon Sep 17 00:00:00 2001 From: Benoit Coste Date: Fri, 5 Mar 2021 15:44:00 +0100 Subject: [PATCH] More reconciliation with mut_morphio (#875) This brings more formatting of the test file --- neurom/check/tests/test_neuron_checks.py | 14 +- neurom/check/tests/test_runner.py | 276 +++++++++------------ neurom/core/tests/test_iter.py | 1 - neurom/features/tests/test_get_features.py | 27 +- test_data/swc/soma_zero_radius.swc | 31 +++ 5 files changed, 168 insertions(+), 181 deletions(-) create mode 100644 test_data/swc/soma_zero_radius.swc diff --git a/neurom/check/tests/test_neuron_checks.py b/neurom/check/tests/test_neuron_checks.py index 41d53df7d..3a3cd4327 100644 --- a/neurom/check/tests/test_neuron_checks.py +++ b/neurom/check/tests/test_neuron_checks.py @@ -42,6 +42,8 @@ SWC_PATH = DATA_PATH / 'swc' ASC_PATH = DATA_PATH / 'neurolucida' H5V1_PATH = DATA_PATH / 'h5/v1' +MORPHIO_OFFSET = 0 + def _load_neuron(name): @@ -221,13 +223,12 @@ def test_nonzero_segment_lengths_bad_data(): 'Single_axon.swc', ] - morphio_offset = 0 bad_ids = [[2, 23, 44, 65], [2], [2], [2], [2]] for i, nrn in enumerate(_pick(files)): ids = nrn_chk.has_all_nonzero_segment_lengths(nrn) nt.assert_equal(ids.info, - [(id + morphio_offset, 0) for id in bad_ids[i]]) + [(id + MORPHIO_OFFSET, 0) for id in bad_ids[i]]) def test_nonzero_segment_lengths_threshold(): @@ -240,9 +241,8 @@ def test_nonzero_segment_lengths_threshold(): ids = nrn_chk.has_all_nonzero_segment_lengths(nrn, threshold=0.25) bad_ids = [(2, 0), (23, 0), (38, 9), (44, 0), (54, 7), (62, 2), (65, 0), (72, 4), (78, 6)] - morphio_offset = 0 nt.assert_equal(ids.info, - [(id + morphio_offset, val) for id, val in bad_ids]) + [(id + MORPHIO_OFFSET, val) for id, val in bad_ids]) def test_nonzero_section_lengths_good_data(): @@ -263,7 +263,7 @@ def test_nonzero_section_lengths_bad_data(): ids = nrn_chk.has_all_nonzero_section_lengths(nrn) nt.ok_(not ids.status) - nt.assert_equal(ids.info, [15]) + nt.assert_equal(ids.info, [15 + MORPHIO_OFFSET]) def test_nonzero_section_lengths_threshold(): @@ -285,8 +285,7 @@ def test_has_nonzero_soma_radius(): def test_has_nonzero_soma_radius_bad_data(): - - nrn = load_neuron(SWC_PATH / 'Single_basal.swc') + nrn = load_neuron(SWC_PATH / 'soma_zero_radius.swc') nt.assert_false(nrn_chk.has_nonzero_soma_radius(nrn).status) @@ -394,6 +393,7 @@ def test_has_no_narrow_dendritic_section(): 8 3 6 -4 0 10. 7 9 3 -5 -4 0 10. 7 """) + nrn = load_neuron(swc_content, reader='swc') res = nrn_chk.has_no_narrow_neurite_section(nrn, dendrite_filter, radius_threshold=5, considered_section_min_length=0) diff --git a/neurom/check/tests/test_runner.py b/neurom/check/tests/test_runner.py index 0c1ccbdfc..d69bb762c 100644 --- a/neurom/check/tests/test_runner.py +++ b/neurom/check/tests/test_runner.py @@ -26,33 +26,24 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from pathlib import Path +import os +from collections import OrderedDict from copy import copy - -from nose import tools as nt +from pathlib import Path from neurom.check.runner import CheckRunner from neurom.exceptions import ConfigError -from pathlib import Path +from nose import tools as nt +_path = os.path.dirname(os.path.abspath(__file__)) +SWC_PATH = Path(__file__).parent / '../../../test_data/swc/' -SWC_PATH = Path(__file__).parent.parent.parent.parent / 'test_data/swc/' -NRN_PATH_0 = str(Path(SWC_PATH, 'Neuron.swc')) -NRN_PATH_1 = str(Path(SWC_PATH, 'Neuron_zero_length_sections.swc')) -NRN_PATH_2 = str(Path(SWC_PATH, 'Single_apical.swc')) -NRN_PATH_3 = str(Path(SWC_PATH, 'Single_basal.swc')) -NRN_PATH_4 = str(Path(SWC_PATH, 'Single_axon.swc')) -NRN_PATH_5 = str(Path(SWC_PATH, 'Single_apical_no_soma.swc')) CONFIG = { 'checks': { 'structural_checks': [ - 'is_single_tree', 'has_soma_points', - 'has_sequential_ids', - 'has_increasing_ids', 'has_valid_soma', - 'has_valid_neurites' ], 'neuron_checks': [ 'has_basal_dendrite', @@ -72,183 +63,140 @@ }, } +checks_not_in_morphio = OrderedDict([ + ('has_valid_neurites', 'Has valid neurites'), + ('has_sequential_ids', 'Has sequential ids'), + ('has_increasing_ids', 'Has increasing ids'), + ('is_single_tree', 'Is single tree'), +]) +CONFIG['checks']['structural_checks'] += list(checks_not_in_morphio.keys()) + CONFIG_COLOR = copy(CONFIG) CONFIG_COLOR['color'] = True -REF_0 = { - 'files': { - NRN_PATH_0: { - "Is single tree": True, - "Has soma points": True, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": True, - "Has valid neurites": True, - "Has basal dendrite": True, - "Has axon": True, - "Has apical dendrite": True, - "Has all nonzero segment lengths": True, - "Has all nonzero section lengths": True, - "Has all nonzero neurite radii": True, - "Has nonzero soma radius": True, - "ALL": True - } - }, - "STATUS": "PASS" -} - -REF_1 = { - 'files': { - NRN_PATH_1: { - "Is single tree": True, - "Has soma points": True, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": True, - "Has valid neurites": True, - "Has basal dendrite": True, - "Has axon": True, - "Has apical dendrite": True, - "Has all nonzero segment lengths": False, - "Has all nonzero section lengths": False, - "Has all nonzero neurite radii": True, - "Has nonzero soma radius": True, - "ALL": False - } - }, - "STATUS": "FAIL" -} - -REF_2 = { - 'files': { - NRN_PATH_2: { - "Is single tree": True, - "Has soma points": True, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": True, - "Has valid neurites": True, - "Has basal dendrite": False, - "Has axon": False, - "Has apical dendrite": True, - "Has all nonzero segment lengths": False, - "Has all nonzero section lengths": True, - "Has all nonzero neurite radii": True, - "Has nonzero soma radius": True, - "ALL": False - } - }, - "STATUS": "FAIL" -} - -REF_3 = { - 'files': { - NRN_PATH_3: { - "Is single tree": True, - "Has soma points": True, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": True, - "Has valid neurites": True, - "Has basal dendrite": True, - "Has axon": False, - "Has apical dendrite": False, - "Has all nonzero segment lengths": False, - "Has all nonzero section lengths": True, - "Has all nonzero neurite radii": True, - "Has nonzero soma radius": False, - "ALL": False - } - }, - "STATUS": "FAIL" -} - -REF_4 = { - 'files': { - NRN_PATH_4: { - "Is single tree": True, - "Has soma points": True, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": True, - "Has valid neurites": True, - "Has basal dendrite": False, - "Has axon": True, - "Has apical dendrite": False, - "Has all nonzero segment lengths": False, - "Has all nonzero section lengths": True, - "Has all nonzero neurite radii": True, - "Has nonzero soma radius": True, - "ALL": False - } - }, - "STATUS": "FAIL" -} - - -REF_5 = { - 'files': { - NRN_PATH_5: { - "Is single tree": True, - "Has soma points": False, - "Has sequential ids": True, - "Has increasing ids": True, - "Has valid soma": False, - "Has valid neurites": False, - "ALL": False - } - }, - "STATUS": "FAIL" -} +def _run_test(path, ref, config=CONFIG, should_pass=False): + '''Run checkers with the passed "config" on file "path" + and compare the results to "ref"''' + results = CheckRunner(config).run(path) + nt.assert_dict_equal(dict(results['files'][path]), ref) + nt.assert_equal(results['STATUS'], + "PASS" if should_pass else "FAIL") + +ref = dict([ + ("Has soma points", True), + ("Has valid soma", True), + ("Has basal dendrite", True), + ("Has axon", True), + ("Has apical dendrite", True), + ("Has all nonzero segment lengths", True), + ("Has all nonzero section lengths", True), + ("Has all nonzero neurite radii", True), + ("Has nonzero soma radius", True), + ("ALL", True) +]) +ref.update({(item.replace('_', ' ').capitalize(), True) for item in checks_not_in_morphio.values()}) def test_ok_neuron(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_0) - nt.assert_equal(summ, REF_0) - + _run_test(os.path.join(SWC_PATH, 'Neuron.swc'), + ref, + should_pass=True) def test_ok_neuron_color(): - checker = CheckRunner(CONFIG_COLOR) - summ = checker.run(NRN_PATH_0) - nt.assert_equal(summ, REF_0) + _run_test(os.path.join(SWC_PATH, 'Neuron.swc'), + ref, + CONFIG_COLOR, + should_pass=True) def test_zero_length_sections_neuron(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_1) - nt.assert_equal(summ, REF_1) + expected = dict([ + ("Has soma points", True), + ("Has valid soma", True), + ("Has basal dendrite", True), + ("Has axon", True), + ("Has apical dendrite", True), + ("Has all nonzero segment lengths", False), + ("Has all nonzero section lengths", False), + ("Has all nonzero neurite radii", True), + ("Has nonzero soma radius", True), + ("ALL", False) + ]) + expected.update({(item, True) for item in checks_not_in_morphio.values()}) + _run_test(os.path.join(SWC_PATH, 'Neuron_zero_length_sections.swc'), + expected) def test_single_apical_neuron(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_2) - nt.assert_equal(summ, REF_2) + expected = dict([ + ("Has soma points", True), + ("Has valid soma", True), + ("Has basal dendrite", False), + ("Has axon", False), + ("Has apical dendrite", True), + ("Has all nonzero segment lengths", False), + ("Has all nonzero section lengths", True), + ("Has all nonzero neurite radii", True), + ("Has nonzero soma radius", True), + ("ALL", False) + ]) + expected.update({(item, True) for item in checks_not_in_morphio.values()}) + _run_test(os.path.join(SWC_PATH, 'Single_apical.swc'), + expected) def test_single_basal_neuron(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_3) - nt.assert_equal(summ, REF_3) + expected = dict( + ([ + ("Has soma points", True), + ("Has valid soma", True), + ("Has basal dendrite", True), + ("Has axon", False), + ("Has apical dendrite", False), + ("Has all nonzero segment lengths", False), + ("Has all nonzero section lengths", True), + ("Has all nonzero neurite radii", True), + ("Has nonzero soma radius", False), # Should be True, will be fixed by v2 + ("ALL", False) + ])) + expected.update({(item, True) for item in checks_not_in_morphio.values()}) + _run_test(os.path.join(SWC_PATH, 'Single_basal.swc'), + expected) def test_single_axon_neuron(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_4) - nt.assert_equal(summ, REF_4) + expected = dict([ + ("Has soma points", True), + ("Has valid soma", True), + ("Has basal dendrite", False), + ("Has axon", True), + ("Has apical dendrite", False), + ("Has all nonzero segment lengths", False), + ("Has all nonzero section lengths", True), + ("Has all nonzero neurite radii", True), + ("Has nonzero soma radius", True), + ("ALL", False) + ]) + expected.update({(item, True) for item in checks_not_in_morphio.values()}) + _run_test(os.path.join(SWC_PATH, 'Single_axon.swc'), + expected) def test_single_apical_no_soma(): - checker = CheckRunner(CONFIG) - summ = checker.run(NRN_PATH_5) - nt.assert_equal(summ, REF_5) + expected = dict([('Has soma points', False), + ('Has valid soma', False), + ('ALL', False)]) + expected.update({(item, True) for item in checks_not_in_morphio.values()}) + expected['Has valid neurites'] = False + _run_test(os.path.join(SWC_PATH, 'Single_apical_no_soma.swc'), + expected) def test_directory_input(): checker = CheckRunner(CONFIG) summ = checker.run(SWC_PATH) - nt.eq_(summ['files'][NRN_PATH_0]['Has axon'], True) - nt.eq_(summ['files'][NRN_PATH_2]['Has axon'], False) + nt.eq_(summ['files'][os.path.join(SWC_PATH, 'Single_axon.swc')]['Has axon'], True) + nt.eq_(summ['files'][os.path.join(SWC_PATH, 'Single_apical.swc')]['Has axon'], False) @nt.raises(IOError) diff --git a/neurom/core/tests/test_iter.py b/neurom/core/tests/test_iter.py index 03ca702f4..93ae9d14f 100644 --- a/neurom/core/tests/test_iter.py +++ b/neurom/core/tests/test_iter.py @@ -117,7 +117,6 @@ def test_iter_sections_ipreorder(): assert_sequence_equal([s.id + MORPHIO_OFFSET for n in POP.neurites for s in n.iter_sections(Tree.ipreorder)], [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 2, 3, 4]) - def test_iter_sections_ipostorder(): assert_sequence_equal([s.id + MORPHIO_OFFSET for n in POP.neurites for s in n.iter_sections(Tree.ipostorder)], [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 85, 83, 81, 79, 77, 75, 73, 71, 69, 67, 65, 2, 3, 4]) diff --git a/neurom/features/tests/test_get_features.py b/neurom/features/tests/test_get_features.py index 813d0d263..21898b9cd 100644 --- a/neurom/features/tests/test_get_features.py +++ b/neurom/features/tests/test_get_features.py @@ -328,16 +328,20 @@ def test_segment_meander_angles_nrn(): feat = 'segment_meander_angles' assert_allclose(_stats(get_feature(feat, NRN)), - (0.326101999292573, 3.129961675751181, 1842.351779156608, 2.4369732528526562)) + (0.32610, 3.12996, 1842.35, 2.43697), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.all)), - (0.326101999292573, 3.129961675751181, 1842.351779156608, 2.4369732528526562)) + (0.32610, 3.12996, 1842.35, 2.43697), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.apical_dendrite)), - (0.326101999292573, 3.0939261437163492, 461.98168732359414, 2.4443475519766884)) + (0.32610, 3.09392, 461.981, 2.44434), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.basal_dendrite)), - (0.47318725279312024, 3.129961675751181, 926.33847274926438, 2.4506308802890593)) + (0.47318, 3.12996, 926.338, 2.45063), + rtol=1e-4) def test_neurite_volumes_nrn(): @@ -345,19 +349,24 @@ def test_neurite_volumes_nrn(): feat = 'neurite_volumes' assert_allclose(_stats(get_feature(feat, NRN)), - (271.94122143951864, 281.24754646913954, 1104.9077698137021, 276.22694245342552)) + (271.9412, 281.2475, 1104.907, 276.2269), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.all)), - (271.94122143951864, 281.24754646913954, 1104.9077698137021, 276.22694245342552)) + (271.9412, 281.2475, 1104.907, 276.2269), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.axon)), - (276.73860261723024, 276.73860261723024, 276.73860261723024, 276.73860261723024)) + (276.7386, 276.7386, 276.7386, 276.7386), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.basal_dendrite)), - (274.98039928781355, 281.24754646913954, 556.22794575695309, 278.11397287847655)) + (274.9803, 281.2475, 556.2279, 278.1139), + rtol=1e-5) assert_allclose(_stats(get_feature(feat, NRN, neurite_type=NeuriteType.apical_dendrite)), - (271.94122143951864, 271.94122143951864, 271.94122143951864, 271.94122143951864)) + (271.9412, 271.9412, 271.9412, 271.9412), + rtol=1e-5) def test_neurite_volumes_pop(): diff --git a/test_data/swc/soma_zero_radius.swc b/test_data/swc/soma_zero_radius.swc new file mode 100644 index 000000000..0a6b24b07 --- /dev/null +++ b/test_data/swc/soma_zero_radius.swc @@ -0,0 +1,31 @@ +# SWC structure: +# index, type, x, y, z, radius, parent +# +# (0, 5) +# (-5, 5)----- ------ (6, 5) +# | +# | +# | +# | Type = 3 +# | +# o origin +# | +# | Type = 2 +# | +# | +#(-5, -4)----- ------ (6, -4) +# (0, -4) +# +# all radii are 1, except for end points, which are 0 +# section types: soma=1, axon=2, basal=3, apical=4 +# Like simple.swc but with a soma with 0 radii + + 1 1 0 0 0 0 -1 + 2 3 0 0 0 0 1 + 3 3 0 5 0 0 2 + 4 3 -5 5 0 0. 3 + 5 3 6 5 0 0. 3 + 6 2 0 0 0 1. 1 + 7 2 0 -4 0 1. 6 + 8 2 6 -4 0 0. 7 + 9 2 -5 -4 0 0. 7