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.
- benchmarks/__init__.py +0 -0
- benchmarks/bench_cbma.py +57 -0
- nimare/__init__.py +45 -0
- nimare/_version.py +21 -0
- nimare/annotate/__init__.py +21 -0
- nimare/annotate/cogat.py +213 -0
- nimare/annotate/gclda.py +924 -0
- nimare/annotate/lda.py +147 -0
- nimare/annotate/text.py +75 -0
- nimare/annotate/utils.py +87 -0
- nimare/base.py +217 -0
- nimare/cli.py +124 -0
- nimare/correct.py +462 -0
- nimare/dataset.py +685 -0
- nimare/decode/__init__.py +33 -0
- nimare/decode/base.py +115 -0
- nimare/decode/continuous.py +462 -0
- nimare/decode/discrete.py +753 -0
- nimare/decode/encode.py +110 -0
- nimare/decode/utils.py +44 -0
- nimare/diagnostics.py +510 -0
- nimare/estimator.py +139 -0
- nimare/extract/__init__.py +19 -0
- nimare/extract/extract.py +466 -0
- nimare/extract/utils.py +295 -0
- nimare/generate.py +331 -0
- nimare/io.py +635 -0
- nimare/meta/__init__.py +39 -0
- nimare/meta/cbma/__init__.py +6 -0
- nimare/meta/cbma/ale.py +951 -0
- nimare/meta/cbma/base.py +947 -0
- nimare/meta/cbma/mkda.py +1361 -0
- nimare/meta/cbmr.py +970 -0
- nimare/meta/ibma.py +1683 -0
- nimare/meta/kernel.py +501 -0
- nimare/meta/models.py +1199 -0
- nimare/meta/utils.py +494 -0
- nimare/nimads.py +492 -0
- nimare/reports/__init__.py +24 -0
- nimare/reports/base.py +664 -0
- nimare/reports/default.yml +123 -0
- nimare/reports/figures.py +651 -0
- nimare/reports/report.tpl +160 -0
- nimare/resources/__init__.py +1 -0
- nimare/resources/atlases/Harvard-Oxford-LICENSE +93 -0
- nimare/resources/atlases/HarvardOxford-cort-maxprob-thr25-2mm.nii.gz +0 -0
- nimare/resources/database_file_manifest.json +142 -0
- nimare/resources/english_spellings.csv +1738 -0
- nimare/resources/filenames.json +32 -0
- nimare/resources/neurosynth_laird_studies.json +58773 -0
- nimare/resources/neurosynth_stoplist.txt +396 -0
- nimare/resources/nidm_pain_dset.json +1349 -0
- nimare/resources/references.bib +541 -0
- nimare/resources/semantic_knowledge_children.txt +325 -0
- nimare/resources/semantic_relatedness_children.txt +249 -0
- nimare/resources/templates/MNI152_2x2x2_brainmask.nii.gz +0 -0
- nimare/resources/templates/tpl-MNI152NLin6Asym_res-01_T1w.nii.gz +0 -0
- nimare/resources/templates/tpl-MNI152NLin6Asym_res-01_desc-brain_mask.nii.gz +0 -0
- nimare/resources/templates/tpl-MNI152NLin6Asym_res-02_T1w.nii.gz +0 -0
- nimare/resources/templates/tpl-MNI152NLin6Asym_res-02_desc-brain_mask.nii.gz +0 -0
- nimare/results.py +225 -0
- nimare/stats.py +276 -0
- nimare/tests/__init__.py +1 -0
- nimare/tests/conftest.py +229 -0
- nimare/tests/data/amygdala_roi.nii.gz +0 -0
- nimare/tests/data/data-neurosynth_version-7_coordinates.tsv.gz +0 -0
- nimare/tests/data/data-neurosynth_version-7_metadata.tsv.gz +0 -0
- nimare/tests/data/data-neurosynth_version-7_vocab-terms_source-abstract_type-tfidf_features.npz +0 -0
- nimare/tests/data/data-neurosynth_version-7_vocab-terms_vocabulary.txt +100 -0
- nimare/tests/data/neurosynth_dset.json +2868 -0
- nimare/tests/data/neurosynth_laird_studies.json +58773 -0
- nimare/tests/data/nidm_pain_dset.json +1349 -0
- nimare/tests/data/nimads_annotation.json +1 -0
- nimare/tests/data/nimads_studyset.json +1 -0
- nimare/tests/data/test_baseline.txt +2 -0
- nimare/tests/data/test_pain_dataset.json +1278 -0
- nimare/tests/data/test_pain_dataset_multiple_contrasts.json +1242 -0
- nimare/tests/data/test_sleuth_file.txt +18 -0
- nimare/tests/data/test_sleuth_file2.txt +10 -0
- nimare/tests/data/test_sleuth_file3.txt +5 -0
- nimare/tests/data/test_sleuth_file4.txt +5 -0
- nimare/tests/data/test_sleuth_file5.txt +5 -0
- nimare/tests/test_annotate_cogat.py +32 -0
- nimare/tests/test_annotate_gclda.py +86 -0
- nimare/tests/test_annotate_lda.py +27 -0
- nimare/tests/test_dataset.py +99 -0
- nimare/tests/test_decode_continuous.py +132 -0
- nimare/tests/test_decode_discrete.py +92 -0
- nimare/tests/test_diagnostics.py +168 -0
- nimare/tests/test_estimator_performance.py +385 -0
- nimare/tests/test_extract.py +46 -0
- nimare/tests/test_generate.py +247 -0
- nimare/tests/test_io.py +240 -0
- nimare/tests/test_meta_ale.py +298 -0
- nimare/tests/test_meta_cbmr.py +295 -0
- nimare/tests/test_meta_ibma.py +240 -0
- nimare/tests/test_meta_kernel.py +209 -0
- nimare/tests/test_meta_mkda.py +234 -0
- nimare/tests/test_nimads.py +21 -0
- nimare/tests/test_reports.py +110 -0
- nimare/tests/test_stats.py +101 -0
- nimare/tests/test_transforms.py +272 -0
- nimare/tests/test_utils.py +200 -0
- nimare/tests/test_workflows.py +221 -0
- nimare/tests/utils.py +126 -0
- nimare/transforms.py +907 -0
- nimare/utils.py +1367 -0
- nimare/workflows/__init__.py +14 -0
- nimare/workflows/base.py +189 -0
- nimare/workflows/cbma.py +165 -0
- nimare/workflows/ibma.py +108 -0
- nimare/workflows/macm.py +77 -0
- nimare/workflows/misc.py +65 -0
- nimare-0.4.2rc4.dist-info/LICENSE +21 -0
- nimare-0.4.2rc4.dist-info/METADATA +124 -0
- nimare-0.4.2rc4.dist-info/RECORD +119 -0
- nimare-0.4.2rc4.dist-info/WHEEL +5 -0
- nimare-0.4.2rc4.dist-info/entry_points.txt +2 -0
- 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
|
+
]
|
nimare/workflows/base.py
ADDED
@@ -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
|
nimare/workflows/cbma.py
ADDED
@@ -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)
|
nimare/workflows/ibma.py
ADDED
@@ -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)
|
nimare/workflows/macm.py
ADDED
@@ -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.")
|
nimare/workflows/misc.py
ADDED
@@ -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.
|