From 56fbac31594d0a4f8759a6aa84078ff0222e0ba3 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 30 Mar 2018 15:52:00 -0700 Subject: [PATCH 01/16] [ENH] Add a activation count map interface --- nipype/algorithms/stats.py | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 nipype/algorithms/stats.py diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py new file mode 100644 index 0000000000..e57a77df98 --- /dev/null +++ b/nipype/algorithms/stats.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +""" +Managing statistical maps +""" +from __future__ import (print_function, division, unicode_literals, + absolute_import) +import os +import nibabel as nb +import numpy as np + +from ..interfaces.base import ( + BaseInterfaceInputSpec, TraitedSpec, SimpleInterface, + traits, InputMultiPath, File +) + + +class ACMInputSpec(BaseInterfaceInputSpec): + in_files = InputMultiPath(File(exists=True), mandatory=True, + desc='input file, generally a list of z-stat maps') + threshold = traits.Float(1.65, usedefault=True, + desc='binarization threshold. A z-value of 1.65 ' + 'corresponds to a two-sided test of p<.10') + + +class ACMOutputSpec(TraitedSpec): + out_file = File(exists=True, desc='output activation count map') + acm_pos = File(exists=True, desc='positive activation count map') + acm_neg = File(exists=True, desc='negative activation count map') + + +class ACM(SimpleInterface): + """ + Calculate a simple Activation Count Maps + """ + input_spec = ACMInputSpec + output_spec = ACMOutputSpec + + def _run_interface(self, runtime): + allmaps = nb.concat_images( + [nb.load(f) for f in self.inputs.in_files]) + acm_pos = np.where(allmaps > self.inputs.threshold).astype( + float).mean(3) + acm_neg = np.where(allmaps < -1.0 * self.inputs.threshold).astype( + float).mean(3) + + acm_diff = acm_pos - acm_neg + + nii = nb.load(self.inputs.in_files[0]) + self._results['out_file'] = os.path.join( + runtime.cwd, 'acm_diff.nii.gz') + self._results['acm_pos'] = os.path.join( + runtime.cwd, 'acm_pos.nii.gz') + self._results['acm_neg'] = os.path.join( + runtime.cwd, 'acm_neg.nii.gz') + + nb.Nifti1Image( + acm_diff, nii.affine, nii.header).to_filename(self._results['out_file']) + nb.Nifti1Image( + acm_pos, nii.affine, nii.header).to_filename(self._results['acm_pos']) + nb.Nifti1Image( + acm_neg, nii.affine, nii.header).to_filename(self._results['acm_neg']) + + return runtime From f6a9a8112f2ce459ecd2845f173c8cff7d1dcd74 Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 30 Mar 2018 15:55:56 -0700 Subject: [PATCH 02/16] add credit to @jokedurnez [skip ci] --- nipype/algorithms/stats.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index e57a77df98..9e222e847d 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -33,6 +33,9 @@ class ACMOutputSpec(TraitedSpec): class ACM(SimpleInterface): """ Calculate a simple Activation Count Maps + + Adapted from: https://github.com/poldracklab/CNP_task_analysis/\ + blob/61c27f5992db9d8800884f8ffceb73e6957db8af/CNP_2nd_level_ACM.py """ input_spec = ACMInputSpec output_spec = ACMOutputSpec From 756088a45e54e1ee3a4f5a5522b4cdc34e31baec Mon Sep 17 00:00:00 2001 From: oesteban Date: Fri, 30 Mar 2018 23:26:36 -0700 Subject: [PATCH 03/16] fix several issues --- nipype/algorithms/stats.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 9e222e847d..66b81e76fd 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -42,10 +42,10 @@ class ACM(SimpleInterface): def _run_interface(self, runtime): allmaps = nb.concat_images( - [nb.load(f) for f in self.inputs.in_files]) - acm_pos = np.where(allmaps > self.inputs.threshold).astype( + [nb.load(f) for f in self.inputs.in_files]).get_data() + acm_pos = (allmaps > self.inputs.threshold).astype( float).mean(3) - acm_neg = np.where(allmaps < -1.0 * self.inputs.threshold).astype( + acm_neg = (allmaps < -1.0 * self.inputs.threshold).astype( float).mean(3) acm_diff = acm_pos - acm_neg From 81167ca255d78553a72388885451cc6005563d9a Mon Sep 17 00:00:00 2001 From: oesteban Date: Sat, 31 Mar 2018 18:59:06 -0700 Subject: [PATCH 04/16] cleaner reading --- nipype/algorithms/stats.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 66b81e76fd..89f59c8f8d 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -43,11 +43,10 @@ class ACM(SimpleInterface): def _run_interface(self, runtime): allmaps = nb.concat_images( [nb.load(f) for f in self.inputs.in_files]).get_data() - acm_pos = (allmaps > self.inputs.threshold).astype( - float).mean(3) - acm_neg = (allmaps < -1.0 * self.inputs.threshold).astype( - float).mean(3) - + acm_pos = np.mean(allmaps > self.inputs.threshold, + axis=3, dtype=np.float32) + acm_neg = np.mean(allmaps < -1.0 * self.inputs.threshold, + axis=3, dtype=np.float32) acm_diff = acm_pos - acm_neg nii = nb.load(self.inputs.in_files[0]) From 8a294e033fefe773ae93f1c82d44f258d0105336 Mon Sep 17 00:00:00 2001 From: oesteban Date: Sat, 31 Mar 2018 19:06:24 -0700 Subject: [PATCH 05/16] make specs --- nipype/algorithms/tests/test_auto_ACM.py | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 nipype/algorithms/tests/test_auto_ACM.py diff --git a/nipype/algorithms/tests/test_auto_ACM.py b/nipype/algorithms/tests/test_auto_ACM.py new file mode 100644 index 0000000000..0ef574bf0e --- /dev/null +++ b/nipype/algorithms/tests/test_auto_ACM.py @@ -0,0 +1,31 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..stats import ACM + + +def test_ACM_inputs(): + input_map = dict( + ignore_exception=dict( + deprecated='1.0.0', + nohash=True, + usedefault=True, + ), + in_files=dict(mandatory=True, ), + threshold=dict(usedefault=True, ), + ) + inputs = ACM.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_ACM_outputs(): + output_map = dict( + acm_neg=dict(), + acm_pos=dict(), + out_file=dict(), + ) + outputs = ACM.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value From 068dda0d750ba9e93307284d1bfccfdbe5df3481 Mon Sep 17 00:00:00 2001 From: oesteban Date: Sat, 31 Mar 2018 19:10:34 -0700 Subject: [PATCH 06/16] drop nb.load --- nipype/algorithms/stats.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 89f59c8f8d..a36c5e1cbd 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -41,8 +41,7 @@ class ACM(SimpleInterface): output_spec = ACMOutputSpec def _run_interface(self, runtime): - allmaps = nb.concat_images( - [nb.load(f) for f in self.inputs.in_files]).get_data() + allmaps = nb.concat_images(self.inputs.in_files).get_data() acm_pos = np.mean(allmaps > self.inputs.threshold, axis=3, dtype=np.float32) acm_neg = np.mean(allmaps < -1.0 * self.inputs.threshold, From beaf3b870c0b0bfdbe84be9925ca41322dcf7fcf Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 10 Apr 2018 09:42:44 -0400 Subject: [PATCH 07/16] TEST: Activation count map smoke test --- nipype/algorithms/tests/test_stats.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 nipype/algorithms/tests/test_stats.py diff --git a/nipype/algorithms/tests/test_stats.py b/nipype/algorithms/tests/test_stats.py new file mode 100644 index 0000000000..f9865a3fb3 --- /dev/null +++ b/nipype/algorithms/tests/test_stats.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: + +import numpy as np +import nibabel as nb +from nipype.algorithms.stats import ACM + + +def test_ACM(tmpdir): + tmpdir.chdir() + in_files = ['{:d}.nii'.format(i) for i in range(3)] + for fname in in_files: + nb.Nifti1Image(np.random.normal(size=(5, 5, 5)), + np.eye(4)).to_filename(fname) + + acm = ACM(in_files=in_files) + res = acm.run() + diff = nb.load(res.outputs.out_file) + pos = nb.load(res.outputs.acm_pos) + neg = nb.load(res.outputs.acm_neg) + assert np.allclose(diff.get_data(), pos.get_data() - neg.get_data()) From 4b93c9e6807d5c7f514ec3aff8628a661e7593f9 Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 10 Apr 2018 09:06:35 -0700 Subject: [PATCH 08/16] address @effigies' comments --- nipype/algorithms/stats.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index a36c5e1cbd..8a625b32b0 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -14,9 +14,10 @@ BaseInterfaceInputSpec, TraitedSpec, SimpleInterface, traits, InputMultiPath, File ) +from ...utils.filemanip import split_filename -class ACMInputSpec(BaseInterfaceInputSpec): +class ActivationCountInputSpec(BaseInterfaceInputSpec): in_files = InputMultiPath(File(exists=True), mandatory=True, desc='input file, generally a list of z-stat maps') threshold = traits.Float(1.65, usedefault=True, @@ -24,21 +25,21 @@ class ACMInputSpec(BaseInterfaceInputSpec): 'corresponds to a two-sided test of p<.10') -class ACMOutputSpec(TraitedSpec): +class ActivationCountOutputSpec(TraitedSpec): out_file = File(exists=True, desc='output activation count map') acm_pos = File(exists=True, desc='positive activation count map') acm_neg = File(exists=True, desc='negative activation count map') -class ACM(SimpleInterface): +class ActivationCount(SimpleInterface): """ Calculate a simple Activation Count Maps Adapted from: https://github.com/poldracklab/CNP_task_analysis/\ blob/61c27f5992db9d8800884f8ffceb73e6957db8af/CNP_2nd_level_ACM.py """ - input_spec = ACMInputSpec - output_spec = ACMOutputSpec + input_spec = ActivationCountInputSpec + output_spec = ActivationCountOutputSpec def _run_interface(self, runtime): allmaps = nb.concat_images(self.inputs.in_files).get_data() @@ -48,19 +49,20 @@ def _run_interface(self, runtime): axis=3, dtype=np.float32) acm_diff = acm_pos - acm_neg - nii = nb.load(self.inputs.in_files[0]) - self._results['out_file'] = os.path.join( - runtime.cwd, 'acm_diff.nii.gz') - self._results['acm_pos'] = os.path.join( - runtime.cwd, 'acm_pos.nii.gz') - self._results['acm_neg'] = os.path.join( - runtime.cwd, 'acm_neg.nii.gz') + template_fname = self.inputs.in_files[0] + ext = split_filename(template_fname)[2] + fname_fmt = os.path.join(runtime.cwd, 'acm_{}' + ext).format - nb.Nifti1Image( - acm_diff, nii.affine, nii.header).to_filename(self._results['out_file']) - nb.Nifti1Image( - acm_pos, nii.affine, nii.header).to_filename(self._results['acm_pos']) - nb.Nifti1Image( - acm_neg, nii.affine, nii.header).to_filename(self._results['acm_neg']) + self._results['out_file'] = fname_fmt('diff') + self._results['acm_pos'] = fname_fmt('pos') + self._results['acm_neg'] = fname_fmt('neg') + + img = nb.load(template_fname) + img.__class__(acm_diff, img.affine, img.header).to_filename( + self._results['out_file']) + img.__class__(acm_pos, img.affine, img.header).to_filename( + self._results['acm_pos']) + img.__class__(acm_neg, img.affine, img.header).to_filename( + self._results['acm_neg']) return runtime From 608c4d2ef788a07e61b93716d0b2af402d6a72a6 Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 10 Apr 2018 09:10:00 -0700 Subject: [PATCH 09/16] update test and autotest --- nipype/algorithms/stats.py | 2 +- .../tests/test_auto_ActivationCount.py | 31 +++++++++++++++++++ nipype/algorithms/tests/test_stats.py | 6 ++-- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 nipype/algorithms/tests/test_auto_ActivationCount.py diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 8a625b32b0..2c361b292d 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -14,7 +14,7 @@ BaseInterfaceInputSpec, TraitedSpec, SimpleInterface, traits, InputMultiPath, File ) -from ...utils.filemanip import split_filename +from ..utils.filemanip import split_filename class ActivationCountInputSpec(BaseInterfaceInputSpec): diff --git a/nipype/algorithms/tests/test_auto_ActivationCount.py b/nipype/algorithms/tests/test_auto_ActivationCount.py new file mode 100644 index 0000000000..c641358b51 --- /dev/null +++ b/nipype/algorithms/tests/test_auto_ActivationCount.py @@ -0,0 +1,31 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..stats import ActivationCount + + +def test_ActivationCount_inputs(): + input_map = dict( + ignore_exception=dict( + deprecated='1.0.0', + nohash=True, + usedefault=True, + ), + in_files=dict(mandatory=True, ), + threshold=dict(usedefault=True, ), + ) + inputs = ActivationCount.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_ActivationCount_outputs(): + output_map = dict( + acm_neg=dict(), + acm_pos=dict(), + out_file=dict(), + ) + outputs = ActivationCount.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/algorithms/tests/test_stats.py b/nipype/algorithms/tests/test_stats.py index f9865a3fb3..0b24ab54c9 100644 --- a/nipype/algorithms/tests/test_stats.py +++ b/nipype/algorithms/tests/test_stats.py @@ -4,17 +4,17 @@ import numpy as np import nibabel as nb -from nipype.algorithms.stats import ACM +from nipype.algorithms.stats import ActivationCount -def test_ACM(tmpdir): +def test_ActivationCount(tmpdir): tmpdir.chdir() in_files = ['{:d}.nii'.format(i) for i in range(3)] for fname in in_files: nb.Nifti1Image(np.random.normal(size=(5, 5, 5)), np.eye(4)).to_filename(fname) - acm = ACM(in_files=in_files) + acm = ActivationCount(in_files=in_files) res = acm.run() diff = nb.load(res.outputs.out_file) pos = nb.load(res.outputs.acm_pos) From f81c1cf36946139196039e7e847066736f688c7a Mon Sep 17 00:00:00 2001 From: oesteban Date: Tue, 10 Apr 2018 09:11:11 -0700 Subject: [PATCH 10/16] remove old autotest --- nipype/algorithms/tests/test_auto_ACM.py | 31 ------------------------ 1 file changed, 31 deletions(-) delete mode 100644 nipype/algorithms/tests/test_auto_ACM.py diff --git a/nipype/algorithms/tests/test_auto_ACM.py b/nipype/algorithms/tests/test_auto_ACM.py deleted file mode 100644 index 0ef574bf0e..0000000000 --- a/nipype/algorithms/tests/test_auto_ACM.py +++ /dev/null @@ -1,31 +0,0 @@ -# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT -from __future__ import unicode_literals -from ..stats import ACM - - -def test_ACM_inputs(): - input_map = dict( - ignore_exception=dict( - deprecated='1.0.0', - nohash=True, - usedefault=True, - ), - in_files=dict(mandatory=True, ), - threshold=dict(usedefault=True, ), - ) - inputs = ACM.input_spec() - - for key, metadata in list(input_map.items()): - for metakey, value in list(metadata.items()): - assert getattr(inputs.traits()[key], metakey) == value -def test_ACM_outputs(): - output_map = dict( - acm_neg=dict(), - acm_pos=dict(), - out_file=dict(), - ) - outputs = ACM.output_spec() - - for key, metadata in list(output_map.items()): - for metakey, value in list(metadata.items()): - assert getattr(outputs.traits()[key], metakey) == value From 6e53f016f819bd6330fa63f7d9002cd6c565432b Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Tue, 17 Apr 2018 15:18:56 -0400 Subject: [PATCH 11/16] adding tests that checks pos/neg for normal distribution --- nipype/algorithms/tests/test_stats.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/nipype/algorithms/tests/test_stats.py b/nipype/algorithms/tests/test_stats.py index 0b24ab54c9..4f431d2442 100644 --- a/nipype/algorithms/tests/test_stats.py +++ b/nipype/algorithms/tests/test_stats.py @@ -5,6 +5,7 @@ import numpy as np import nibabel as nb from nipype.algorithms.stats import ActivationCount +import pytest def test_ActivationCount(tmpdir): @@ -20,3 +21,23 @@ def test_ActivationCount(tmpdir): pos = nb.load(res.outputs.acm_pos) neg = nb.load(res.outputs.acm_neg) assert np.allclose(diff.get_data(), pos.get_data() - neg.get_data()) + + +@pytest.mark.parametrize("threshold, above_thresh", [ + (1, 15.865), # above one standard deviation (one side) + (2, 2.275), # above two standard deviations (one side) + (3, 0.135) # above three standard deviations (one side) + ]) +def test_ActivationCount_normaldistr(tmpdir, threshold, above_thresh): + tmpdir.chdir() + in_files = ['{:d}.nii'.format(i) for i in range(3)] + for fname in in_files: + nb.Nifti1Image(np.random.normal(size=(50, 50, 50)), + np.eye(4)).to_filename(fname) + + acm = ActivationCount(in_files=in_files, threshold=threshold) + res = acm.run() + pos = nb.load(res.outputs.acm_pos) + neg = nb.load(res.outputs.acm_neg) + assert np.isclose(pos.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-6) + assert np.isclose(neg.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-6) From 6348862218f532ed204c572a7787dc125773c092 Mon Sep 17 00:00:00 2001 From: Dorota Jarecka Date: Tue, 17 Apr 2018 16:25:45 -0400 Subject: [PATCH 12/16] increasing atol in the test --- nipype/algorithms/tests/test_stats.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/algorithms/tests/test_stats.py b/nipype/algorithms/tests/test_stats.py index 4f431d2442..278c44ea7a 100644 --- a/nipype/algorithms/tests/test_stats.py +++ b/nipype/algorithms/tests/test_stats.py @@ -32,12 +32,12 @@ def test_ActivationCount_normaldistr(tmpdir, threshold, above_thresh): tmpdir.chdir() in_files = ['{:d}.nii'.format(i) for i in range(3)] for fname in in_files: - nb.Nifti1Image(np.random.normal(size=(50, 50, 50)), + nb.Nifti1Image(np.random.normal(size=(100, 100, 100)), np.eye(4)).to_filename(fname) acm = ActivationCount(in_files=in_files, threshold=threshold) res = acm.run() pos = nb.load(res.outputs.acm_pos) neg = nb.load(res.outputs.acm_neg) - assert np.isclose(pos.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-6) - assert np.isclose(neg.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-6) + assert np.isclose(pos.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-4) + assert np.isclose(neg.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-4) From e0ba9963d5d50e497391edeaebbc324fa852c185 Mon Sep 17 00:00:00 2001 From: oesteban Date: Wed, 25 Apr 2018 10:55:26 -0700 Subject: [PATCH 13/16] make threshold mandatory without default --- nipype/algorithms/stats.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 2c361b292d..6f6da4a12d 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -20,9 +20,9 @@ class ActivationCountInputSpec(BaseInterfaceInputSpec): in_files = InputMultiPath(File(exists=True), mandatory=True, desc='input file, generally a list of z-stat maps') - threshold = traits.Float(1.65, usedefault=True, - desc='binarization threshold. A z-value of 1.65 ' - 'corresponds to a two-sided test of p<.10') + threshold = traits.Float( + mandatory=True, desc='binarization threshold. E.g. a threshold of 1.65 ' + 'corresponds to a two-sided test of p<.10') class ActivationCountOutputSpec(TraitedSpec): From cfb19c44c8de6ecff13eced56b4ce8bc0c5a9042 Mon Sep 17 00:00:00 2001 From: oesteban Date: Wed, 25 Apr 2018 10:59:04 -0700 Subject: [PATCH 14/16] forgot make specs --- nipype/algorithms/tests/test_auto_ActivationCount.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/algorithms/tests/test_auto_ActivationCount.py b/nipype/algorithms/tests/test_auto_ActivationCount.py index c641358b51..180f52a30e 100644 --- a/nipype/algorithms/tests/test_auto_ActivationCount.py +++ b/nipype/algorithms/tests/test_auto_ActivationCount.py @@ -11,7 +11,7 @@ def test_ActivationCount_inputs(): usedefault=True, ), in_files=dict(mandatory=True, ), - threshold=dict(usedefault=True, ), + threshold=dict(mandatory=True, ), ) inputs = ActivationCount.input_spec() From 31bc3118bd47ef3a350a3340254ddc80b7e0876b Mon Sep 17 00:00:00 2001 From: oesteban Date: Wed, 25 Apr 2018 11:00:22 -0700 Subject: [PATCH 15/16] [skip ci] improve description --- nipype/algorithms/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/algorithms/stats.py b/nipype/algorithms/stats.py index 6f6da4a12d..51a3bc9088 100644 --- a/nipype/algorithms/stats.py +++ b/nipype/algorithms/stats.py @@ -22,7 +22,7 @@ class ActivationCountInputSpec(BaseInterfaceInputSpec): desc='input file, generally a list of z-stat maps') threshold = traits.Float( mandatory=True, desc='binarization threshold. E.g. a threshold of 1.65 ' - 'corresponds to a two-sided test of p<.10') + 'corresponds to a two-sided Z-test of p<.10') class ActivationCountOutputSpec(TraitedSpec): From 728bc1bd98598ef2561747a73449da25f7a7a635 Mon Sep 17 00:00:00 2001 From: oesteban Date: Wed, 25 Apr 2018 13:34:30 -0700 Subject: [PATCH 16/16] fix test --- nipype/algorithms/tests/test_stats.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/nipype/algorithms/tests/test_stats.py b/nipype/algorithms/tests/test_stats.py index 278c44ea7a..9a4c7525b5 100644 --- a/nipype/algorithms/tests/test_stats.py +++ b/nipype/algorithms/tests/test_stats.py @@ -15,7 +15,7 @@ def test_ActivationCount(tmpdir): nb.Nifti1Image(np.random.normal(size=(5, 5, 5)), np.eye(4)).to_filename(fname) - acm = ActivationCount(in_files=in_files) + acm = ActivationCount(in_files=in_files, threshold=1.65) res = acm.run() diff = nb.load(res.outputs.out_file) pos = nb.load(res.outputs.acm_pos) @@ -24,10 +24,10 @@ def test_ActivationCount(tmpdir): @pytest.mark.parametrize("threshold, above_thresh", [ - (1, 15.865), # above one standard deviation (one side) - (2, 2.275), # above two standard deviations (one side) - (3, 0.135) # above three standard deviations (one side) - ]) + (1, 15.865), # above one standard deviation (one side) + (2, 2.275), # above two standard deviations (one side) + (3, 0.135) # above three standard deviations (one side) +]) def test_ActivationCount_normaldistr(tmpdir, threshold, above_thresh): tmpdir.chdir() in_files = ['{:d}.nii'.format(i) for i in range(3)] @@ -39,5 +39,7 @@ def test_ActivationCount_normaldistr(tmpdir, threshold, above_thresh): res = acm.run() pos = nb.load(res.outputs.acm_pos) neg = nb.load(res.outputs.acm_neg) - assert np.isclose(pos.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-4) - assert np.isclose(neg.get_data().mean(), above_thresh*1.e-2, rtol=0.1, atol=1.e-4) + assert np.isclose(pos.get_data().mean(), + above_thresh * 1.e-2, rtol=0.1, atol=1.e-4) + assert np.isclose(neg.get_data().mean(), + above_thresh * 1.e-2, rtol=0.1, atol=1.e-4)