From fedfa4910abaae6fcddea3590762f981cfe09171 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 10:55:00 -0500 Subject: [PATCH 01/13] Start implementing FocusCounter diagnostic class. --- nimare/diagnostics.py | 206 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index 7347e1982..45135901b 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -232,3 +232,209 @@ def _transform( stat_prop_values = cluster_masker.transform(stat_prop_img) return expid, stat_prop_values + + +class FocusCounter(NiMAREBase): + """Run a focus-count analysis on a meta-analysis result. + + Parameters + ---------- + target_image : :obj:`str`, optional + The meta-analytic map for which clusters will be characterized. + The default is z because log-p will not always have value of zero for non-cluster voxels. + 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). + Default is None. + n_cores : :obj:`int`, optional + Number of cores to use for parallelization. + If <=0, defaults to using all available cores. + Default is 1. + + Notes + ----- + This analysis characterizes the relative contribution of each experiment in a meta-analysis + to the resulting clusters by looping through experiments, calculating the Estimator's summary + statistic for all experiments *except* the target experiment, dividing the resulting test + summary statistics by the summary statistics from the original meta-analysis, and finally + averaging the resulting proportion values across all voxels in each cluster. + + Warnings + -------- + Pairwise meta-analyses, like ALESubtraction and MKDAChi2, are not yet supported in this + method. + """ + + def __init__( + self, + target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", + voxel_thresh=None, + n_cores=1, + ): + self.target_image = target_image + self.voxel_thresh = voxel_thresh + self.n_cores = self._check_ncores(n_cores) + + def transform(self, result): + """Apply the analysis to a MetaResult. + + Parameters + ---------- + result : :obj:`~nimare.results.MetaResult` + A MetaResult produced by a coordinate- or image-based meta-analysis. + + Returns + ------- + contribution_table : :obj:`pandas.DataFrame` + A DataFrame with information about relative contributions of each experiment to each + cluster in the thresholded map. + There is one row for each experiment, as well as one more row at the top of the table + (below the header), which has the center of mass of each cluster. + The centers of mass are not guaranteed to fall within the actual clusters, but can + serve as a useful heuristic for identifying them. + There is one column for each cluster, with column names being integers indicating the + cluster's associated value in the ``labeled_cluster_img`` output. + labeled_cluster_img : :obj:`nibabel.nifti1.Nifti1Image` + The labeled, thresholded map that is used to identify clusters characterized by this + analysis. + Each cluster in the map has a single value, which corresponds to the cluster's column + name in ``contribution_table``. + """ + if not hasattr(result.estimator, "dataset"): + raise AttributeError( + "MetaResult was not generated by an Estimator with a `dataset` attribute. " + "This may be because the Estimator was a pairwise Estimator. " + "The Jackknife method does not currently work with pairwise Estimators." + ) + dset = result.estimator.dataset + # We need to copy the estimator because it will otherwise overwrite the original version + # with one missing a study in its inputs. + estimator = copy.deepcopy(result.estimator) + original_masker = estimator.masker + + # Collect the thresholded cluster map + if self.target_image in result.maps: + target_img = result.get_map(self.target_image, return_type="image") + else: + available_maps = [f"'{m}'" for m in result.maps.keys()] + raise ValueError( + f"Target image ('{self.target_image}') not present in result. " + f"Available maps in result are: {', '.join(available_maps)}." + ) + + if self.voxel_thresh: + thresh_img = image.threshold_img(target_img, self.voxel_thresh) + else: + thresh_img = target_img + + thresh_arr = thresh_img.get_fdata() + + # Use study IDs in inputs_ instead of dataset, because we don't want to try fitting the + # estimator to a study that might have been filtered out by the estimator's criteria. + meta_ids = estimator.inputs_["id"] + rows = ["Center of Mass"] + list(meta_ids) + + # Let's label the clusters in the thresholded map so we can use it as a NiftiLabelsMasker + # This won't work when the Estimator's masker isn't a NiftiMasker... :( + conn = np.zeros((3, 3, 3), int) + conn[:, :, 1] = 1 + conn[:, 1, :] = 1 + conn[1, :, :] = 1 + labeled_cluster_arr, n_clusters = ndimage.measurements.label(thresh_arr, conn) + labeled_cluster_img = nib.Nifti1Image( + labeled_cluster_arr, + affine=target_img.affine, + header=target_img.header, + ) + + if n_clusters == 0: + LGR.warning("No clusters found") + contribution_table = pd.DataFrame(index=rows) + return contribution_table, labeled_cluster_img + + # Identify center of mass for each cluster + # This COM may fall outside the cluster, but it is a useful heuristic for identifying them + cluster_ids = list(range(1, n_clusters + 1)) + cluster_coms = ndimage.center_of_mass( + labeled_cluster_arr, + labeled_cluster_arr, + cluster_ids, + ) + cluster_coms = np.array(cluster_coms) + cluster_coms = vox2mm(cluster_coms, target_img.affine) + + cluster_com_strs = [] + for i_peak in range(len(cluster_ids)): + x, y, z = cluster_coms[i_peak, :].astype(int) + xyz_str = f"({x}, {y}, {z})" + cluster_com_strs.append(xyz_str) + + # Mask using a labels masker, so that we can easily get the mean value for each cluster + cluster_masker = input_data.NiftiLabelsMasker(labeled_cluster_img) + cluster_masker.fit(labeled_cluster_img) + + # Create empty contribution table + contribution_table = pd.DataFrame(index=rows, columns=cluster_ids) + contribution_table.index.name = "Cluster ID" + contribution_table.loc["Center of Mass"] = cluster_com_strs + + with tqdm_joblib(tqdm(total=len(meta_ids))): + jackknife_results = Parallel(n_jobs=self.n_cores)( + delayed(self._transform)( + study_id, + all_ids=meta_ids, + dset=dset, + estimator=estimator, + target_value_map=target_value_map, + stat_values=stat_values, + original_masker=original_masker, + cluster_masker=cluster_masker, + ) + for study_id in meta_ids + ) + + # Add the results to the table + for expid, stat_prop_values in jackknife_results: + contribution_table.loc[expid] = stat_prop_values + + return contribution_table, labeled_cluster_img + + def _transform( + self, + expid, + all_ids, + dset, + estimator, + target_value_map, + stat_values, + original_masker, + cluster_masker, + ): + # Fit Estimator to all studies except the target study + other_ids = [id_ for id_ in all_ids if id_ != expid] + temp_dset = dset.slice(other_ids) + temp_result = estimator.fit(temp_dset) + + # Collect the target values (e.g., ALE values) from the N-1 meta-analysis + temp_stat_img = temp_result.get_map(target_value_map, return_type="image") + temp_stat_vals = np.squeeze(original_masker.transform(temp_stat_img)) + + # Voxelwise proportional reduction of each statistic after removal of the experiment + with np.errstate(divide="ignore", invalid="ignore"): + prop_values = np.true_divide(temp_stat_vals, stat_values) + prop_values = np.nan_to_num(prop_values) + + voxelwise_stat_prop_values = 1 - prop_values + + # Now get the cluster-wise mean of the proportion values + # pending resolution of https://github.com/nilearn/nilearn/issues/2724 + try: + stat_prop_img = original_masker.inverse_transform(voxelwise_stat_prop_values) + except IndexError: + stat_prop_img = squeeze_image( + original_masker.inverse_transform([voxelwise_stat_prop_values]) + ) + + stat_prop_values = cluster_masker.transform(stat_prop_img) + return expid, stat_prop_values From 91a97f127f4ff566bb8461d715c71a92209a4d26 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 11:55:50 -0500 Subject: [PATCH 02/13] Hopefully get it working. --- nimare/diagnostics.py | 72 +++++++++++++------------------------------ 1 file changed, 22 insertions(+), 50 deletions(-) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index 45135901b..a011fe695 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -9,10 +9,11 @@ from nibabel.funcs import squeeze_image from nilearn import image, input_data from scipy import ndimage +from scipy.spatial.distance import cdist from tqdm.auto import tqdm -from .base import NiMAREBase -from .utils import tqdm_joblib, vox2mm +from nimare.base import NiMAREBase +from nimare.utils import mm2vox, tqdm_joblib, vox2mm LGR = logging.getLogger(__name__) @@ -307,11 +308,10 @@ def transform(self, result): "This may be because the Estimator was a pairwise Estimator. " "The Jackknife method does not currently work with pairwise Estimators." ) - dset = result.estimator.dataset + # We need to copy the estimator because it will otherwise overwrite the original version # with one missing a study in its inputs. estimator = copy.deepcopy(result.estimator) - original_masker = estimator.masker # Collect the thresholded cluster map if self.target_image in result.maps: @@ -357,9 +357,7 @@ def transform(self, result): # This COM may fall outside the cluster, but it is a useful heuristic for identifying them cluster_ids = list(range(1, n_clusters + 1)) cluster_coms = ndimage.center_of_mass( - labeled_cluster_arr, - labeled_cluster_arr, - cluster_ids, + labeled_cluster_arr, labeled_cluster_arr, cluster_ids ) cluster_coms = np.array(cluster_coms) cluster_coms = vox2mm(cluster_coms, target_img.affine) @@ -383,58 +381,32 @@ def transform(self, result): jackknife_results = Parallel(n_jobs=self.n_cores)( delayed(self._transform)( study_id, - all_ids=meta_ids, - dset=dset, - estimator=estimator, - target_value_map=target_value_map, - stat_values=stat_values, - original_masker=original_masker, + coords_df=estimator.inputs_["coordinates"], cluster_masker=cluster_masker, ) for study_id in meta_ids ) # Add the results to the table - for expid, stat_prop_values in jackknife_results: - contribution_table.loc[expid] = stat_prop_values + for expid, focus_counts in jackknife_results: + contribution_table.loc[expid] = focus_counts return contribution_table, labeled_cluster_img - def _transform( - self, - expid, - all_ids, - dset, - estimator, - target_value_map, - stat_values, - original_masker, - cluster_masker, - ): - # Fit Estimator to all studies except the target study - other_ids = [id_ for id_ in all_ids if id_ != expid] - temp_dset = dset.slice(other_ids) - temp_result = estimator.fit(temp_dset) - - # Collect the target values (e.g., ALE values) from the N-1 meta-analysis - temp_stat_img = temp_result.get_map(target_value_map, return_type="image") - temp_stat_vals = np.squeeze(original_masker.transform(temp_stat_img)) - - # Voxelwise proportional reduction of each statistic after removal of the experiment - with np.errstate(divide="ignore", invalid="ignore"): - prop_values = np.true_divide(temp_stat_vals, stat_values) - prop_values = np.nan_to_num(prop_values) + def _transform(self, expid, coordinates_df, labeled_cluster_map, affine): + coords = coordinates_df.loc[coordinates_df["id"] == expid] + ijk = mm2vox(coords[["x", "y", "z"]], affine) - voxelwise_stat_prop_values = 1 - prop_values + clust_ids = sorted(list(np.unique(labeled_cluster_map)[1:])) + focus_counts = [] - # Now get the cluster-wise mean of the proportion values - # pending resolution of https://github.com/nilearn/nilearn/issues/2724 - try: - stat_prop_img = original_masker.inverse_transform(voxelwise_stat_prop_values) - except IndexError: - stat_prop_img = squeeze_image( - original_masker.inverse_transform([voxelwise_stat_prop_values]) - ) + for i_cluster, c_val in enumerate(clust_ids): + cluster_mask = labeled_cluster_map == c_val + cluster_idx = np.vstack(np.where(cluster_mask)) + distances = cdist(cluster_idx.T, ijk) + distances = distances < 1 + distances = np.any(distances, axis=0) + n_included_voxels = np.sum(distances) + focus_counts.append(n_included_voxels) - stat_prop_values = cluster_masker.transform(stat_prop_img) - return expid, stat_prop_values + return expid, focus_counts From ad7767dce5eb0ef3c0b6be3c540f839801226309 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 12:06:36 -0500 Subject: [PATCH 03/13] Add test. --- nimare/diagnostics.py | 19 +++++++--------- nimare/tests/test_diagnostics.py | 37 +++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index a011fe695..e69d5aa89 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -236,7 +236,7 @@ def _transform( class FocusCounter(NiMAREBase): - """Run a focus-count analysis on a meta-analysis result. + """Run a focus-count analysis on a coordinate-based meta-analysis result. Parameters ---------- @@ -256,13 +256,13 @@ class FocusCounter(NiMAREBase): Notes ----- This analysis characterizes the relative contribution of each experiment in a meta-analysis - to the resulting clusters by looping through experiments, calculating the Estimator's summary - statistic for all experiments *except* the target experiment, dividing the resulting test - summary statistics by the summary statistics from the original meta-analysis, and finally - averaging the resulting proportion values across all voxels in each cluster. + to the resulting clusters by counting the number of peaks from each experiment that fall within + each significant cluster. Warnings -------- + This method only works for coordinate-based meta-analyses. + Pairwise meta-analyses, like ALESubtraction and MKDAChi2, are not yet supported in this method. """ @@ -368,10 +368,6 @@ def transform(self, result): xyz_str = f"({x}, {y}, {z})" cluster_com_strs.append(xyz_str) - # Mask using a labels masker, so that we can easily get the mean value for each cluster - cluster_masker = input_data.NiftiLabelsMasker(labeled_cluster_img) - cluster_masker.fit(labeled_cluster_img) - # Create empty contribution table contribution_table = pd.DataFrame(index=rows, columns=cluster_ids) contribution_table.index.name = "Cluster ID" @@ -381,8 +377,9 @@ def transform(self, result): jackknife_results = Parallel(n_jobs=self.n_cores)( delayed(self._transform)( study_id, - coords_df=estimator.inputs_["coordinates"], - cluster_masker=cluster_masker, + coordinates_df=estimator.inputs_["coordinates"], + labeled_cluster_map=labeled_cluster_arr, + affine=target_img.affine, ) for study_id in meta_ids ) diff --git a/nimare/tests/test_diagnostics.py b/nimare/tests/test_diagnostics.py index c0108b9e6..3502cf0d9 100644 --- a/nimare/tests/test_diagnostics.py +++ b/nimare/tests/test_diagnostics.py @@ -4,7 +4,7 @@ import pytest from nilearn.input_data import NiftiLabelsMasker -from nimare.diagnostics import Jackknife +from nimare.diagnostics import FocusCounter, Jackknife from nimare.meta import cbma, ibma from nimare.tests.utils import get_test_data_path @@ -72,3 +72,38 @@ def test_jackknife_with_custom_masker_smoke(testdata_ibma): with pytest.raises(ValueError): jackknife = Jackknife(target_image="doggy", voxel_thresh=0.5) jackknife.transform(res) + + +@pytest.mark.parametrize( + "estimator,meta_type,n_samples,target_image", + [ + (cbma.ALE, "cbma", "onesample", "z"), + (cbma.MKDADensity, "cbma", "onesample", "z"), + (cbma.KDA, "cbma", "onesample", "z"), + (cbma.MKDAChi2, "cbma", "twosample", "z_desc-consistency"), + ], +) +def test_focuscounter_smoke( + testdata_ibma, + testdata_cbma_full, + estimator, + meta_type, + n_samples, + target_image, +): + """Smoke test the FocusCounter method.""" + meta = estimator() + testdata = testdata_ibma if meta_type == "ibma" else testdata_cbma_full + if n_samples == "twosample": + res = meta.fit(testdata, testdata) + else: + res = meta.fit(testdata) + + counter = FocusCounter(target_image=target_image, voxel_thresh=1.65) + + if n_samples == "twosample": + with pytest.raises(AttributeError): + counter.transform(res) + else: + cluster_table, labeled_img = counter.transform(res) + assert cluster_table.shape[0] == len(meta.inputs_["id"]) + 1 From f9e481602a5df4f46fdf893e2097f9aed1383c79 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 12:10:29 -0500 Subject: [PATCH 04/13] Update ale.py --- nimare/workflows/ale.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/nimare/workflows/ale.py b/nimare/workflows/ale.py index cb405b97c..060fa7d21 100644 --- a/nimare/workflows/ale.py +++ b/nimare/workflows/ale.py @@ -6,9 +6,9 @@ import numpy as np -from ..correct import FWECorrector -from ..io import convert_sleuth_to_dataset -from ..meta import ALE, ALESubtraction +from nimare.correct import FWECorrector +from nimare.io import convert_sleuth_to_dataset +from nimare.meta import ALE, ALESubtraction LGR = logging.getLogger(__name__) @@ -72,7 +72,7 @@ def ale_sleuth_workflow( ---------- - Eickhoff, S. B., Bzdok, D., Laird, A. R., Kurth, F., & Fox, P. T. (2012). Activation likelihood estimation meta-analysis revisited. NeuroImage, -59(3), 2349–2361. +59(3), 2349-2361. - Fonov, V., Evans, A. C., Botteron, K., Almli, C. R., McKinstry, R. C., Collins, D. L., & Brain Development Cooperative Group. (2011). Unbiased average age-appropriate atlases for pediatric studies. @@ -82,11 +82,11 @@ def ale_sleuth_workflow( to adulthood. NeuroImage, (47), S102. - Turkeltaub, P. E., Eden, G. F., Jones, K. M., & Zeffiro, T. A. (2002). Meta-analysis of the functional neuroanatomy of single-word reading: method -and validation. NeuroImage, 16(3 Pt 1), 765–780. +and validation. NeuroImage, 16(3 Pt 1), 765-780. - Turkeltaub, P. E., Eickhoff, S. B., Laird, A. R., Fox, M., Wiener, M., & Fox, P. (2012). Minimizing within-experiment and within-group effects in Activation Likelihood Estimation meta-analyses. Human Brain Mapping, -33(1), 1–13. +33(1), 1-13. """ ale = ALE(kernel__fwhm=fwhm) @@ -149,14 +149,14 @@ def ale_sleuth_workflow( ---------- - Turkeltaub, P. E., Eden, G. F., Jones, K. M., & Zeffiro, T. A. (2002). Meta-analysis of the functional neuroanatomy of single-word reading: method -and validation. NeuroImage, 16(3 Pt 1), 765–780. +and validation. NeuroImage, 16(3 Pt 1), 765-780. - Eickhoff, S. B., Bzdok, D., Laird, A. R., Kurth, F., & Fox, P. T. (2012). Activation likelihood estimation meta-analysis revisited. NeuroImage, -59(3), 2349–2361. +59(3), 2349-2361. - Turkeltaub, P. E., Eickhoff, S. B., Laird, A. R., Fox, M., Wiener, M., & Fox, P. (2012). Minimizing within-experiment and within-group effects in Activation Likelihood Estimation meta-analyses. Human Brain Mapping, -33(1), 1–13. +33(1), 1-13. - Fonov, V., Evans, A. C., Botteron, K., Almli, C. R., McKinstry, R. C., Collins, D. L., & Brain Development Cooperative Group. (2011). Unbiased average age-appropriate atlases for pediatric studies. From c2d93875a6a0a77a083b911e8fd423ce924f9c48 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 17:53:42 -0500 Subject: [PATCH 05/13] [skip ci] Update api.rst --- docs/api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api.rst b/docs/api.rst index 9d5420fbb..eeaae3430 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -95,6 +95,7 @@ For more information about the components of coordinate-based meta-analysis in N :template: class.rst diagnostics.Jackknife + diagnostics.FocusCounter .. _api_annotate_ref: From c1838d52ba89f4ad5c14da64a6e4dfc869f13d5e Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 22 Feb 2022 18:14:50 -0500 Subject: [PATCH 06/13] Improve examples. --- .../03_plot_compare_ibma_and_cbma.py | 15 +++++++++++++++ .../05_plot_cbma_subtraction_conjunction.py | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py b/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py index a8ef07305..3e03dc1b6 100644 --- a/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py +++ b/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py @@ -19,6 +19,7 @@ from nilearn.plotting import plot_stat_map from nimare.dataset import Dataset +from nimare.diagnostics import Jackknife from nimare.extract import download_nidm_pain from nimare.meta.cbma import ALE from nimare.meta.ibma import DerSimonianLaird @@ -74,3 +75,17 @@ } ) print(stat_df.corr()) + +############################################################################### +# Characterize the relative contributions of experiments in the results +# ----------------------------------------------------------------------------- + +jknife = Jackknife(target_image="z", voxel_thresh=1.645) +cbma_cluster_table, cbma_cluster_img = jknife.transform(meta_cbma.results) +ibma_cluster_table, ibma_cluster_img = jknife.transform(meta_ibma.results) + +############################################################################### +cbma_cluster_table.head(10) + +############################################################################### +ibma_cluster_table.head(10) diff --git a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py index a603b99ce..e5fa8e411 100644 --- a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py +++ b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py @@ -20,7 +20,7 @@ from nimare import io, utils from nimare.correct import FWECorrector -from nimare.diagnostics import Jackknife +from nimare.diagnostics import FocusCounter from nimare.meta.cbma import ALE, ALESubtraction ############################################################################### @@ -84,12 +84,12 @@ # Characterize the relative contributions of experiments in the ALE results # ----------------------------------------------------------------------------- -jknife = Jackknife( +counter = FocusCounter( target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", voxel_thresh=None, ) -knowledge_cluster_table, knowledge_cluster_img = jknife.transform(knowledge_corrected_results) -related_cluster_table, related_cluster_img = jknife.transform(related_corrected_results) +knowledge_cluster_table, knowledge_cluster_img = counter.transform(knowledge_corrected_results) +related_cluster_table, related_cluster_img = counter.transform(related_corrected_results) # %% # ############################################################################# From abb5bbd8bbb766d53af00edee421c75f38a72190 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sat, 26 Feb 2022 11:43:13 -0500 Subject: [PATCH 07/13] Make a copy of the estimator in Jackknife._transform. --- nimare/diagnostics.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index e69d5aa89..e6ee737ee 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -206,6 +206,8 @@ def _transform( original_masker, cluster_masker, ): + estimator = copy.deepcopy(estimator) + # Fit Estimator to all studies except the target study other_ids = [id_ for id_ in all_ids if id_ != expid] temp_dset = dset.slice(other_ids) From bf1aefb7277f2d369f7745c39615960b6957b941 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sat, 26 Feb 2022 12:57:13 -0500 Subject: [PATCH 08/13] Try reducing the examples. --- .../03_plot_compare_ibma_and_cbma.py | 15 ---------- .../05_plot_cbma_subtraction_conjunction.py | 29 ++++++++++++++----- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py b/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py index 3e03dc1b6..a8ef07305 100644 --- a/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py +++ b/examples/02_meta-analyses/03_plot_compare_ibma_and_cbma.py @@ -19,7 +19,6 @@ from nilearn.plotting import plot_stat_map from nimare.dataset import Dataset -from nimare.diagnostics import Jackknife from nimare.extract import download_nidm_pain from nimare.meta.cbma import ALE from nimare.meta.ibma import DerSimonianLaird @@ -75,17 +74,3 @@ } ) print(stat_df.corr()) - -############################################################################### -# Characterize the relative contributions of experiments in the results -# ----------------------------------------------------------------------------- - -jknife = Jackknife(target_image="z", voxel_thresh=1.645) -cbma_cluster_table, cbma_cluster_img = jknife.transform(meta_cbma.results) -ibma_cluster_table, ibma_cluster_img = jknife.transform(meta_ibma.results) - -############################################################################### -cbma_cluster_table.head(10) - -############################################################################### -ibma_cluster_table.head(10) diff --git a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py index e5fa8e411..d938c6cda 100644 --- a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py +++ b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py @@ -20,7 +20,7 @@ from nimare import io, utils from nimare.correct import FWECorrector -from nimare.diagnostics import FocusCounter +from nimare.diagnostics import FocusCounter, Jackknife from nimare.meta.cbma import ALE, ALESubtraction ############################################################################### @@ -83,21 +83,36 @@ ############################################################################### # Characterize the relative contributions of experiments in the ALE results # ----------------------------------------------------------------------------- +# NiMARE contains two methods for this: :class:`~nimare.diagnostics.Jackknife` +# and :class:`~nimare.diagnostics.FocusCounter`. +# We will show both below. counter = FocusCounter( target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", voxel_thresh=None, ) -knowledge_cluster_table, knowledge_cluster_img = counter.transform(knowledge_corrected_results) -related_cluster_table, related_cluster_img = counter.transform(related_corrected_results) +knowledge_count_table, knowledge_cluster_img = counter.transform(knowledge_corrected_results) +related_count_table, related_cluster_img = counter.transform(related_corrected_results) -# %% # ############################################################################# -knowledge_cluster_table.head(10) +knowledge_count_table.head(10) -# %% # ############################################################################# -related_cluster_table.head(10) +related_count_table.head(10) + +# ############################################################################# +jackknife = Jackknife( + target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", + voxel_thresh=None, +) +knowledge_jackknife_table, _ = jackknife.transform(knowledge_corrected_results) +related_jackknife_table, _ = jackknife.transform(related_corrected_results) + +# ############################################################################# +knowledge_jackknife_table.head(10) + +# ############################################################################# +related_jackknife_table.head(10) ############################################################################### # Subtraction analysis From 2db1cbe3aaf5c9ecdb993157844d523e05f60136 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sat, 26 Feb 2022 13:18:04 -0500 Subject: [PATCH 09/13] Update 08_plot_simulated_data.py --- examples/02_meta-analyses/08_plot_simulated_data.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/02_meta-analyses/08_plot_simulated_data.py b/examples/02_meta-analyses/08_plot_simulated_data.py index 0b638f3b6..d0873778d 100644 --- a/examples/02_meta-analyses/08_plot_simulated_data.py +++ b/examples/02_meta-analyses/08_plot_simulated_data.py @@ -110,7 +110,6 @@ def analyze_and_plot(dset, ground_truth_foci=None, correct=True, return_cres=Fal # ------------------------------- display = analyze_and_plot(manual_dset, ground_truth_foci) -display.frame_axes.figure.show() ############################################################################### # Control percentage of studies with the foci of interest @@ -129,7 +128,6 @@ def analyze_and_plot(dset, ground_truth_foci=None, correct=True, return_cres=Fal # ------------------------------------- display = analyze_and_plot(perc_foci_dset, ground_truth_foci[0:2]) -display.frame_axes.figure.show() ############################################################################### # Create a null dataset From 88ccec771f60ed4f93f3a03e0fd96d9c81b21e19 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sat, 26 Feb 2022 13:57:08 -0500 Subject: [PATCH 10/13] [skip-ci] Fix example. --- .../02_meta-analyses/05_plot_cbma_subtraction_conjunction.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py index d938c6cda..395413998 100644 --- a/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py +++ b/examples/02_meta-analyses/05_plot_cbma_subtraction_conjunction.py @@ -94,12 +94,15 @@ knowledge_count_table, knowledge_cluster_img = counter.transform(knowledge_corrected_results) related_count_table, related_cluster_img = counter.transform(related_corrected_results) +# %% # ############################################################################# knowledge_count_table.head(10) +# %% # ############################################################################# related_count_table.head(10) +# %% # ############################################################################# jackknife = Jackknife( target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", @@ -108,9 +111,11 @@ knowledge_jackknife_table, _ = jackknife.transform(knowledge_corrected_results) related_jackknife_table, _ = jackknife.transform(related_corrected_results) +# %% # ############################################################################# knowledge_jackknife_table.head(10) +# %% # ############################################################################# related_jackknife_table.head(10) From bad3ecf25a049c479df9052b5ca3b43301e829fb Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sun, 27 Feb 2022 12:18:38 -0500 Subject: [PATCH 11/13] Incorporate FocusCounter into ALE workflow. --- nimare/workflows/ale.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nimare/workflows/ale.py b/nimare/workflows/ale.py index 060fa7d21..82f2a9eb5 100644 --- a/nimare/workflows/ale.py +++ b/nimare/workflows/ale.py @@ -7,6 +7,7 @@ import numpy as np from nimare.correct import FWECorrector +from nimare.diagnostics import FocusCounter from nimare.io import convert_sleuth_to_dataset from nimare.meta import ALE, ALESubtraction @@ -97,6 +98,11 @@ def ale_sleuth_workflow( method="montecarlo", n_iters=n_iters, voxel_thresh=v_thr, n_cores=n_cores ) cres = corr.transform(results) + fcounter = FocusCounter( + target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", + voxel_thresh=None, + ) + count_df = fcounter.transform(cres) boilerplate = boilerplate.format( n_exps=len(dset.ids), @@ -180,7 +186,15 @@ def ale_sleuth_workflow( method="montecarlo", n_iters=n_iters, voxel_thresh=v_thr, n_cores=n_cores ) cres1 = corr.transform(res1) + fcounter = FocusCounter( + target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", + voxel_thresh=None, + ) + count_df1 = fcounter.transform(cres1) + cres2 = corr.transform(res2) + count_df2 = fcounter.transform(cres2) + sub = ALESubtraction(n_iters=n_iters, kernel__fwhm=fwhm) sres = sub.fit(dset1, dset2) @@ -211,13 +225,16 @@ def ale_sleuth_workflow( LGR.info("Saving output maps...") if not sleuth_file2: cres.save_maps(output_dir=output_dir, prefix=prefix) + count_df.to_csv(os.path.join(output_dir, prefix + "_clust.tsv"), index=False, sep="\t") copyfile(sleuth_file, os.path.join(output_dir, prefix + "input_coordinates.txt")) else: prefix1 = os.path.splitext(os.path.basename(sleuth_file))[0] + "_" prefix2 = os.path.splitext(os.path.basename(sleuth_file2))[0] + "_" prefix3 = prefix + "subtraction_" cres1.save_maps(output_dir=output_dir, prefix=prefix1) + count_df1.to_csv(os.path.join(output_dir, prefix1 + "_clust.tsv"), index=False, sep="\t") cres2.save_maps(output_dir=output_dir, prefix=prefix2) + count_df2.to_csv(os.path.join(output_dir, prefix2 + "_clust.tsv"), index=False, sep="\t") sres.save_maps(output_dir=output_dir, prefix=prefix3) copyfile(sleuth_file, os.path.join(output_dir, prefix + "group1_input_coordinates.txt")) copyfile(sleuth_file2, os.path.join(output_dir, prefix + "group2_input_coordinates.txt")) From 554f31b5da2c073ce1ee19c96b5555345374282e Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sun, 27 Feb 2022 12:39:08 -0500 Subject: [PATCH 12/13] Fix the workflow. --- nimare/workflows/ale.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nimare/workflows/ale.py b/nimare/workflows/ale.py index 82f2a9eb5..acc572d0a 100644 --- a/nimare/workflows/ale.py +++ b/nimare/workflows/ale.py @@ -102,7 +102,7 @@ def ale_sleuth_workflow( target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", voxel_thresh=None, ) - count_df = fcounter.transform(cres) + count_df, _ = fcounter.transform(cres) boilerplate = boilerplate.format( n_exps=len(dset.ids), @@ -190,10 +190,10 @@ def ale_sleuth_workflow( target_image="z_desc-size_level-cluster_corr-FWE_method-montecarlo", voxel_thresh=None, ) - count_df1 = fcounter.transform(cres1) + count_df1, _ = fcounter.transform(cres1) cres2 = corr.transform(res2) - count_df2 = fcounter.transform(cres2) + count_df2, _ = fcounter.transform(cres2) sub = ALESubtraction(n_iters=n_iters, kernel__fwhm=fwhm) sres = sub.fit(dset1, dset2) From c2386702693ea3dfbb9db2f9173414bb9dd6c86c Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Sun, 27 Feb 2022 13:06:56 -0500 Subject: [PATCH 13/13] Add versionadded directives to diagnostics classes. --- nimare/diagnostics.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nimare/diagnostics.py b/nimare/diagnostics.py index e6ee737ee..945726379 100644 --- a/nimare/diagnostics.py +++ b/nimare/diagnostics.py @@ -21,6 +21,8 @@ class Jackknife(NiMAREBase): """Run a jackknife analysis on a meta-analysis result. + .. versionadded:: 0.0.11 + Parameters ---------- target_image : :obj:`str`, optional @@ -240,6 +242,8 @@ def _transform( class FocusCounter(NiMAREBase): """Run a focus-count analysis on a coordinate-based meta-analysis result. + .. versionadded:: 0.0.12 + Parameters ---------- target_image : :obj:`str`, optional