From 94a92cce1504cf7509d7082f832bfe158bc913b4 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Mon, 23 Jan 2023 16:48:07 -0500 Subject: [PATCH 01/32] Add `cbma_workflow` function --- nimare/results.py | 2 +- nimare/tests/test_workflows.py | 41 +++++++++++++++++ nimare/workflows/__init__.py | 3 +- nimare/workflows/cbma.py | 84 ++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 nimare/workflows/cbma.py diff --git a/nimare/results.py b/nimare/results.py index 25cb034ff..57514e780 100644 --- a/nimare/results.py +++ b/nimare/results.py @@ -148,7 +148,7 @@ def save_tables(self, output_dir=".", prefix="", prefix_sep="_", names=None): tables = {k: self.tables[k] for k in names} for tabletype, table in tables.items(): - filename = prefix + tables + ".tsv" + filename = prefix + tabletype + ".tsv" outpath = os.path.join(output_dir, filename) table.to_csv(outpath, sep="\t", index=False) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 98de585a6..471567e6c 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -1,7 +1,11 @@ """Test nimare.workflows.""" import os.path as op +import nimare from nimare import cli, workflows +from nimare.correct import FWECorrector +from nimare.diagnostics import FocusCounter +from nimare.meta.cbma.ale import ALE from nimare.tests.utils import get_test_data_path @@ -81,3 +85,40 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): ] ) assert op.isfile(op.join(tmpdir, f"{prefix}_group2_input_coordinates.txt")) + + +def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): + """Run smoke test for CBMA workflow.""" + tmpdir = tmp_path_factory.mktemp("test_cbma_workflow_function_smoke") + + # Initialize estimator, corrector and diagnostic classes + est = ALE(null_method="approximate") + corr = FWECorrector(method="montecarlo", n_iters=100) + diag = FocusCounter() + + cres = workflows.cbma_workflow( + testdata_cbma_full, + meta_estimator=est, + corrector=corr, + diagnostics=(diag,), + output_dir=tmpdir, + ) + + assert isinstance(cres, nimare.results.MetaResult) + + assert "cluster_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "cluster_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "cluster_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "FocusCounter_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "FocusCounter_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "FocusCounter_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() + + for imgtype in cres.maps.keys(): + filename = imgtype + ".nii.gz" + outpath = op.join(tmpdir, filename) + assert op.isfile(outpath) + + for tabletype in cres.tables.keys(): + filename = tabletype + ".tsv" + outpath = op.join(tmpdir, filename) + assert op.isfile(outpath) diff --git a/nimare/workflows/__init__.py b/nimare/workflows/__init__.py index ecc0c2ab6..4c18a433c 100644 --- a/nimare/workflows/__init__.py +++ b/nimare/workflows/__init__.py @@ -1,6 +1,7 @@ """Common meta-analytic workflows.""" from .ale import ale_sleuth_workflow +from .cbma import cbma_workflow from .macm import macm_workflow -__all__ = ["ale_sleuth_workflow", "macm_workflow"] +__all__ = ["ale_sleuth_workflow", "cbma_workflow", "macm_workflow"] diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py new file mode 100644 index 000000000..b5bef791f --- /dev/null +++ b/nimare/workflows/cbma.py @@ -0,0 +1,84 @@ +"""Workflow for running an coordinates-based meta-analysis from a NiMARE database.""" +import logging + +from nilearn import reporting + +from nimare.correct import FWECorrector +from nimare.diagnostics import FocusCounter +from nimare.meta import ALE + +LGR = logging.getLogger(__name__) + + +def cbma_workflow( + dataset, + meta_estimator=ALE(), + corrector=FWECorrector(), + diagnostics=(FocusCounter(),), + output_dir=None, +): + """Compose a coordinate-based meta-analysis workflow. + + .. versionadded:: 0.0.14 + + This workflow performs a coordinate-based meta-analysis, multiple comparison correction, + and diagnosis analysis on corrected meta-analytic images. + + Parameters + ---------- + dataset : :obj:`~nimare.dataset.Dataset` + Dataset for which to run meta-analyses to generate maps. + meta_estimator : :class:`~nimare.base.CBMAEstimator`, optional + Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.ale.ALE`. + meta_corrector : :class:`~nimare.correct.Corrector`, optional + Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`. + diagnostics : :obj:`tuple`, optional + Tuple of meta-analysis diagnostic classes. + Default is :class:`~nimare.diagnostics.FocusCounter`. + output_dir : :obj:`str`, optional + Output directory in which to save results. If the directory doesn't + exist, it will be created. Default is None (the results are not saved). + + Returns + ------- + :obj:`~nimare.results.MetaResult` + Results of Estimator and Corrector fitting with cluster and diagnostic tables. + """ + LGR.info("Performing meta-analysis...") + results = meta_estimator.fit(dataset) + + LGR.info("Performing correction on meta-analysis...") + corr_results = corrector.transform(results) + + for img_key in corr_results.maps.keys(): + # Save cluster table only for z maps + if img_key.startswith("z_"): + cbma_img = corr_results.get_map(img_key) + + LGR.info("Generating cluster tables...") + cluster_df = reporting.get_clusters_table(cbma_img, stat_threshold=0) + # Remove prefix from name + img_name = "_".join(img_key.split("_")[1:]) + + if not cluster_df.empty: + clust_tbl_name = f"cluster_{img_name}" + corr_results.tables[clust_tbl_name] = cluster_df + + # Run diagnostic on corrected z maps + if "_corr-" in img_key: + for diagnostic in diagnostics: + diagnostic.target_image = img_key + + LGR.info("Performing diagnostic on corrected meta-analysis...") + count_df, _ = diagnostic.transform(corr_results) + + if not count_df.empty: + diag_tbl_name = f"{diagnostic.__class__.__name__}_{img_name}" + corr_results.tables[diag_tbl_name] = count_df + + if output_dir is not None: + LGR.info(f"Saving meta-result object to {output_dir}...") + corr_results.save_maps(output_dir=output_dir) + corr_results.save_tables(output_dir=output_dir) + + return corr_results From f3411117cff28d70b67b865cc1bf81f1da62d7bf Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Mon, 23 Jan 2023 16:57:25 -0500 Subject: [PATCH 02/32] Fix typo --- nimare/workflows/cbma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index b5bef791f..9d511f4df 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -22,7 +22,7 @@ def cbma_workflow( .. versionadded:: 0.0.14 This workflow performs a coordinate-based meta-analysis, multiple comparison correction, - and diagnosis analysis on corrected meta-analytic images. + and diagnostics analyses on corrected meta-analytic images. Parameters ---------- From 24c8de1ec9891e871f1fe82d66487cbb0756b44c Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Wed, 25 Jan 2023 09:58:07 -0500 Subject: [PATCH 03/32] @jdkent Apply suggestions from code review --- nimare/workflows/cbma.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 9d511f4df..16aa49ba0 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -22,7 +22,7 @@ def cbma_workflow( .. versionadded:: 0.0.14 This workflow performs a coordinate-based meta-analysis, multiple comparison correction, - and diagnostics analyses on corrected meta-analytic images. + and diagnostics analyses on corrected meta-analytic maps. Parameters ---------- @@ -50,34 +50,41 @@ def cbma_workflow( LGR.info("Performing correction on meta-analysis...") corr_results = corrector.transform(results) + LGR.info("Generating cluster tables and performing diagnostics on corrected meta-analyses...") for img_key in corr_results.maps.keys(): # Save cluster table only for z maps if img_key.startswith("z_"): cbma_img = corr_results.get_map(img_key) - - LGR.info("Generating cluster tables...") cluster_df = reporting.get_clusters_table(cbma_img, stat_threshold=0) + # Remove prefix from name img_name = "_".join(img_key.split("_")[1:]) - + clust_tbl_name = f"cluster_{img_name}" if not cluster_df.empty: - clust_tbl_name = f"cluster_{img_name}" corr_results.tables[clust_tbl_name] = cluster_df + else: + LGR.warn( + f"Key {clust_tbl_name} will not be stored in MetaResult.tables dictionary." + ) # Run diagnostic on corrected z maps if "_corr-" in img_key: + LGR.info("Performing diagnostic on corrected meta-analysis...") for diagnostic in diagnostics: diagnostic.target_image = img_key - - LGR.info("Performing diagnostic on corrected meta-analysis...") count_df, _ = diagnostic.transform(corr_results) + diag_tbl_name = f"{diagnostic.__class__.__name__}_{img_name}" if not count_df.empty: - diag_tbl_name = f"{diagnostic.__class__.__name__}_{img_name}" corr_results.tables[diag_tbl_name] = count_df + else: + LGR.warn( + f"Key {diag_tbl_name} will not be stored in " + "MetaResult.tables dictionary." + ) if output_dir is not None: - LGR.info(f"Saving meta-result object to {output_dir}...") + LGR.info(f"Saving meta-analytic maps and tables result to {output_dir}...") corr_results.save_maps(output_dir=output_dir) corr_results.save_tables(output_dir=output_dir) From 97779a5836297337bb5d57816d7d945de19ec3d4 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 14 Mar 2023 11:07:58 -0400 Subject: [PATCH 04/32] take clusters table from diagnostics --- nimare/tests/test_workflows.py | 10 +++---- nimare/workflows/cbma.py | 51 +++++++++++++--------------------- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 471567e6c..65cb4d7fa 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -4,7 +4,7 @@ import nimare from nimare import cli, workflows from nimare.correct import FWECorrector -from nimare.diagnostics import FocusCounter +from nimare.diagnostics import Jackknife from nimare.meta.cbma.ale import ALE from nimare.tests.utils import get_test_data_path @@ -94,7 +94,7 @@ def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): # Initialize estimator, corrector and diagnostic classes est = ALE(null_method="approximate") corr = FWECorrector(method="montecarlo", n_iters=100) - diag = FocusCounter() + diag = Jackknife() cres = workflows.cbma_workflow( testdata_cbma_full, @@ -109,9 +109,9 @@ def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): assert "cluster_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() assert "cluster_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() assert "cluster_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "FocusCounter_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "FocusCounter_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "FocusCounter_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "Jackknife_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "Jackknife_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "Jackknife_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() for imgtype in cres.maps.keys(): filename = imgtype + ".nii.gz" diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 16aa49ba0..adc0f368a 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -1,10 +1,8 @@ """Workflow for running an coordinates-based meta-analysis from a NiMARE database.""" import logging -from nilearn import reporting - from nimare.correct import FWECorrector -from nimare.diagnostics import FocusCounter +from nimare.diagnostics import Jackknife from nimare.meta import ALE LGR = logging.getLogger(__name__) @@ -14,7 +12,7 @@ def cbma_workflow( dataset, meta_estimator=ALE(), corrector=FWECorrector(), - diagnostics=(FocusCounter(),), + diagnostics=(Jackknife(),), output_dir=None, ): """Compose a coordinate-based meta-analysis workflow. @@ -50,38 +48,27 @@ def cbma_workflow( LGR.info("Performing correction on meta-analysis...") corr_results = corrector.transform(results) - LGR.info("Generating cluster tables and performing diagnostics on corrected meta-analyses...") + LGR.info("Generating clusters tables and performing diagnostics on corrected meta-analyses...") for img_key in corr_results.maps.keys(): # Save cluster table only for z maps - if img_key.startswith("z_"): - cbma_img = corr_results.get_map(img_key) - cluster_df = reporting.get_clusters_table(cbma_img, stat_threshold=0) - - # Remove prefix from name + if img_key.startswith("z_") and ("_corr-" in img_key): img_name = "_".join(img_key.split("_")[1:]) - clust_tbl_name = f"cluster_{img_name}" - if not cluster_df.empty: - corr_results.tables[clust_tbl_name] = cluster_df - else: - LGR.warn( - f"Key {clust_tbl_name} will not be stored in MetaResult.tables dictionary." - ) - - # Run diagnostic on corrected z maps - if "_corr-" in img_key: - LGR.info("Performing diagnostic on corrected meta-analysis...") - for diagnostic in diagnostics: - diagnostic.target_image = img_key - count_df, _ = diagnostic.transform(corr_results) - diag_tbl_name = f"{diagnostic.__class__.__name__}_{img_name}" - if not count_df.empty: - corr_results.tables[diag_tbl_name] = count_df - else: - LGR.warn( - f"Key {diag_tbl_name} will not be stored in " - "MetaResult.tables dictionary." - ) + for diagnostic in diagnostics: + diagnostic.target_image = img_key + contribution_table, cluster_df, _ = diagnostic.transform(corr_results) + + diag_name = diagnostic.__class__.__name__ + clust_tbl_name = f"cluster_{img_name}" + diag_tbl_name = f"{diag_name}_{img_name}" + if not contribution_table.empty: + corr_results.tables[clust_tbl_name] = cluster_df + corr_results.tables[diag_tbl_name] = contribution_table + else: + LGR.warn( + f"Key {diag_tbl_name} and {clust_tbl_name} will not be stored in " + "MetaResult.tables dictionary." + ) if output_dir is not None: LGR.info(f"Saving meta-analytic maps and tables result to {output_dir}...") From 7af5adce2100b51e9af597982dca070db4caf86e Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 13:01:07 -0400 Subject: [PATCH 05/32] Add example to gallery --- docs/api.rst | 1 + .../02_meta-analyses/10_plot_cbma_workflow.py | 84 +++++++++++++++++++ nimare/workflows/cbma.py | 53 +++++++----- 3 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 examples/02_meta-analyses/10_plot_cbma_workflow.py diff --git a/docs/api.rst b/docs/api.rst index 39f4261b9..01e496322 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -310,6 +310,7 @@ For more information about fetching data from the internet, see :ref:`fetching t workflows.ale_sleuth_workflow workflows.macm_workflow + workflows.cbma_workflow .. _api_base_ref: diff --git a/examples/02_meta-analyses/10_plot_cbma_workflow.py b/examples/02_meta-analyses/10_plot_cbma_workflow.py new file mode 100644 index 000000000..b8626c375 --- /dev/null +++ b/examples/02_meta-analyses/10_plot_cbma_workflow.py @@ -0,0 +1,84 @@ +""" + +.. _cbma_workflow: + +==================================================== +Run a coordinate-based meta-analysis (CBMA) workflow +==================================================== + +NiMARE provides a plethora of tools for performing meta-analyses on neuroimaging data. +Sometimes it's difficult to know where to start, especially if you're new to meta-analysis. +This tutorial will walk you through using a CBMA workflow function which puts together +the fundamental steps of a CBMA meta-analysis. +""" +import os +from pprint import pprint + +import matplotlib.pyplot as plt +from nilearn.plotting import plot_stat_map + +from nimare.dataset import Dataset +from nimare.utils import get_resource_path +from nimare.workflows import cbma_workflow + +############################################################################### +# Load Dataset +# ----------------------------------------------------------------------------- + +dset_file = os.path.join(get_resource_path(), "nidm_pain_dset.json") +dset = Dataset(dset_file) + +############################################################################### +# Run CBMA Workflow +# ----------------------------------------------------------------------------- +# The CBMA workflow function runs the following steps: +# +# 1. Runs a meta-analysis using the specified method (default: ALE) +# 2. Applies a corrector to the meta-analysis results (default: FWECorrector) +# 3. Generates cluster tables and runs diagnostics on the corrected results (default: Jackknife) +# +# All in one function call! + +result = cbma_workflow(dset) + +############################################################################### +# Plot Results +# ----------------------------------------------------------------------------- +# The CBMA workflow function returns a :class:`~nimare.results.MetaResult` object, +# where you can access the corrected results of the meta-analysis and diagnostics tables. +# +# Corrected map: +img = result.get_map("z_corr-FWE_method-bonferroni") +plot_stat_map( + img, + cut_coords=4, + display_mode="z", + threshold=2.326, # cluster-level p < .01, one-tailed + cmap="RdBu_r", + vmax=4, +) +plt.show() + +############################################################################### +# Clusters table +# `````````````````````````````````````````````````````````````````````````````` +result.tables["z_corr-FWE_method-bonferroni_clust"] + +############################################################################### +# Contribution table +# `````````````````````````````````````````````````````````````````````````````` +result.tables["z_corr-FWE_method-bonferroni_Jackknife"] + +############################################################################### +# Methods +# ----------------------------------------------------------------------------- +# The MetaResult object also provides boilerplate text automatically generated by NiMARE, +# which is released under the `CC0 `_ license. +print("Description:") +pprint(result.description_) + +############################################################################### +# References +# `````````````````````````````````````````````````````````````````````````````` +print("References:") +pprint(result.bibtex_) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index adc0f368a..5acfbdaf3 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -1,5 +1,7 @@ """Workflow for running an coordinates-based meta-analysis from a NiMARE database.""" +import itertools import logging +import os.path as op from nimare.correct import FWECorrector from nimare.diagnostics import Jackknife @@ -10,7 +12,7 @@ def cbma_workflow( dataset, - meta_estimator=ALE(), + meta_estimator=ALE(null_method="approximate"), corrector=FWECorrector(), diagnostics=(Jackknife(),), output_dir=None, @@ -49,30 +51,39 @@ def cbma_workflow( corr_results = corrector.transform(results) LGR.info("Generating clusters tables and performing diagnostics on corrected meta-analyses...") - for img_key in corr_results.maps.keys(): - # Save cluster table only for z maps - if img_key.startswith("z_") and ("_corr-" in img_key): - img_name = "_".join(img_key.split("_")[1:]) + img_keys = [ + img_key + for img_key in corr_results.maps.keys() + if img_key.startswith("z_") and ("_corr-" in img_key) + ] + for img_key, diagnostic in itertools.product(img_keys, diagnostics): + diagnostic.target_image = img_key + contribution_table, clusters_table, _ = diagnostic.transform(corr_results) - for diagnostic in diagnostics: - diagnostic.target_image = img_key - contribution_table, cluster_df, _ = diagnostic.transform(corr_results) - - diag_name = diagnostic.__class__.__name__ - clust_tbl_name = f"cluster_{img_name}" - diag_tbl_name = f"{diag_name}_{img_name}" - if not contribution_table.empty: - corr_results.tables[clust_tbl_name] = cluster_df - corr_results.tables[diag_tbl_name] = contribution_table - else: - LGR.warn( - f"Key {diag_tbl_name} and {clust_tbl_name} will not be stored in " - "MetaResult.tables dictionary." - ) + diag_name = diagnostic.__class__.__name__ + clust_tbl_name = f"{img_key}_clust" + count_tbl_name = f"{img_key}_{diag_name}" + if not contribution_table.empty: + corr_results.tables[clust_tbl_name] = clusters_table + corr_results.tables[count_tbl_name] = contribution_table + else: + LGR.warn( + f"Key {count_tbl_name} and {clust_tbl_name} will not be stored in " + "MetaResult.tables dictionary." + ) if output_dir is not None: - LGR.info(f"Saving meta-analytic maps and tables result to {output_dir}...") + LGR.info(f"Saving meta-analytic maps, tables and boilerplate to {output_dir}...") corr_results.save_maps(output_dir=output_dir) corr_results.save_tables(output_dir=output_dir) + boilerplate = corr_results.description_ + with open(op.join(output_dir, "boilerplate.txt"), "w") as fo: + fo.write(boilerplate) + + bibtex = corr_results.bibtex_ + with open(op.join(output_dir, "references.bib"), "w") as fo: + fo.write(bibtex) + + LGR.info("Workflow completed.") return corr_results From e35143f7c437cd6a52815211f1c0e02afe0b583c Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 13:03:57 -0400 Subject: [PATCH 06/32] Update cbma.py --- nimare/workflows/cbma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 5acfbdaf3..dd1703938 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -12,7 +12,7 @@ def cbma_workflow( dataset, - meta_estimator=ALE(null_method="approximate"), + meta_estimator=ALE(), corrector=FWECorrector(), diagnostics=(Jackknife(),), output_dir=None, From cd1df83354ebbf2c4d6762547bf87feb25f68e30 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 15:39:01 -0400 Subject: [PATCH 07/32] support string inputs --- nimare/tests/test_workflows.py | 12 +++--- nimare/workflows/cbma.py | 68 ++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 65cb4d7fa..21f5336a2 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -106,12 +106,12 @@ def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): assert isinstance(cres, nimare.results.MetaResult) - assert "cluster_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "cluster_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "cluster_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "Jackknife_desc-mass_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "Jackknife_desc-size_level-cluster_corr-FWE_method-montecarlo" in cres.tables.keys() - assert "Jackknife_level-voxel_corr-FWE_method-montecarlo" in cres.tables.keys() + assert "z_desc-mass_level-cluster_corr-FWE_method-montecarlo_clust" in cres.tables.keys() + assert "z_desc-size_level-cluster_corr-FWE_method-montecarlo_clust" in cres.tables.keys() + assert "z_level-voxel_corr-FWE_method-montecarlo_clust" in cres.tables.keys() + assert "z_desc-mass_level-cluster_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() + assert "z_desc-size_level-cluster_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() + assert "z_level-voxel_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() for imgtype in cres.maps.keys(): filename = imgtype + ".nii.gz" diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index dd1703938..34f980198 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -1,18 +1,22 @@ """Workflow for running an coordinates-based meta-analysis from a NiMARE database.""" +import inspect import itertools import logging import os.path as op -from nimare.correct import FWECorrector -from nimare.diagnostics import Jackknife +from nimare.correct import Corrector, FWECorrector +from nimare.dataset import Dataset +from nimare.diagnostics import Diagnostics, Jackknife from nimare.meta import ALE +from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator +from nimare.utils import _check_type LGR = logging.getLogger(__name__) def cbma_workflow( dataset, - meta_estimator=ALE(), + estimator=None, corrector=FWECorrector(), diagnostics=(Jackknife(),), output_dir=None, @@ -28,11 +32,13 @@ def cbma_workflow( ---------- dataset : :obj:`~nimare.dataset.Dataset` Dataset for which to run meta-analyses to generate maps. - meta_estimator : :class:`~nimare.base.CBMAEstimator`, optional + estimator : :class:`~nimare.base.CBMAEstimator`, :obj:`str` {'ale', 'scale', 'mkdadensity', + 'kda'}, or optional Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.ale.ALE`. - meta_corrector : :class:`~nimare.correct.Corrector`, optional + corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', 'bonferroni'} + or optional Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`. - diagnostics : :obj:`tuple`, optional + diagnostics : :obj:`tuple`, :obj:`str` {'jackknife', 'focusCounter'}, or optional Tuple of meta-analysis diagnostic classes. Default is :class:`~nimare.diagnostics.FocusCounter`. output_dir : :obj:`str`, optional @@ -44,8 +50,56 @@ def cbma_workflow( :obj:`~nimare.results.MetaResult` Results of Estimator and Corrector fitting with cluster and diagnostic tables. """ + # Check dataset type + dataset = _check_type(dataset, Dataset) + + # Options allows for string input + estm_options = ("ale", "scale", "mkdadensity", "kda") + corr_options = ("montecarlo", "fdr", "bonferroni") + diag_options = ("jackknife", "focuscounter") + + # Check estimator type + if estimator is None: + estimator = ALE() + elif inspect.isclass(estimator): + estimator = _check_type(estimator, CBMAEstimator) + elif isinstance(estimator, str): + if estimator not in estm_options: + raise ValueError(f'"estimator" of kind string must be {", ".join(estm_options)}') + else: + raise ValueError( + f'"estimator" is {type(estimator)}, it must be a kind of CBMAEstimator, or a string.' + ) + + # Check corrector type + if inspect.isclass(corrector): + corrector = _check_type(corrector, Corrector) + elif isinstance(corrector, str): + if corrector not in corr_options: + raise ValueError(f'"corrector" of kind string must be {", ".join(corr_options)}') + else: + raise ValueError( + f'"corrector" is {type(corrector)}, it must be a kind of Corrector, or a string.' + ) + + # Check diagnostics type + if inspect.isclass(diagnostics): + diagnostics = _check_type(diagnostics, Diagnostics) + elif isinstance(diagnostics, str): + if diagnostics not in diag_options: + raise ValueError(f'"diagnostics" of kind string must be {", ".join(diag_options)}') + else: + raise ValueError( + f'"diagnostics" is {type(diagnostics)}, it must be a kind of Diagnostics, or a string.' + ) + + if isinstance(estimator, PairwiseCBMAEstimator): + raise AttributeError( + "The cbma_workflow function does not currently work with pairwise Estimators." + ) + LGR.info("Performing meta-analysis...") - results = meta_estimator.fit(dataset) + results = estimator.fit(dataset) LGR.info("Performing correction on meta-analysis...") corr_results = corrector.transform(results) From 9649f049e4534a1a7c3f12fa0ff47f7a1440be06 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 16:04:17 -0400 Subject: [PATCH 08/32] refactor code --- nimare/workflows/cbma.py | 67 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 34f980198..b9df7fb7e 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -14,11 +14,28 @@ LGR = logging.getLogger(__name__) +def _collect_class(obj, clss): + """Collect a class from a module.""" + pass + + +def _check_input(obj, clss, options): + if inspect.isclass(obj): + obj = _check_type(obj, clss) + elif isinstance(obj, str): + if obj not in options: + raise ValueError(f'"estimator" of kind string must be {", ".join(options)}') + obj = _collect_class(obj, clss) + else: + raise ValueError(f'"estimator" is {type(obj)}, it must be a kind of {clss}, or a string.') + return obj + + def cbma_workflow( dataset, estimator=None, - corrector=FWECorrector(), - diagnostics=(Jackknife(),), + corrector=None, + diagnostics=None, output_dir=None, ): """Compose a coordinate-based meta-analysis workflow. @@ -58,40 +75,18 @@ def cbma_workflow( corr_options = ("montecarlo", "fdr", "bonferroni") diag_options = ("jackknife", "focuscounter") - # Check estimator type - if estimator is None: - estimator = ALE() - elif inspect.isclass(estimator): - estimator = _check_type(estimator, CBMAEstimator) - elif isinstance(estimator, str): - if estimator not in estm_options: - raise ValueError(f'"estimator" of kind string must be {", ".join(estm_options)}') - else: - raise ValueError( - f'"estimator" is {type(estimator)}, it must be a kind of CBMAEstimator, or a string.' - ) - - # Check corrector type - if inspect.isclass(corrector): - corrector = _check_type(corrector, Corrector) - elif isinstance(corrector, str): - if corrector not in corr_options: - raise ValueError(f'"corrector" of kind string must be {", ".join(corr_options)}') - else: - raise ValueError( - f'"corrector" is {type(corrector)}, it must be a kind of Corrector, or a string.' - ) - - # Check diagnostics type - if inspect.isclass(diagnostics): - diagnostics = _check_type(diagnostics, Diagnostics) - elif isinstance(diagnostics, str): - if diagnostics not in diag_options: - raise ValueError(f'"diagnostics" of kind string must be {", ".join(diag_options)}') - else: - raise ValueError( - f'"diagnostics" is {type(diagnostics)}, it must be a kind of Diagnostics, or a string.' - ) + # Check inputs and set defaults + estimator = ( + ALE() if corrector is None else _check_input(corrector, CBMAEstimator, estm_options) + ) + corrector = ( + FWECorrector() if corrector is None else _check_input(corrector, Corrector, corr_options) + ) + diagnostics = ( + (Jackknife(),) + if diagnostics is None + else _check_input(diagnostics, Diagnostics, diag_options) + ) if isinstance(estimator, PairwiseCBMAEstimator): raise AttributeError( From 1652329edded85e56c95acafeb663520a8d4e8bb Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 16:10:01 -0400 Subject: [PATCH 09/32] Update cbma.py --- nimare/workflows/cbma.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index b9df7fb7e..c3722fa8e 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -14,7 +14,7 @@ LGR = logging.getLogger(__name__) -def _collect_class(obj, clss): +def _collect_class(str_name, base_clss): """Collect a class from a module.""" pass @@ -77,7 +77,7 @@ def cbma_workflow( # Check inputs and set defaults estimator = ( - ALE() if corrector is None else _check_input(corrector, CBMAEstimator, estm_options) + ALE() if estimator is None else _check_input(estimator, CBMAEstimator, estm_options) ) corrector = ( FWECorrector() if corrector is None else _check_input(corrector, Corrector, corr_options) From 1c6a268c329afdd0c03bcb2c5691d99ce60ed851 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 17:23:31 -0400 Subject: [PATCH 10/32] [skip CI] support n_cores --- nimare/workflows/cbma.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index c3722fa8e..7fb1319d1 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -9,7 +9,7 @@ from nimare.diagnostics import Diagnostics, Jackknife from nimare.meta import ALE from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator -from nimare.utils import _check_type +from nimare.utils import _check_ncores, _check_type LGR = logging.getLogger(__name__) @@ -19,13 +19,13 @@ def _collect_class(str_name, base_clss): pass -def _check_input(obj, clss, options): +def _check_input(obj, clss, options, **kwargs): if inspect.isclass(obj): - obj = _check_type(obj, clss) + obj = _check_type(obj, clss, **kwargs) elif isinstance(obj, str): if obj not in options: raise ValueError(f'"estimator" of kind string must be {", ".join(options)}') - obj = _collect_class(obj, clss) + obj = _collect_class(obj, clss, **kwargs) else: raise ValueError(f'"estimator" is {type(obj)}, it must be a kind of {clss}, or a string.') return obj @@ -37,6 +37,7 @@ def cbma_workflow( corrector=None, diagnostics=None, output_dir=None, + n_cores=1, ): """Compose a coordinate-based meta-analysis workflow. @@ -61,12 +62,18 @@ def cbma_workflow( output_dir : :obj:`str`, optional Output directory in which to save results. If the directory doesn't exist, it will be created. Default is None (the results are not saved). + n_cores : :obj:`int`, optional + Number of cores to use for parallelization. + If <=0, defaults to using all available cores. + Default is 1. Returns ------- :obj:`~nimare.results.MetaResult` Results of Estimator and Corrector fitting with cluster and diagnostic tables. """ + n_cores = _check_ncores(n_cores) + # Check dataset type dataset = _check_type(dataset, Dataset) @@ -75,22 +82,26 @@ def cbma_workflow( corr_options = ("montecarlo", "fdr", "bonferroni") diag_options = ("jackknife", "focuscounter") - # Check inputs and set defaults + # Check inputs and set defaults if input is None estimator = ( - ALE() if estimator is None else _check_input(estimator, CBMAEstimator, estm_options) + ALE(n_cores=n_cores) + if estimator is None + else _check_input(estimator, CBMAEstimator, estm_options, n_cores=n_cores) ) corrector = ( - FWECorrector() if corrector is None else _check_input(corrector, Corrector, corr_options) + FWECorrector(method="montecarlo", n_cores=n_cores) + if corrector is None + else _check_input(corrector, Corrector, corr_options, n_cores=n_cores) ) diagnostics = ( - (Jackknife(),) + (Jackknife(n_cores=n_cores),) if diagnostics is None - else _check_input(diagnostics, Diagnostics, diag_options) + else _check_input(diagnostics, Diagnostics, diag_options, n_cores=n_cores) ) if isinstance(estimator, PairwiseCBMAEstimator): raise AttributeError( - "The cbma_workflow function does not currently work with pairwise Estimators." + 'The "cbma_workflow" function does not currently work with pairwise Estimators.' ) LGR.info("Performing meta-analysis...") From 5d24099f09972094f9630b6f971bc6c3b7f77901 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 21:06:39 -0400 Subject: [PATCH 11/32] [skip ci] map string to classes --- nimare/tests/test_workflows.py | 9 +++---- nimare/workflows/cbma.py | 44 +++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 21f5336a2..c80cdb1ae 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -92,13 +92,14 @@ def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): tmpdir = tmp_path_factory.mktemp("test_cbma_workflow_function_smoke") # Initialize estimator, corrector and diagnostic classes - est = ALE(null_method="approximate") - corr = FWECorrector(method="montecarlo", n_iters=100) - diag = Jackknife() + est = ALE + # corr = FWECorrector(method="montecarlo", n_iters=100) + corr = "montecarlo" + diag = Jackknife cres = workflows.cbma_workflow( testdata_cbma_full, - meta_estimator=est, + estimator=est, corrector=corr, diagnostics=(diag,), output_dir=tmpdir, diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 7fb1319d1..dc4246eee 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -4,31 +4,47 @@ import logging import os.path as op -from nimare.correct import Corrector, FWECorrector +from nimare.correct import Corrector, FDRCorrector, FWECorrector from nimare.dataset import Dataset -from nimare.diagnostics import Diagnostics, Jackknife -from nimare.meta import ALE +from nimare.diagnostics import FocusCounter, Jackknife +from nimare.meta import ALE, KDA, SCALE, MKDADensity from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator from nimare.utils import _check_ncores, _check_type LGR = logging.getLogger(__name__) -def _collect_class(str_name, base_clss): - """Collect a class from a module.""" - pass +def _str_to_class(str_name): + """Match a string to a class name without initializing the class.""" + classes = { + "ale": ALE, + "scale": SCALE, + "mkdadensity": MKDADensity, + "kda": KDA, + "montecarlo": FWECorrector, + "fdr": FDRCorrector, + "bonferroni": FWECorrector, + "jackknife": Jackknife, + "focuscounter": FocusCounter, + } + return classes[str_name] def _check_input(obj, clss, options, **kwargs): - if inspect.isclass(obj): - obj = _check_type(obj, clss, **kwargs) - elif isinstance(obj, str): + """Check input for workflow functions.""" + if isinstance(obj, str): if obj not in options: raise ValueError(f'"estimator" of kind string must be {", ".join(options)}') - obj = _collect_class(obj, clss, **kwargs) - else: - raise ValueError(f'"estimator" is {type(obj)}, it must be a kind of {clss}, or a string.') - return obj + + # Get the class from the string + obj_str = obj + obj = _str_to_class(obj_str) + + # Add the method to the kwargs if it's a FWECorrector + if obj == FWECorrector: + kwargs["method"] = obj_str + + return _check_type(obj, clss, **kwargs) def cbma_workflow( @@ -96,7 +112,7 @@ def cbma_workflow( diagnostics = ( (Jackknife(n_cores=n_cores),) if diagnostics is None - else _check_input(diagnostics, Diagnostics, diag_options, n_cores=n_cores) + else _check_input(diagnostics, Jackknife, diag_options, n_cores=n_cores) ) if isinstance(estimator, PairwiseCBMAEstimator): From 81ea6b35f7fa42a2641aa6ad04c855551801fcdd Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 22:00:13 -0400 Subject: [PATCH 12/32] [skip ci] test possible combinations --- nimare/tests/test_workflows.py | 55 ++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index c80cdb1ae..056e046f9 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -1,11 +1,13 @@ """Test nimare.workflows.""" import os.path as op +import pytest + import nimare from nimare import cli, workflows from nimare.correct import FWECorrector -from nimare.diagnostics import Jackknife -from nimare.meta.cbma.ale import ALE +from nimare.diagnostics import FocusCounter, Jackknife +from nimare.meta.cbma import ALE, MKDAChi2 from nimare.tests.utils import get_test_data_path @@ -87,33 +89,40 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): assert op.isfile(op.join(tmpdir, f"{prefix}_group2_input_coordinates.txt")) -def test_cbma_workflow_function_smoke(tmp_path_factory, testdata_cbma_full): +@pytest.mark.parametrize( + "estimator,corrector,diagnostics", + [ + (ALE, FWECorrector(method="montecarlo", n_iters=100), [Jackknife]), + ("ale" "bonferroni", [Jackknife, FocusCounter]), + ("kda", "fdr", Jackknife), + (MKDAChi2, "montecarlo", "focusCounter"), + ], +) +def test_cbma_workflow_function_smoke( + tmp_path_factory, testdata_cbma_full, estimator, corrector, diagnostics +): """Run smoke test for CBMA workflow.""" tmpdir = tmp_path_factory.mktemp("test_cbma_workflow_function_smoke") - # Initialize estimator, corrector and diagnostic classes - est = ALE - # corr = FWECorrector(method="montecarlo", n_iters=100) - corr = "montecarlo" - diag = Jackknife - - cres = workflows.cbma_workflow( - testdata_cbma_full, - estimator=est, - corrector=corr, - diagnostics=(diag,), - output_dir=tmpdir, - ) + if estimator == MKDAChi2: + with pytest.raises(AttributeError): + workflows.cbma_workflow( + testdata_cbma_full, + estimator=estimator, + corrector=corrector, + diagnostics=diagnostics, + ) + else: + cres = workflows.cbma_workflow( + testdata_cbma_full, + estimator=estimator, + corrector=corrector, + diagnostics=diagnostics, + output_dir=tmpdir, + ) assert isinstance(cres, nimare.results.MetaResult) - assert "z_desc-mass_level-cluster_corr-FWE_method-montecarlo_clust" in cres.tables.keys() - assert "z_desc-size_level-cluster_corr-FWE_method-montecarlo_clust" in cres.tables.keys() - assert "z_level-voxel_corr-FWE_method-montecarlo_clust" in cres.tables.keys() - assert "z_desc-mass_level-cluster_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() - assert "z_desc-size_level-cluster_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() - assert "z_level-voxel_corr-FWE_method-montecarlo_Jackknife" in cres.tables.keys() - for imgtype in cres.maps.keys(): filename = imgtype + ".nii.gz" outpath = op.join(tmpdir, filename) From d3a878bc2e065e313221bc67cae7f94c7aba99ee Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Thu, 16 Mar 2023 22:05:39 -0400 Subject: [PATCH 13/32] [skip CI] Also support single diagnostic class --- nimare/workflows/cbma.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index dc4246eee..bb2854e6e 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -1,12 +1,11 @@ """Workflow for running an coordinates-based meta-analysis from a NiMARE database.""" -import inspect import itertools import logging import os.path as op from nimare.correct import Corrector, FDRCorrector, FWECorrector from nimare.dataset import Dataset -from nimare.diagnostics import FocusCounter, Jackknife +from nimare.diagnostics import Diagnostics, FocusCounter, Jackknife from nimare.meta import ALE, KDA, SCALE, MKDADensity from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator from nimare.utils import _check_ncores, _check_type @@ -72,8 +71,9 @@ def cbma_workflow( corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', 'bonferroni'} or optional Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`. - diagnostics : :obj:`tuple`, :obj:`str` {'jackknife', 'focusCounter'}, or optional - Tuple of meta-analysis diagnostic classes. + diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, + :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focusCounter'}, or optional + List of meta-analysis diagnostic classes. A single diagnostic class can also be passed. Default is :class:`~nimare.diagnostics.FocusCounter`. output_dir : :obj:`str`, optional Output directory in which to save results. If the directory doesn't @@ -81,6 +81,8 @@ def cbma_workflow( n_cores : :obj:`int`, optional Number of cores to use for parallelization. If <=0, defaults to using all available cores. + If estimator, corrector, or diagnostics are passed as initialized objects, this parameter + will be ignored. Default is 1. Returns @@ -90,6 +92,9 @@ def cbma_workflow( """ n_cores = _check_ncores(n_cores) + if not isinstance(diagnostics, list) and diagnostics is not None: + diagnostics = [diagnostics] + # Check dataset type dataset = _check_type(dataset, Dataset) @@ -109,11 +114,14 @@ def cbma_workflow( if corrector is None else _check_input(corrector, Corrector, corr_options, n_cores=n_cores) ) - diagnostics = ( - (Jackknife(n_cores=n_cores),) - if diagnostics is None - else _check_input(diagnostics, Jackknife, diag_options, n_cores=n_cores) - ) + + if diagnostics is None: + diagnostics = [FocusCounter(n_cores=n_cores)] + else: + diagnostics = [ + _check_input(diagnostic, Diagnostics, diag_options, n_cores=n_cores) + for diagnostic in diagnostics + ] if isinstance(estimator, PairwiseCBMAEstimator): raise AttributeError( From 4615ebf156a7222668954036fe0611e8c057000f Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 10:43:36 -0400 Subject: [PATCH 14/32] Use FDR in the example --- .../02_meta-analyses/10_plot_cbma_workflow.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/02_meta-analyses/10_plot_cbma_workflow.py b/examples/02_meta-analyses/10_plot_cbma_workflow.py index b8626c375..e696bdb4c 100644 --- a/examples/02_meta-analyses/10_plot_cbma_workflow.py +++ b/examples/02_meta-analyses/10_plot_cbma_workflow.py @@ -34,12 +34,15 @@ # The CBMA workflow function runs the following steps: # # 1. Runs a meta-analysis using the specified method (default: ALE) -# 2. Applies a corrector to the meta-analysis results (default: FWECorrector) +# 2. Applies a corrector to the meta-analysis results (default: FWECorrector, montecarlo) # 3. Generates cluster tables and runs diagnostics on the corrected results (default: Jackknife) # # All in one function call! - -result = cbma_workflow(dset) +# result = cbma_workflow(dset) +# For this example, we use an FDR correction because the default corrector (FWE correction with +# Monte Carlo simulation) takes a long time to run due to the high number of iterations that +# are required +result = cbma_workflow(dset, corrector="fdr") ############################################################################### # Plot Results @@ -48,7 +51,7 @@ # where you can access the corrected results of the meta-analysis and diagnostics tables. # # Corrected map: -img = result.get_map("z_corr-FWE_method-bonferroni") +img = result.get_map("z_corr-FDR") plot_stat_map( img, cut_coords=4, @@ -62,12 +65,12 @@ ############################################################################### # Clusters table # `````````````````````````````````````````````````````````````````````````````` -result.tables["z_corr-FWE_method-bonferroni_clust"] +result.tables["z_corr-FDR_clust"] ############################################################################### # Contribution table # `````````````````````````````````````````````````````````````````````````````` -result.tables["z_corr-FWE_method-bonferroni_Jackknife"] +result.tables["z_corr-FDR_Jackknife"] ############################################################################### # Methods From 373fd2295eb23b46f410d072d30ae6f9ed1391e7 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 14:41:25 -0400 Subject: [PATCH 15/32] Update test_workflows.py --- nimare/tests/test_workflows.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 056e046f9..b70b66916 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -122,6 +122,8 @@ def test_cbma_workflow_function_smoke( ) assert isinstance(cres, nimare.results.MetaResult) + assert op.isfile(op.join(tmpdir, "boilerplate.txt")) + assert op.isfile(op.join(tmpdir, "references.bib")) for imgtype in cres.maps.keys(): filename = imgtype + ".nii.gz" From 6317595a9e4d1eed14cd9929db06b06752f1d258 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 14:47:46 -0400 Subject: [PATCH 16/32] Update test_workflows.py --- nimare/tests/test_workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index b70b66916..01cdc4ea5 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -93,7 +93,7 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): "estimator,corrector,diagnostics", [ (ALE, FWECorrector(method="montecarlo", n_iters=100), [Jackknife]), - ("ale" "bonferroni", [Jackknife, FocusCounter]), + ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), (MKDAChi2, "montecarlo", "focusCounter"), ], From 5318cca9b1955fef3e3b0eaea8f059b1fc0b4e88 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 15:00:13 -0400 Subject: [PATCH 17/32] fix tests --- nimare/tests/test_workflows.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 01cdc4ea5..de3ab20d6 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -95,7 +95,7 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): (ALE, FWECorrector(method="montecarlo", n_iters=100), [Jackknife]), ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), - (MKDAChi2, "montecarlo", "focusCounter"), + (MKDAChi2, "montecarlo", "focuscounter"), ], ) def test_cbma_workflow_function_smoke( @@ -121,16 +121,16 @@ def test_cbma_workflow_function_smoke( output_dir=tmpdir, ) - assert isinstance(cres, nimare.results.MetaResult) - assert op.isfile(op.join(tmpdir, "boilerplate.txt")) - assert op.isfile(op.join(tmpdir, "references.bib")) + assert isinstance(cres, nimare.results.MetaResult) + assert op.isfile(op.join(tmpdir, "boilerplate.txt")) + assert op.isfile(op.join(tmpdir, "references.bib")) - for imgtype in cres.maps.keys(): - filename = imgtype + ".nii.gz" - outpath = op.join(tmpdir, filename) - assert op.isfile(outpath) + for imgtype in cres.maps.keys(): + filename = imgtype + ".nii.gz" + outpath = op.join(tmpdir, filename) + assert op.isfile(outpath) - for tabletype in cres.tables.keys(): - filename = tabletype + ".tsv" - outpath = op.join(tmpdir, filename) - assert op.isfile(outpath) + for tabletype in cres.tables.keys(): + filename = tabletype + ".tsv" + outpath = op.join(tmpdir, filename) + assert op.isfile(outpath) From 51bbef13328f1a5c574b3c4cf98438c38de36440 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 15:00:41 -0400 Subject: [PATCH 18/32] Update test_workflows.py --- nimare/tests/test_workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index de3ab20d6..241ecdf7f 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -92,7 +92,7 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): @pytest.mark.parametrize( "estimator,corrector,diagnostics", [ - (ALE, FWECorrector(method="montecarlo", n_iters=100), [Jackknife]), + (ALE, FWECorrector(method="montecarlo", n_iters=10), [Jackknife]), ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), (MKDAChi2, "montecarlo", "focuscounter"), From 5fa9327b7b693c38050690c80c4bcc4f6c1ef2bc Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 15:05:49 -0400 Subject: [PATCH 19/32] Use warning instead of warn --- nimare/workflows/cbma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index bb2854e6e..7c2979829 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -151,7 +151,7 @@ def cbma_workflow( corr_results.tables[clust_tbl_name] = clusters_table corr_results.tables[count_tbl_name] = contribution_table else: - LGR.warn( + LGR.warning( f"Key {count_tbl_name} and {clust_tbl_name} will not be stored in " "MetaResult.tables dictionary." ) From dd5246137712f56838174749092a2f4adbeeca3b Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 16:03:37 -0400 Subject: [PATCH 20/32] Set default voxel_thresh for diagnostics --- examples/02_meta-analyses/10_plot_cbma_workflow.py | 8 ++++---- nimare/workflows/cbma.py | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/02_meta-analyses/10_plot_cbma_workflow.py b/examples/02_meta-analyses/10_plot_cbma_workflow.py index e696bdb4c..a85ffbcb5 100644 --- a/examples/02_meta-analyses/10_plot_cbma_workflow.py +++ b/examples/02_meta-analyses/10_plot_cbma_workflow.py @@ -51,12 +51,12 @@ # where you can access the corrected results of the meta-analysis and diagnostics tables. # # Corrected map: -img = result.get_map("z_corr-FDR") +img = result.get_map("z_corr-FDR_method-indep") plot_stat_map( img, cut_coords=4, display_mode="z", - threshold=2.326, # cluster-level p < .01, one-tailed + threshold=3.1, # cluster-level p < 0.001, one-tailed cmap="RdBu_r", vmax=4, ) @@ -65,12 +65,12 @@ ############################################################################### # Clusters table # `````````````````````````````````````````````````````````````````````````````` -result.tables["z_corr-FDR_clust"] +result.tables["z_corr-FDR_method-indep_clust"] ############################################################################### # Contribution table # `````````````````````````````````````````````````````````````````````````````` -result.tables["z_corr-FDR_Jackknife"] +result.tables["z_corr-FDR_method-indep_Jackknife"] ############################################################################### # Methods diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 7c2979829..10bc3d7ac 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -8,6 +8,7 @@ from nimare.diagnostics import Diagnostics, FocusCounter, Jackknife from nimare.meta import ALE, KDA, SCALE, MKDADensity from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator +from nimare.transforms import p_to_z from nimare.utils import _check_ncores, _check_type LGR = logging.getLogger(__name__) @@ -115,11 +116,13 @@ def cbma_workflow( else _check_input(corrector, Corrector, corr_options, n_cores=n_cores) ) + pval = 0.05 if corrector.method == "montecarlo" else 0.001 + vthr = p_to_z(pval, tail="one") # Set voxel_thresh for diagnostics if diagnostics is None: - diagnostics = [FocusCounter(n_cores=n_cores)] + diagnostics = [Jackknife(voxel_thresh=vthr, n_cores=n_cores)] else: diagnostics = [ - _check_input(diagnostic, Diagnostics, diag_options, n_cores=n_cores) + _check_input(diagnostic, Diagnostics, diag_options, voxel_thresh=vthr, n_cores=n_cores) for diagnostic in diagnostics ] From 6e74b0cb3d616c1baa85f8e16eae64220014b61c Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 16:15:04 -0400 Subject: [PATCH 21/32] Update diagnostics.py --- nimare/diagnostics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index af421c8ec..583c549b9 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -73,7 +73,7 @@ def transform(self, result): """ none_contribution_table = False if not hasattr(result.estimator, "dataset"): - LGR.warn( + LGR.warning( "MetaResult was not generated by an Estimator with a `dataset` attribute. " "This may be because the Estimator was a pairwise Estimator. The " "Jackknife/FocusCounter method does not currently work with pairwise Estimators. " From b004ef4fc4bc2128acd8799fe49fcfcaae309637 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Fri, 17 Mar 2023 16:45:52 -0400 Subject: [PATCH 22/32] update doc, fix typo --- examples/02_meta-analyses/10_plot_cbma_workflow.py | 2 ++ nimare/workflows/cbma.py | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/02_meta-analyses/10_plot_cbma_workflow.py b/examples/02_meta-analyses/10_plot_cbma_workflow.py index a85ffbcb5..bf02fb3a7 100644 --- a/examples/02_meta-analyses/10_plot_cbma_workflow.py +++ b/examples/02_meta-analyses/10_plot_cbma_workflow.py @@ -38,7 +38,9 @@ # 3. Generates cluster tables and runs diagnostics on the corrected results (default: Jackknife) # # All in one function call! +# # result = cbma_workflow(dset) +# # For this example, we use an FDR correction because the default corrector (FWE correction with # Monte Carlo simulation) takes a long time to run due to the high number of iterations that # are required diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 10bc3d7ac..a25b8d402 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -66,14 +66,15 @@ def cbma_workflow( ---------- dataset : :obj:`~nimare.dataset.Dataset` Dataset for which to run meta-analyses to generate maps. - estimator : :class:`~nimare.base.CBMAEstimator`, :obj:`str` {'ale', 'scale', 'mkdadensity', + estimator : :class:`~nimare.base.CBMAEstimator`, :obj:`str` {'ale', 'scale', 'mkdadensity', \ 'kda'}, or optional Meta-analysis estimator. Default is :class:`~nimare.meta.cbma.ale.ALE`. - corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', 'bonferroni'} - or optional + corrector : :class:`~nimare.correct.Corrector`, :obj:`str` {'montecarlo', 'fdr', \ + 'bonferroni'} or optional Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`. - diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, - :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focusCounter'}, or optional + diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, \ + :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focusCounter'}, \ + or optional List of meta-analysis diagnostic classes. A single diagnostic class can also be passed. Default is :class:`~nimare.diagnostics.FocusCounter`. output_dir : :obj:`str`, optional @@ -150,7 +151,7 @@ def cbma_workflow( diag_name = diagnostic.__class__.__name__ clust_tbl_name = f"{img_key}_clust" count_tbl_name = f"{img_key}_{diag_name}" - if not contribution_table.empty: + if not clusters_table.empty: corr_results.tables[clust_tbl_name] = clusters_table corr_results.tables[count_tbl_name] = contribution_table else: From 2c2fddae80e00e644965834ed411ea3f6ce86bc8 Mon Sep 17 00:00:00 2001 From: "Julio A. Peraza" <52050407+JulioAPeraza@users.noreply.github.com> Date: Sat, 18 Mar 2023 08:59:48 -0400 Subject: [PATCH 23/32] Update nimare/workflows/cbma.py Co-authored-by: James Kent --- nimare/workflows/cbma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index a25b8d402..29ac8ab2a 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -73,7 +73,7 @@ def cbma_workflow( 'bonferroni'} or optional Meta-analysis corrector. Default is :class:`~nimare.correct.FWECorrector`. diagnostics : :obj:`list` of :class:`~nimare.diagnostics.Diagnostics`, \ - :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focusCounter'}, \ + :class:`~nimare.diagnostics.Diagnostics`, :obj:`str` {'jackknife', 'focuscounter'}, \ or optional List of meta-analysis diagnostic classes. A single diagnostic class can also be passed. Default is :class:`~nimare.diagnostics.FocusCounter`. From 244abba535a0e86c8d32d3f6bcb417ee9e5372dc Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 21 Mar 2023 22:07:43 -0400 Subject: [PATCH 24/32] Skips None in save_tables() --- nimare/results.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nimare/results.py b/nimare/results.py index 73841f190..2272c841a 100644 --- a/nimare/results.py +++ b/nimare/results.py @@ -179,7 +179,10 @@ def save_tables(self, output_dir=".", prefix="", prefix_sep="_", names=None): for tabletype, table in tables.items(): filename = prefix + tabletype + ".tsv" outpath = os.path.join(output_dir, filename) - table.to_csv(outpath, sep="\t", index=False) + if table is not None: + table.to_csv(outpath, sep="\t", index=False) + else: + LGR.warning(f"Table {tabletype} is None. Not saving.") def copy(self): """Return copy of result object.""" From dd143fc61765ab891b37a2829ea859167cbb9cfb Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 21 Mar 2023 22:08:10 -0400 Subject: [PATCH 25/32] Add empty tables and none to dict too --- nimare/workflows/cbma.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 29ac8ab2a..fa54bb647 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -8,7 +8,6 @@ from nimare.diagnostics import Diagnostics, FocusCounter, Jackknife from nimare.meta import ALE, KDA, SCALE, MKDADensity from nimare.meta.cbma.base import CBMAEstimator, PairwiseCBMAEstimator -from nimare.transforms import p_to_z from nimare.utils import _check_ncores, _check_type LGR = logging.getLogger(__name__) @@ -117,13 +116,11 @@ def cbma_workflow( else _check_input(corrector, Corrector, corr_options, n_cores=n_cores) ) - pval = 0.05 if corrector.method == "montecarlo" else 0.001 - vthr = p_to_z(pval, tail="one") # Set voxel_thresh for diagnostics if diagnostics is None: - diagnostics = [Jackknife(voxel_thresh=vthr, n_cores=n_cores)] + diagnostics = [Jackknife(n_cores=n_cores)] else: diagnostics = [ - _check_input(diagnostic, Diagnostics, diag_options, voxel_thresh=vthr, n_cores=n_cores) + _check_input(diagnostic, Diagnostics, diag_options, n_cores=n_cores) for diagnostic in diagnostics ] @@ -149,16 +146,8 @@ def cbma_workflow( contribution_table, clusters_table, _ = diagnostic.transform(corr_results) diag_name = diagnostic.__class__.__name__ - clust_tbl_name = f"{img_key}_clust" - count_tbl_name = f"{img_key}_{diag_name}" - if not clusters_table.empty: - corr_results.tables[clust_tbl_name] = clusters_table - corr_results.tables[count_tbl_name] = contribution_table - else: - LGR.warning( - f"Key {count_tbl_name} and {clust_tbl_name} will not be stored in " - "MetaResult.tables dictionary." - ) + corr_results.tables[f"{img_key}_clust"] = clusters_table + corr_results.tables[f"{img_key}_{diag_name}"] = contribution_table if output_dir is not None: LGR.info(f"Saving meta-analytic maps, tables and boilerplate to {output_dir}...") From 58d00e74d3b60335dc898ea19dfebb5255497d04 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 19:19:23 -0400 Subject: [PATCH 26/32] Add voxel_thresh and cluster_threshold parameters --- nimare/workflows/cbma.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index fa54bb647..53a0a198c 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -51,6 +51,8 @@ def cbma_workflow( estimator=None, corrector=None, diagnostics=None, + voxel_thresh=1.65, + cluster_threshold=10, output_dir=None, n_cores=1, ): @@ -76,6 +78,19 @@ def cbma_workflow( or optional List of meta-analysis diagnostic classes. A single diagnostic class can also be passed. Default is :class:`~nimare.diagnostics.FocusCounter`. + voxel_thresh : :obj:`float` or None, optional + An optional voxel-level threshold that may be applied to the ``target_image`` to define + clusters. This can be None if the ``target_image`` is already thresholded + (e.g., a cluster-level corrected map). + If estimator, corrector, or diagnostics are passed as initialized objects, this parameter + will be ignored. + Default is 1.96, which correspond with `p-value = .05`. + cluster_threshold : :obj:`int` or None, optional + Cluster size threshold, in :term:`voxels`. + If None, then no cluster size threshold will be applied. + If estimator, corrector, or diagnostics are passed as initialized objects, this parameter + will be ignored. + Default is 10. output_dir : :obj:`str`, optional Output directory in which to save results. If the directory doesn't exist, it will be created. Default is None (the results are not saved). @@ -116,11 +131,16 @@ def cbma_workflow( else _check_input(corrector, Corrector, corr_options, n_cores=n_cores) ) + diag_kwargs = { + "voxel_thresh": voxel_thresh, + "cluster_threshold": cluster_threshold, + "n_cores": n_cores, + } if diagnostics is None: - diagnostics = [Jackknife(n_cores=n_cores)] + diagnostics = [Jackknife(**diag_kwargs)] else: diagnostics = [ - _check_input(diagnostic, Diagnostics, diag_options, n_cores=n_cores) + _check_input(diagnostic, Diagnostics, diag_options, **diag_kwargs) for diagnostic in diagnostics ] From 60504640f6c828c2fa22c8db843162d8770af028 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 19:19:54 -0400 Subject: [PATCH 27/32] Test non-cbma estimator --- nimare/tests/test_workflows.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 241ecdf7f..5f3b46c8d 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -8,6 +8,7 @@ from nimare.correct import FWECorrector from nimare.diagnostics import FocusCounter, Jackknife from nimare.meta.cbma import ALE, MKDAChi2 +from nimare.meta.ibma import Fishers from nimare.tests.utils import get_test_data_path @@ -96,6 +97,7 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), (MKDAChi2, "montecarlo", "focuscounter"), + (Fishers, "montecarlo", None), ], ) def test_cbma_workflow_function_smoke( @@ -112,6 +114,14 @@ def test_cbma_workflow_function_smoke( corrector=corrector, diagnostics=diagnostics, ) + elif estimator == Fishers: + with pytest.raises((AttributeError, ValueError)): + workflows.cbma_workflow( + testdata_cbma_full, + estimator=estimator, + corrector=corrector, + diagnostics=diagnostics, + ) else: cres = workflows.cbma_workflow( testdata_cbma_full, @@ -133,4 +143,6 @@ def test_cbma_workflow_function_smoke( for tabletype in cres.tables.keys(): filename = tabletype + ".tsv" outpath = op.join(tmpdir, filename) - assert op.isfile(outpath) + # For estimator == ALE, tables are None + if estimator != ALE: + assert op.isfile(outpath) From 0a817253e36f2586e957ae0de434af11580e0fc5 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 19:19:58 -0400 Subject: [PATCH 28/32] Update base.py --- nimare/meta/cbma/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimare/meta/cbma/base.py b/nimare/meta/cbma/base.py index 1f738f1ca..61c9b948d 100644 --- a/nimare/meta/cbma/base.py +++ b/nimare/meta/cbma/base.py @@ -75,7 +75,7 @@ def __init__(self, kernel_transformer, *, mask=None, **kwargs): # Flag any extraneous kwargs other_kwargs = dict(set(kwargs.items()) - set(kernel_args.items())) if other_kwargs: - LGR.warn(f"Unused keyword arguments found: {tuple(other_kwargs.items())}") + LGR.warning(f"Unused keyword arguments found: {tuple(other_kwargs.items())}") # Get kernel transformer kernel_args = {k.split("kernel__")[1]: v for k, v in kernel_args.items()} From 1761655e23b7d362a9acfbdda71894e25c11f8e1 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 19:20:03 -0400 Subject: [PATCH 29/32] Update 10_plot_cbma_workflow.py --- examples/02_meta-analyses/10_plot_cbma_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/02_meta-analyses/10_plot_cbma_workflow.py b/examples/02_meta-analyses/10_plot_cbma_workflow.py index bf02fb3a7..ac1aee221 100644 --- a/examples/02_meta-analyses/10_plot_cbma_workflow.py +++ b/examples/02_meta-analyses/10_plot_cbma_workflow.py @@ -58,7 +58,7 @@ img, cut_coords=4, display_mode="z", - threshold=3.1, # cluster-level p < 0.001, one-tailed + threshold=1.65, # voxel_thresh p < .05, one-tailed cmap="RdBu_r", vmax=4, ) From 050d3a0692d411ab757af1a0caa3e7d5a5b75744 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 19:30:34 -0400 Subject: [PATCH 30/32] Improve coverage --- nimare/tests/test_workflows.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index 5f3b46c8d..ce251b6d5 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -96,8 +96,9 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): (ALE, FWECorrector(method="montecarlo", n_iters=10), [Jackknife]), ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), - (MKDAChi2, "montecarlo", "focuscounter"), - (Fishers, "montecarlo", None), + ("mkdadensity", "fdr", "focuscounter"), + (MKDAChi2, "montecarlo", None), + (Fishers, "montecarlo", "jackknife"), ], ) def test_cbma_workflow_function_smoke( From 58f2cfcfa172c2ea8ae6cf21ac3cdb73d2021a94 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 21:21:51 -0400 Subject: [PATCH 31/32] Update documentation --- nimare/workflows/cbma.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index 53a0a198c..bad378aba 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -60,8 +60,8 @@ def cbma_workflow( .. versionadded:: 0.0.14 - This workflow performs a coordinate-based meta-analysis, multiple comparison correction, - and diagnostics analyses on corrected meta-analytic maps. + This workflow performs a coordinate-based meta-analysis, multiple comparison corrections, + and diagnostics analyses on corrected meta-analytic z-score maps. Parameters ---------- @@ -79,17 +79,15 @@ def cbma_workflow( List of meta-analysis diagnostic classes. A single diagnostic class can also be passed. Default is :class:`~nimare.diagnostics.FocusCounter`. voxel_thresh : :obj:`float` or None, optional - An optional voxel-level threshold that may be applied to the ``target_image`` to define - clusters. This can be None if the ``target_image`` is already thresholded - (e.g., a cluster-level corrected map). - If estimator, corrector, or diagnostics are passed as initialized objects, this parameter - will be ignored. - Default is 1.96, which correspond with `p-value = .05`. + An optional voxel-level threshold that may be applied to the ``target_image`` in the + :class:`~nimare.diagnostics.Diagnostics` class to define clusters. This can be None or 0 + if the ``target_image`` is already thresholded (e.g., a cluster-level corrected map). + If diagnostics are passed as initialized objects, this parameter will be ignored. + Default is 1.65, which corresponds to p-value = .05, one-tailed. cluster_threshold : :obj:`int` or None, optional Cluster size threshold, in :term:`voxels`. If None, then no cluster size threshold will be applied. - If estimator, corrector, or diagnostics are passed as initialized objects, this parameter - will be ignored. + If diagnostics are passed as initialized objects, this parameter will be ignored. Default is 10. output_dir : :obj:`str`, optional Output directory in which to save results. If the directory doesn't From 6af419b72ea4007d9a9018ebad3b6861e80e06d1 Mon Sep 17 00:00:00 2001 From: JulioAPeraza Date: Tue, 28 Mar 2023 21:25:47 -0400 Subject: [PATCH 32/32] Improve coverage --- nimare/tests/test_workflows.py | 9 +++++++++ nimare/workflows/cbma.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/nimare/tests/test_workflows.py b/nimare/tests/test_workflows.py index ce251b6d5..518699aed 100644 --- a/nimare/tests/test_workflows.py +++ b/nimare/tests/test_workflows.py @@ -94,6 +94,7 @@ def test_ale_workflow_cli_smoke_2(tmp_path_factory): "estimator,corrector,diagnostics", [ (ALE, FWECorrector(method="montecarlo", n_iters=10), [Jackknife]), + ("ales", "bonferroni", Jackknife), ("ale", "bonferroni", [Jackknife, FocusCounter]), ("kda", "fdr", Jackknife), ("mkdadensity", "fdr", "focuscounter"), @@ -123,6 +124,14 @@ def test_cbma_workflow_function_smoke( corrector=corrector, diagnostics=diagnostics, ) + elif estimator == "ales": + with pytest.raises(ValueError): + workflows.cbma_workflow( + testdata_cbma_full, + estimator=estimator, + corrector=corrector, + diagnostics=diagnostics, + ) else: cres = workflows.cbma_workflow( testdata_cbma_full, diff --git a/nimare/workflows/cbma.py b/nimare/workflows/cbma.py index bad378aba..7f8e44a8a 100644 --- a/nimare/workflows/cbma.py +++ b/nimare/workflows/cbma.py @@ -33,7 +33,7 @@ def _check_input(obj, clss, options, **kwargs): """Check input for workflow functions.""" if isinstance(obj, str): if obj not in options: - raise ValueError(f'"estimator" of kind string must be {", ".join(options)}') + raise ValueError(f'"{obj}" of kind string must be {", ".join(options)}') # Get the class from the string obj_str = obj