nimare 0.4.2rc4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. benchmarks/__init__.py +0 -0
  2. benchmarks/bench_cbma.py +57 -0
  3. nimare/__init__.py +45 -0
  4. nimare/_version.py +21 -0
  5. nimare/annotate/__init__.py +21 -0
  6. nimare/annotate/cogat.py +213 -0
  7. nimare/annotate/gclda.py +924 -0
  8. nimare/annotate/lda.py +147 -0
  9. nimare/annotate/text.py +75 -0
  10. nimare/annotate/utils.py +87 -0
  11. nimare/base.py +217 -0
  12. nimare/cli.py +124 -0
  13. nimare/correct.py +462 -0
  14. nimare/dataset.py +685 -0
  15. nimare/decode/__init__.py +33 -0
  16. nimare/decode/base.py +115 -0
  17. nimare/decode/continuous.py +462 -0
  18. nimare/decode/discrete.py +753 -0
  19. nimare/decode/encode.py +110 -0
  20. nimare/decode/utils.py +44 -0
  21. nimare/diagnostics.py +510 -0
  22. nimare/estimator.py +139 -0
  23. nimare/extract/__init__.py +19 -0
  24. nimare/extract/extract.py +466 -0
  25. nimare/extract/utils.py +295 -0
  26. nimare/generate.py +331 -0
  27. nimare/io.py +635 -0
  28. nimare/meta/__init__.py +39 -0
  29. nimare/meta/cbma/__init__.py +6 -0
  30. nimare/meta/cbma/ale.py +951 -0
  31. nimare/meta/cbma/base.py +947 -0
  32. nimare/meta/cbma/mkda.py +1361 -0
  33. nimare/meta/cbmr.py +970 -0
  34. nimare/meta/ibma.py +1683 -0
  35. nimare/meta/kernel.py +501 -0
  36. nimare/meta/models.py +1199 -0
  37. nimare/meta/utils.py +494 -0
  38. nimare/nimads.py +492 -0
  39. nimare/reports/__init__.py +24 -0
  40. nimare/reports/base.py +664 -0
  41. nimare/reports/default.yml +123 -0
  42. nimare/reports/figures.py +651 -0
  43. nimare/reports/report.tpl +160 -0
  44. nimare/resources/__init__.py +1 -0
  45. nimare/resources/atlases/Harvard-Oxford-LICENSE +93 -0
  46. nimare/resources/atlases/HarvardOxford-cort-maxprob-thr25-2mm.nii.gz +0 -0
  47. nimare/resources/database_file_manifest.json +142 -0
  48. nimare/resources/english_spellings.csv +1738 -0
  49. nimare/resources/filenames.json +32 -0
  50. nimare/resources/neurosynth_laird_studies.json +58773 -0
  51. nimare/resources/neurosynth_stoplist.txt +396 -0
  52. nimare/resources/nidm_pain_dset.json +1349 -0
  53. nimare/resources/references.bib +541 -0
  54. nimare/resources/semantic_knowledge_children.txt +325 -0
  55. nimare/resources/semantic_relatedness_children.txt +249 -0
  56. nimare/resources/templates/MNI152_2x2x2_brainmask.nii.gz +0 -0
  57. nimare/resources/templates/tpl-MNI152NLin6Asym_res-01_T1w.nii.gz +0 -0
  58. nimare/resources/templates/tpl-MNI152NLin6Asym_res-01_desc-brain_mask.nii.gz +0 -0
  59. nimare/resources/templates/tpl-MNI152NLin6Asym_res-02_T1w.nii.gz +0 -0
  60. nimare/resources/templates/tpl-MNI152NLin6Asym_res-02_desc-brain_mask.nii.gz +0 -0
  61. nimare/results.py +225 -0
  62. nimare/stats.py +276 -0
  63. nimare/tests/__init__.py +1 -0
  64. nimare/tests/conftest.py +229 -0
  65. nimare/tests/data/amygdala_roi.nii.gz +0 -0
  66. nimare/tests/data/data-neurosynth_version-7_coordinates.tsv.gz +0 -0
  67. nimare/tests/data/data-neurosynth_version-7_metadata.tsv.gz +0 -0
  68. nimare/tests/data/data-neurosynth_version-7_vocab-terms_source-abstract_type-tfidf_features.npz +0 -0
  69. nimare/tests/data/data-neurosynth_version-7_vocab-terms_vocabulary.txt +100 -0
  70. nimare/tests/data/neurosynth_dset.json +2868 -0
  71. nimare/tests/data/neurosynth_laird_studies.json +58773 -0
  72. nimare/tests/data/nidm_pain_dset.json +1349 -0
  73. nimare/tests/data/nimads_annotation.json +1 -0
  74. nimare/tests/data/nimads_studyset.json +1 -0
  75. nimare/tests/data/test_baseline.txt +2 -0
  76. nimare/tests/data/test_pain_dataset.json +1278 -0
  77. nimare/tests/data/test_pain_dataset_multiple_contrasts.json +1242 -0
  78. nimare/tests/data/test_sleuth_file.txt +18 -0
  79. nimare/tests/data/test_sleuth_file2.txt +10 -0
  80. nimare/tests/data/test_sleuth_file3.txt +5 -0
  81. nimare/tests/data/test_sleuth_file4.txt +5 -0
  82. nimare/tests/data/test_sleuth_file5.txt +5 -0
  83. nimare/tests/test_annotate_cogat.py +32 -0
  84. nimare/tests/test_annotate_gclda.py +86 -0
  85. nimare/tests/test_annotate_lda.py +27 -0
  86. nimare/tests/test_dataset.py +99 -0
  87. nimare/tests/test_decode_continuous.py +132 -0
  88. nimare/tests/test_decode_discrete.py +92 -0
  89. nimare/tests/test_diagnostics.py +168 -0
  90. nimare/tests/test_estimator_performance.py +385 -0
  91. nimare/tests/test_extract.py +46 -0
  92. nimare/tests/test_generate.py +247 -0
  93. nimare/tests/test_io.py +240 -0
  94. nimare/tests/test_meta_ale.py +298 -0
  95. nimare/tests/test_meta_cbmr.py +295 -0
  96. nimare/tests/test_meta_ibma.py +240 -0
  97. nimare/tests/test_meta_kernel.py +209 -0
  98. nimare/tests/test_meta_mkda.py +234 -0
  99. nimare/tests/test_nimads.py +21 -0
  100. nimare/tests/test_reports.py +110 -0
  101. nimare/tests/test_stats.py +101 -0
  102. nimare/tests/test_transforms.py +272 -0
  103. nimare/tests/test_utils.py +200 -0
  104. nimare/tests/test_workflows.py +221 -0
  105. nimare/tests/utils.py +126 -0
  106. nimare/transforms.py +907 -0
  107. nimare/utils.py +1367 -0
  108. nimare/workflows/__init__.py +14 -0
  109. nimare/workflows/base.py +189 -0
  110. nimare/workflows/cbma.py +165 -0
  111. nimare/workflows/ibma.py +108 -0
  112. nimare/workflows/macm.py +77 -0
  113. nimare/workflows/misc.py +65 -0
  114. nimare-0.4.2rc4.dist-info/LICENSE +21 -0
  115. nimare-0.4.2rc4.dist-info/METADATA +124 -0
  116. nimare-0.4.2rc4.dist-info/RECORD +119 -0
  117. nimare-0.4.2rc4.dist-info/WHEEL +5 -0
  118. nimare-0.4.2rc4.dist-info/entry_points.txt +2 -0
  119. nimare-0.4.2rc4.dist-info/top_level.txt +2 -0
@@ -0,0 +1,14 @@
1
+ """Common meta-analytic workflows."""
2
+
3
+ from .cbma import CBMAWorkflow, PairwiseCBMAWorkflow
4
+ from .ibma import IBMAWorkflow
5
+ from .macm import macm_workflow
6
+ from .misc import conjunction_analysis
7
+
8
+ __all__ = [
9
+ "CBMAWorkflow",
10
+ "PairwiseCBMAWorkflow",
11
+ "IBMAWorkflow",
12
+ "macm_workflow",
13
+ "conjunction_analysis",
14
+ ]
@@ -0,0 +1,189 @@
1
+ """Base class for workflow."""
2
+
3
+ import copy
4
+ import itertools
5
+ import logging
6
+ import os.path as op
7
+ from abc import abstractmethod
8
+
9
+ from nimare.base import NiMAREBase
10
+ from nimare.correct import Corrector, FDRCorrector, FWECorrector
11
+ from nimare.diagnostics import Diagnostics, FocusCounter, Jackknife
12
+ from nimare.meta import ALE, KDA, SCALE, ALESubtraction, MKDAChi2, MKDADensity
13
+ from nimare.meta.cbma.base import PairwiseCBMAEstimator
14
+ from nimare.meta.ibma import (
15
+ DerSimonianLaird,
16
+ Fishers,
17
+ Hedges,
18
+ PermutedOLS,
19
+ SampleSizeBasedLikelihood,
20
+ Stouffers,
21
+ VarianceBasedLikelihood,
22
+ WeightedLeastSquares,
23
+ )
24
+ from nimare.utils import _check_ncores, _check_type
25
+
26
+ LGR = logging.getLogger(__name__)
27
+
28
+ # Match a string to a class name without initializing the class.
29
+ STR_TO_CLASS = {
30
+ "ale": ALE,
31
+ "scale": SCALE,
32
+ "mkdadensity": MKDADensity,
33
+ "kda": KDA,
34
+ "mkdachi2": MKDAChi2,
35
+ "alesubtraction": ALESubtraction,
36
+ "stouffers": Stouffers,
37
+ "fishers": Fishers,
38
+ "permutedols": PermutedOLS,
39
+ "wleastsquares": WeightedLeastSquares,
40
+ "dersimonianlaird": DerSimonianLaird,
41
+ "hedges": Hedges,
42
+ "samplesizebl": SampleSizeBasedLikelihood,
43
+ "variancebl": VarianceBasedLikelihood,
44
+ "montecarlo": FWECorrector,
45
+ "fdr": FDRCorrector,
46
+ "bonferroni": FWECorrector,
47
+ "jackknife": Jackknife,
48
+ "focuscounter": FocusCounter,
49
+ }
50
+
51
+
52
+ def _check_input(obj, clss, options, **kwargs):
53
+ """Check input for workflow functions."""
54
+ if isinstance(obj, str):
55
+ if obj not in options:
56
+ raise ValueError(f'"{obj}" of kind string must be {", ".join(options)}')
57
+
58
+ # Get the class from the string
59
+ obj_str = obj
60
+ obj = STR_TO_CLASS[obj_str]
61
+
62
+ # Add the method to the kwargs if it's a FWECorrector
63
+ if obj == FWECorrector:
64
+ kwargs["method"] = obj_str
65
+
66
+ return _check_type(obj, clss, **kwargs)
67
+
68
+
69
+ class Workflow(NiMAREBase):
70
+ """Base class for workflow methods.
71
+
72
+ .. versionadded:: 0.1.2
73
+ """
74
+
75
+ def __init__(
76
+ self,
77
+ estimator=None,
78
+ corrector=None,
79
+ diagnostics=None,
80
+ voxel_thresh=1.65,
81
+ cluster_threshold=10,
82
+ output_dir=None,
83
+ n_cores=1,
84
+ ):
85
+ self.voxel_thresh = voxel_thresh
86
+ self.cluster_threshold = cluster_threshold
87
+ self.output_dir = output_dir
88
+ self.n_cores = _check_ncores(n_cores)
89
+ self._preprocess_input(estimator, corrector, diagnostics)
90
+
91
+ def _preprocess_input(self, estimator, corrector, diagnostics):
92
+ if not isinstance(diagnostics, list) and diagnostics is not None:
93
+ diagnostics = [diagnostics]
94
+
95
+ # Check inputs and set defaults if input is None
96
+ estimator = (
97
+ self._estm_default(n_cores=self.n_cores)
98
+ if estimator is None
99
+ else _check_input(estimator, self._estm_base, self._estm_options, n_cores=self.n_cores)
100
+ )
101
+
102
+ corrector = (
103
+ self._corr_default(method=self._mcc_method, n_cores=self.n_cores)
104
+ if corrector is None
105
+ else _check_input(corrector, Corrector, self._corr_options, n_cores=self.n_cores)
106
+ )
107
+
108
+ diag_kwargs = {
109
+ "voxel_thresh": self.voxel_thresh,
110
+ "cluster_threshold": self.cluster_threshold,
111
+ "n_cores": self.n_cores,
112
+ }
113
+ if diagnostics is None:
114
+ diagnostics = [self._diag_default(**diag_kwargs)]
115
+ else:
116
+ diagnostics = [
117
+ _check_input(diagnostic, Diagnostics, self._diag_options, **diag_kwargs)
118
+ for diagnostic in diagnostics
119
+ ]
120
+
121
+ pairwaise_workflow = self.__class__.__name__ == "PairwiseCBMAWorkflow"
122
+ if (not pairwaise_workflow) and isinstance(estimator, PairwiseCBMAEstimator):
123
+ raise AttributeError('"CBMAWorkflow" does not work with pairwise Estimators.')
124
+
125
+ self.estimator = estimator
126
+ self.corrector = corrector
127
+ self.diagnostics = diagnostics
128
+
129
+ @abstractmethod
130
+ def fit(self, dataset):
131
+ """Apply estimation to dataset and output results."""
132
+
133
+ def _transform(self, result):
134
+ """Implement the correction procedure and perform diagnostics.
135
+
136
+ Parameters
137
+ ----------
138
+ result : :obj:`~nimare.results.MetaResult`
139
+ MetaResult object from which to extract the p value map and Estimator.
140
+
141
+ Returns
142
+ -------
143
+ :obj:`~nimare.results.MetaResult`
144
+ Results of Estimator, Corrector, and Diagnostics fitting with label maps,
145
+ cluster and diagnostic tables.
146
+ """
147
+ LGR.info("Performing correction on meta-analysis...")
148
+ corr_result = self.corrector.transform(result)
149
+
150
+ LGR.info("Performing diagnostics on corrected meta-analyses...")
151
+ # Perform diagnostic only on desc-mass when using montecarlo correction
152
+ corr_method = corr_result.get_params()["corrector__method"]
153
+
154
+ if issubclass(type(result.estimator), PairwiseCBMAEstimator):
155
+ modalities = (
156
+ ["_desc-associationMass", "_corr-"]
157
+ if corr_method == "montecarlo"
158
+ else ["_desc-", "_corr-"]
159
+ )
160
+ else:
161
+ modalities = ["_desc-mass", "_corr-"] if corr_method == "montecarlo" else ["_corr-"]
162
+
163
+ img_keys = [
164
+ img_key
165
+ for img_key in corr_result.maps.keys()
166
+ if img_key.startswith("z_") and all(mod in img_key for mod in modalities)
167
+ ]
168
+
169
+ for img_key, diagnostic in itertools.product(img_keys, self.diagnostics):
170
+ # Work on copy of diagnostic:
171
+ diagnostic_cp = copy.deepcopy(diagnostic)
172
+ diagnostic_cp = diagnostic_cp.set_params(target_image=img_key)
173
+ corr_result = diagnostic_cp.transform(corr_result)
174
+
175
+ if self.output_dir is not None:
176
+ LGR.info(f"Saving meta-analytic maps, tables and boilerplate to {self.output_dir}...")
177
+ corr_result.save_maps(output_dir=self.output_dir)
178
+ corr_result.save_tables(output_dir=self.output_dir)
179
+
180
+ boilerplate = corr_result.description_
181
+ with open(op.join(self.output_dir, "boilerplate.txt"), "w") as fo:
182
+ fo.write(boilerplate)
183
+
184
+ bibtex = corr_result.bibtex_
185
+ with open(op.join(self.output_dir, "references.bib"), "w") as fo:
186
+ fo.write(bibtex)
187
+
188
+ LGR.info("Workflow completed.")
189
+ return corr_result
@@ -0,0 +1,165 @@
1
+ """Workflow for running an coordinates-based meta-analysis from a NiMARE database."""
2
+
3
+ import logging
4
+
5
+ from nimare.correct import FWECorrector
6
+ from nimare.dataset import Dataset
7
+ from nimare.diagnostics import Jackknife
8
+ from nimare.meta import ALE, MKDAChi2
9
+ from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator
10
+ from nimare.utils import _check_type
11
+ from nimare.workflows.base import Workflow
12
+
13
+ LGR = logging.getLogger(__name__)
14
+
15
+
16
+ class CBMAWorkflow(Workflow):
17
+ """Compose a coordinate-based meta-analysis workflow.
18
+
19
+ .. versionchanged:: 0.1.2
20
+
21
+ - `cbma_workflow` function was converted to CBMAWorkflow class.
22
+
23
+ .. versionadded:: 0.0.14
24
+
25
+ This workflow performs a coordinate-based meta-analysis, multiple comparison corrections,
26
+ and diagnostics analyses on corrected meta-analytic z-score maps.
27
+
28
+ Parameters
29
+ ----------
30
+ estimator : :class:`~nimare.meta.cbma.base.CBMAEstimator`, :obj:`str` {'ale', 'scale', \
31
+ 'mkdadensity', 'kda'}, optional
32
+ Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.ale.ALE`.
33
+ corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', \
34
+ 'bonferroni'}, optional
35
+ Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`.
36
+ diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, \
37
+ :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focuscounter'}, \
38
+ optional
39
+ List of meta-analysis diagnostic classes. A single diagnostic class can also be passed.
40
+ Default is :class:`~nimare.diagnostics.FocusCounter`.
41
+ voxel_thresh : :obj:`float` or None, optional
42
+ An optional voxel-level threshold that may be applied to the ``target_image`` in the
43
+ :class:`~nimare.diagnostics.Diagnostics` class to define clusters. This can be None or 0
44
+ if the ``target_image`` is already thresholded (e.g., a cluster-level corrected map).
45
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
46
+ Default is 1.65, which corresponds to p-value = .05, one-tailed.
47
+ cluster_threshold : :obj:`int` or None, optional
48
+ Cluster size threshold, in :term:`voxels<voxel>`.
49
+ If None, then no cluster size threshold will be applied.
50
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
51
+ Default is 10.
52
+ output_dir : :obj:`str`, optional
53
+ Output directory in which to save results. If the directory doesn't
54
+ exist, it will be created. Default is None (the results are not saved).
55
+ n_cores : :obj:`int`, optional
56
+ Number of cores to use for parallelization.
57
+ If <=0, defaults to using all available cores.
58
+ If estimator, corrector, or diagnostics are passed as initialized objects, this parameter
59
+ will be ignored.
60
+ Default is 1.
61
+ """
62
+
63
+ # Options allows for string input
64
+ _estm_base = CBMAEstimator
65
+ _estm_options = ("ale", "scale", "mkdadensity", "kda")
66
+ _corr_options = ("montecarlo", "fdr", "bonferroni")
67
+ _diag_options = ("jackknife", "focuscounter")
68
+ _mcc_method = "montecarlo"
69
+ _estm_default = ALE
70
+ _corr_default = FWECorrector
71
+ _diag_default = Jackknife
72
+
73
+ def fit(self, dataset, drop_invalid=True):
74
+ """Fit Workflow to a Dataset.
75
+
76
+ Parameters
77
+ ----------
78
+ dataset : :obj:`~nimare.dataset.Dataset`
79
+ Dataset to analyze.
80
+
81
+ Returns
82
+ -------
83
+ :obj:`~nimare.results.MetaResult`
84
+ Results of Estimator fitting.
85
+ """
86
+ # Check dataset type
87
+ dataset = _check_type(dataset, Dataset)
88
+
89
+ LGR.info("Performing meta-analysis...")
90
+ results = self.estimator.fit(dataset, drop_invalid=drop_invalid)
91
+
92
+ return self._transform(results)
93
+
94
+
95
+ class PairwiseCBMAWorkflow(Workflow):
96
+ """Base class for pairwise coordinate-based meta-analysis workflow methods.
97
+
98
+ .. versionadded:: 0.1.2
99
+
100
+ Parameters
101
+ ----------
102
+ estimator : :class:`~nimare.meta.cbma.base.PairwiseCBMAEstimator`, :obj:`str` \
103
+ {'alesubtraction', 'mkdachi2'}, or optional
104
+ Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.kda.MKDAChi2`.
105
+ corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', \
106
+ 'bonferroni'} or optional
107
+ Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`.
108
+ diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, \
109
+ :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focuscounter'}, \
110
+ or optional
111
+ List of meta-analysis diagnostic classes. A single diagnostic class can also be passed.
112
+ Default is :class:`~nimare.diagnostics.FocusCounter`.
113
+ voxel_thresh : :obj:`float` or None, optional
114
+ An optional voxel-level threshold that may be applied to the ``target_image`` in the
115
+ :class:`~nimare.diagnostics.Diagnostics` class to define clusters. This can be None or 0
116
+ if the ``target_image`` is already thresholded (e.g., a cluster-level corrected map).
117
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
118
+ Default is 1.65, which corresponds to p-value = .05, one-tailed.
119
+ cluster_threshold : :obj:`int` or None, optional
120
+ Cluster size threshold, in :term:`voxels<voxel>`.
121
+ If None, then no cluster size threshold will be applied.
122
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
123
+ Default is 10.
124
+ output_dir : :obj:`str`, optional
125
+ Output directory in which to save results. If the directory doesn't
126
+ exist, it will be created. Default is None (the results are not saved).
127
+ n_cores : :obj:`int`, optional
128
+ Number of cores to use for parallelization.
129
+ If <=0, defaults to using all available cores.
130
+ If estimator, corrector, or diagnostics are passed as initialized objects, this parameter
131
+ will be ignored.
132
+ Default is 1.
133
+ """
134
+
135
+ # Options allows for string input
136
+ _estm_base = PairwiseCBMAEstimator
137
+ _estm_options = ("alesubtraction", "mkdachi2")
138
+ _corr_options = ("montecarlo", "fdr", "bonferroni")
139
+ _diag_options = ("jackknife", "focuscounter")
140
+ _mcc_method = "montecarlo"
141
+ _estm_default = MKDAChi2
142
+ _corr_default = FWECorrector
143
+ _diag_default = Jackknife
144
+
145
+ def fit(self, dataset1, dataset2, drop_invalid=True):
146
+ """Fit Workflow to two Datasets.
147
+
148
+ Parameters
149
+ ----------
150
+ dataset1/dataset2 : :obj:`~nimare.dataset.Dataset`
151
+ Dataset objects to analyze.
152
+
153
+ Returns
154
+ -------
155
+ :obj:`~nimare.results.MetaResult`
156
+ Results of Estimator fitting.
157
+ """
158
+ # Check dataset type
159
+ dataset1 = _check_type(dataset1, Dataset)
160
+ dataset2 = _check_type(dataset2, Dataset)
161
+
162
+ LGR.info("Performing meta-analysis...")
163
+ results = self.estimator.fit(dataset1, dataset2, drop_invalid=drop_invalid)
164
+
165
+ return self._transform(results)
@@ -0,0 +1,108 @@
1
+ """Workflow for running an image-based meta-analysis from a NiMARE database."""
2
+
3
+ import logging
4
+
5
+ from nimare.correct import FDRCorrector
6
+ from nimare.dataset import Dataset
7
+ from nimare.diagnostics import Jackknife
8
+ from nimare.meta.ibma import IBMAEstimator, Stouffers
9
+ from nimare.transforms import ImageTransformer
10
+ from nimare.utils import _check_type
11
+ from nimare.workflows.base import Workflow
12
+
13
+ LGR = logging.getLogger(__name__)
14
+
15
+
16
+ class IBMAWorkflow(Workflow):
17
+ """Compose a coordinate-based meta-analysis workflow.
18
+
19
+ .. versionadded:: 0.2.0
20
+
21
+ This workflow performs a coordinate-based meta-analysis, multiple comparison corrections,
22
+ and diagnostics analyses on corrected meta-analytic z-score maps.
23
+
24
+ Parameters
25
+ ----------
26
+ estimator : :class:`~nimare.meta.ibma.IBMAEstimator`, :obj:`str` {'stouffers', 'fishers', \
27
+ 'hedges', 'permutedols', 'wleastsquares', 'dersimonianlaird', 'samplesizebl'. 'variancebl'}, \
28
+ or optional
29
+ Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.ale.ALE`.
30
+ corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', \
31
+ 'bonferroni'} or optional
32
+ Meta-analysis corrector. Default is :class:`~nimare.correct.FDRCorrector`.
33
+ diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, \
34
+ :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife'}, \
35
+ or optional
36
+ List of meta-analysis diagnostic classes. A single diagnostic class can also be passed.
37
+ Default is :class:`~nimare.diagnostics.FocusCounter`.
38
+ voxel_thresh : :obj:`float` or None, optional
39
+ An optional voxel-level threshold that may be applied to the ``target_image`` in the
40
+ :class:`~nimare.diagnostics.Diagnostics` class to define clusters. This can be None or 0
41
+ if the ``target_image`` is already thresholded (e.g., a cluster-level corrected map).
42
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
43
+ Default is 1.65, which corresponds to p-value = .05, one-tailed.
44
+ cluster_threshold : :obj:`int` or None, optional
45
+ Cluster size threshold, in :term:`voxels<voxel>`.
46
+ If None, then no cluster size threshold will be applied.
47
+ If diagnostics are passed as initialized objects, this parameter will be ignored.
48
+ Default is 10.
49
+ output_dir : :obj:`str`, optional
50
+ Output directory in which to save results. If the directory doesn't
51
+ exist, it will be created. Default is None (the results are not saved).
52
+ n_cores : :obj:`int`, optional
53
+ Number of cores to use for parallelization.
54
+ If <=0, defaults to using all available cores.
55
+ If estimator, corrector, or diagnostics are passed as initialized objects, this parameter
56
+ will be ignored.
57
+ Default is 1.
58
+ """
59
+
60
+ # Options allows for string input
61
+ _estm_base = IBMAEstimator
62
+ _estm_options = (
63
+ "stouffers",
64
+ "fishers",
65
+ "permutedols",
66
+ "wleastsquares",
67
+ "dersimonianlaird",
68
+ "hedges",
69
+ "samplesizebl",
70
+ "variancebl",
71
+ )
72
+ _corr_options = ("montecarlo", "fdr", "bonferroni")
73
+ _diag_options = "jackknife"
74
+ _mcc_method = "indep"
75
+ _estm_default = Stouffers
76
+ _corr_default = FDRCorrector
77
+ _diag_default = Jackknife
78
+
79
+ def fit(self, dataset, drop_invalid=True):
80
+ """Fit Workflow to a Dataset.
81
+
82
+ Parameters
83
+ ----------
84
+ dataset : :obj:`~nimare.dataset.Dataset`
85
+ Dataset to analyze.
86
+
87
+ Returns
88
+ -------
89
+ :obj:`~nimare.results.MetaResult`
90
+ Results of Estimator fitting.
91
+ """
92
+ # Check dataset type
93
+ dataset = _check_type(dataset, Dataset)
94
+
95
+ # Calculate missing images. Possible targets: {"z", "p", "beta", "varcope"}.
96
+ # Infer from self.estimator._required_inputs
97
+ targets = [
98
+ target
99
+ for _, (type_, target) in self.estimator._required_inputs.items()
100
+ if type_ == "image"
101
+ ]
102
+ xformer = ImageTransformer(target=targets)
103
+ dataset = xformer.transform(dataset)
104
+
105
+ LGR.info("Performing meta-analysis...")
106
+ results = self.estimator.fit(dataset, drop_invalid=drop_invalid)
107
+
108
+ return self._transform(results)
@@ -0,0 +1,77 @@
1
+ """Perform MACM with ALE algorithm."""
2
+
3
+ import logging
4
+ import os
5
+ import pathlib
6
+ from shutil import copyfile
7
+
8
+ from nimare.correct import FWECorrector
9
+ from nimare.dataset import Dataset
10
+ from nimare.meta import ALE
11
+
12
+ LGR = logging.getLogger(__name__)
13
+
14
+
15
+ def macm_workflow(
16
+ dataset_file,
17
+ mask_file,
18
+ output_dir=None,
19
+ prefix=None,
20
+ n_iters=5000,
21
+ v_thr=0.001,
22
+ n_cores=1,
23
+ ):
24
+ """Perform MACM with ALE algorithm."""
25
+ LGR.info("Loading coordinates...")
26
+ dset = Dataset(dataset_file)
27
+ sel_ids = dset.get_studies_by_mask(mask_file)
28
+ sel_dset = dset.slice(sel_ids)
29
+ n_foci_db = dset.coordinates.shape[0]
30
+ n_foci_sel = sel_dset.coordinates.shape[0]
31
+ n_exps_db = len(dset.ids)
32
+ n_exps_sel = len(sel_dset.ids)
33
+
34
+ LGR.info("Performing meta-analysis...")
35
+ ale = ALE()
36
+ results = ale.fit(sel_dset)
37
+ corr = FWECorrector(method="montecarlo", n_iters=n_iters, voxel_thresh=v_thr, n_cores=n_cores)
38
+ cres = corr.transform(results)
39
+
40
+ boilerplate = cres.description_
41
+
42
+ boilerplate = (
43
+ "A meta-analytic connectivity modeling (MACM; "
44
+ "\\citealt{laird2009investigating,robinson2010metaanalytic,eickhoff2010anatomical}) "
45
+ "analysis was performed. "
46
+ f"The input dataset included {n_foci_db} foci across {n_exps_db} experiments, "
47
+ "from which experiments were selected for analysis if they had at least one focus inside "
48
+ "the target mask. "
49
+ f"The resulting sample included {n_foci_sel} foci across {n_exps_sel} experiments. "
50
+ ) + boilerplate
51
+
52
+ # Inject the composite description into the ALESubtraction MetaResult to trigger
53
+ # a re-compilation of references
54
+ cres.description_ = boilerplate
55
+ bibtex = cres.bibtex_ # This will now include references from all three analyses
56
+
57
+ if output_dir is None:
58
+ output_dir = os.path.abspath(os.path.dirname(dataset_file))
59
+ else:
60
+ pathlib.Path(output_dir).mkdir(parents=True, exist_ok=True)
61
+
62
+ if prefix is None:
63
+ base = os.path.basename(dataset_file)
64
+ prefix, _ = os.path.splitext(base)
65
+ prefix += "_"
66
+
67
+ LGR.info("Saving output maps...")
68
+ cres.save_maps(output_dir=output_dir, prefix=prefix)
69
+ copyfile(dataset_file, os.path.join(output_dir, prefix + "input_dataset.json"))
70
+
71
+ with open(os.path.join(output_dir, prefix + "boilerplate.txt"), "w") as fo:
72
+ fo.write(boilerplate)
73
+
74
+ with open(os.path.join(output_dir, prefix + "references.bib"), "w") as fo:
75
+ fo.write(bibtex)
76
+
77
+ LGR.info("Workflow completed.")
@@ -0,0 +1,65 @@
1
+ """Miscellaneous Workflows."""
2
+
3
+ import logging
4
+
5
+ import nibabel as nib
6
+ from nilearn._utils import check_niimg_3d
7
+ from nilearn.image import math_img
8
+
9
+ LGR = logging.getLogger(__name__)
10
+
11
+
12
+ def conjunction_analysis(imgs):
13
+ """Perform a conjunction analysis.
14
+
15
+ .. versionadded:: 0.2.0
16
+
17
+ This method is described in :footcite:t:`nichols2005valid`.
18
+
19
+ Parameters
20
+ ----------
21
+ imgs : :obj:`list` of 3D :obj:`~nibabel.nifti1.Nifti1Image`, or :obj:`list` of :obj:`str`
22
+ List of images upon which to perform the conjuction analysis.
23
+ If a list of strings is provided, it is assumed to be paths to NIfTI images.
24
+
25
+ Returns
26
+ -------
27
+ :obj:`~nibabel.nifti1.Nifti1Image`
28
+ Conjunction image.
29
+
30
+ References
31
+ ----------
32
+ .. footbibliography::
33
+ """
34
+ if len(imgs) < 2:
35
+ raise ValueError("Conjunction analysis requires more than one image.")
36
+
37
+ imgs_dict = {}
38
+ mult_formula, min_formula = "", ""
39
+ for img_i, img_obj in enumerate(imgs):
40
+ if isinstance(img_obj, str):
41
+ img = nib.load(img_obj)
42
+ elif isinstance(img_obj, nib.Nifti1Image):
43
+ img = img_obj
44
+ else:
45
+ raise ValueError(
46
+ f"Invalid image type provided: {type(img_obj)}. Must be a path to a NIfTI image "
47
+ "or a NIfTI image object."
48
+ )
49
+
50
+ img = check_niimg_3d(img)
51
+
52
+ img_label = f"img{img_i}"
53
+ imgs_dict[img_label] = img
54
+ mult_formula += img_label
55
+ min_formula += img_label
56
+
57
+ if img_i != len(imgs) - 1:
58
+ mult_formula += " * "
59
+ min_formula += ", "
60
+
61
+ formula = f"np.where({mult_formula} > 0, np.minimum.reduce([{min_formula}]), 0)"
62
+ LGR.info("Performing conjunction analysis...")
63
+ LGR.info(f"Formula: {formula}")
64
+
65
+ return math_img(formula, **imgs_dict)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 NiMARE developers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.