From ad37d37951273637544eecac74ded801b6bdb833 Mon Sep 17 00:00:00 2001 From: Hao-Ting Wang Date: Wed, 10 May 2023 11:13:28 -0400 Subject: [PATCH] black and codespell for the jupyter book narratives to the results --- content/research_report/results-atlas.md | 213 +++++++++++-- content/research_report/results-group.md | 389 ++++++++++++++--------- 2 files changed, 421 insertions(+), 181 deletions(-) diff --git a/content/research_report/results-atlas.md b/content/research_report/results-atlas.md index 207d03a..27e7f79 100644 --- a/content/research_report/results-atlas.md +++ b/content/research_report/results-atlas.md @@ -11,12 +11,12 @@ kernelspec: name: python3 --- -```{code-cell} ipython3 +```{code-cell} :tags: [hide-input, hide-output] import warnings -warnings.filterwarnings('ignore') +warnings.filterwarnings("ignore") from fmriprep_denoise.dataset.atlas import ATLAS_METADATA from fmriprep_denoise.visualization import figures, utils @@ -29,33 +29,200 @@ path_root = utils.get_data_root() / "denoise-metrics" # Results: atlas level It is possible to view the data at atlas level! +Please click on the launch button to lunch the Binder instance for interactive data viewing. + +In the report we used four atlases, three of them came with multiple parcellation schemes. + +- Gordon atlas: 333 +- Schaefer 7 network atlas: 100, 200, 300, 400, 500, 600, 800 +- Multiresolution Intrinsic Segmentation Template (MIST): 7, 12, 20, 36, 64, 122, 197, 325, 444, “ROI” (210 parcels, 122 split by the midline) +- DiFuMo atlas: 64, 128, 256, 512, 1024 + +## Before we start: Loss of temporal degrees of freedom + +As any denoising strategy aims at a particular trade-off between the amount of noise removed and the preservation of degrees of freedom for signals, first and foremost, we would like to presentthe loss of temporal degrees of freedom. + +This is an important consideration accompanying the remaining metrics. + +```{code-cell} +:tags: [hide-input] + +from fmriprep_denoise.visualization import degrees_of_freedom_loss + + +def notebook_plot_loss_degrees_of_freedom(criteria_name, fmriprep_version): + datasets = ["ds000228", "ds000030"] + data = degrees_of_freedom_loss.load_data( + path_root, datasets, criteria_name, fmriprep_version + ) + degrees_of_freedom_loss.plot_stats(data) + + +criteria_name = widgets.Dropdown( + options=["stringent", "minimal", None], + value="stringent", + description="Threshould: ", + disabled=False, +) + +fmriprep_version = widgets.Dropdown( + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, +) + +interactive( + notebook_plot_loss_degrees_of_freedom, + criteria_name=criteria_name, + fmriprep_version=fmriprep_version, +) +``` + +## Each parcelation scheme + +We can also plot them by each parcellation schemes. + +This is the original way Ciric and colleagues (2017) presented their results! + +### Gordon atlas + +```{code-cell} +atlas = "gordon333" -```{code-cell} ipython3 dataset = widgets.Dropdown( - options=['ds000228', 'ds000030'], - description='Dataset : ', - disabled=False + options=["ds000228", "ds000030"], description="Dataset : ", disabled=False ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - description='fmriprep : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + description="fmriprep : ", + disabled=False, ) -atlas = widgets.Dropdown( - options=ATLAS_METADATA.keys(), - description='atlas : ', - disabled=False +dimension = widgets.Dropdown( + description="dimensions : ", + options=ATLAS_METADATA[atlas]["dimensions"], + disabled=False, +) + + +@interact(ds=dataset, f=fmriprep_version, d=dimension) +def show_atlas(ds, f, d): + print(ds, f, ATLAS_METADATA[atlas]["atlas"], "dimensions: ", d) + figures.plot_motion_resid(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_distance_dependence(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_network_modularity(ds, f, path_root, atlas_name=atlas, dimension=d) +``` + +### MIST + +```{code-cell} +atlas = "mist" + +dataset = widgets.Dropdown( + options=["ds000228", "ds000030"], description="Dataset : ", disabled=False +) +fmriprep_version = widgets.Dropdown( + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + description="fmriprep : ", + disabled=False, ) dimension = widgets.Dropdown( - description='dimensions : ', - disabled=False - ) + description="dimensions : ", + options=ATLAS_METADATA[atlas]["dimensions"], + disabled=False, +) + + +@interact(ds=dataset, f=fmriprep_version, d=dimension) +def show_atlas(ds, f, d): + print(ds, f, ATLAS_METADATA[atlas]["atlas"], "dimensions: ", d) + figures.plot_motion_resid(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_distance_dependence(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_network_modularity(ds, f, path_root, atlas_name=atlas, dimension=d) +``` + +### Schaefer 7 network + +```{code-cell} +atlas = "schaefer7networks" + +dataset = widgets.Dropdown( + options=["ds000228", "ds000030"], description="Dataset : ", disabled=False +) +fmriprep_version = widgets.Dropdown( + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + description="fmriprep : ", + disabled=False, +) +dimension = widgets.Dropdown( + description="dimensions : ", + options=ATLAS_METADATA[atlas]["dimensions"], + disabled=False, +) + + +@interact(ds=dataset, f=fmriprep_version, d=dimension) +def show_atlas(ds, f, d): + print(ds, f, ATLAS_METADATA[atlas]["atlas"], "dimensions: ", d) + figures.plot_motion_resid(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_distance_dependence(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_network_modularity(ds, f, path_root, atlas_name=atlas, dimension=d) +``` + +### DiFuMo + +```{code-cell} +atlas = "difumo" + +dataset = widgets.Dropdown( + options=["ds000228", "ds000030"], description="Dataset : ", disabled=False +) +fmriprep_version = widgets.Dropdown( + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + description="fmriprep : ", + disabled=False, +) +dimension = widgets.Dropdown( + description="dimensions : ", + options=ATLAS_METADATA[atlas]["dimensions"], + disabled=False, +) + + +@interact(ds=dataset, f=fmriprep_version, d=dimension) +def show_atlas(ds, f, d): + print(ds, f, ATLAS_METADATA[atlas]["atlas"], "dimensions: ", d) + figures.plot_motion_resid(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_distance_dependence(ds, f, path_root, atlas_name=atlas, dimension=d) + figures.plot_network_modularity(ds, f, path_root, atlas_name=atlas, dimension=d) +``` + +## View as atlas collection + +You can view the metrics by atlas collections here. + +We will summmarise the metrics by each atlas collection. + +**The summary statistics are computed on the fly, it might take a bit of time.** + +```{code-cell} +dataset = widgets.Dropdown( + options=["ds000228", "ds000030"], description="Dataset : ", disabled=False +) +fmriprep_version = widgets.Dropdown( + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + description="fmriprep : ", + disabled=False, +) +atlas = widgets.Dropdown( + description="atlas : ", options=list(ATLAS_METADATA.keys()), disabled=False +) + -@interact(ds=dataset, f=fmriprep_version, a=atlas, d=dimension) -def print_city(ds, f, a, d): - dimension.options = ATLAS_METADATA[a]['dimensions'] - print(ds, f, a, d) - figures.plot_motion_resid(ds, f, path_root, atlas_name=a, dimension=d) - figures.plot_distance_dependence(ds, f, path_root, atlas_name=a, dimension=d) - figures.plot_network_modularity(ds, f, path_root, atlas_name=a, dimension=d) +@interact(ds=dataset, f=fmriprep_version, a=atlas) +def show_atlas(ds, f, a): + print(ds, f, a) + figures.plot_motion_resid(ds, f, path_root, atlas_name=a, dimension=None) + figures.plot_distance_dependence(ds, f, path_root, atlas_name=a, dimension=None) + figures.plot_network_modularity(ds, f, path_root, atlas_name=a, dimension=None) ``` diff --git a/content/research_report/results-group.md b/content/research_report/results-group.md index 1c230c5..b4421c0 100644 --- a/content/research_report/results-group.md +++ b/content/research_report/results-group.md @@ -11,11 +11,12 @@ kernelspec: name: python3 --- -```{code-cell} ipython3 +```{code-cell} :tags: [hide-input] import warnings -warnings.filterwarnings('ignore') + +warnings.filterwarnings("ignore") import ipywidgets as widgets from ipywidgets import interactive @@ -23,65 +24,78 @@ from fmriprep_denoise.visualization import utils path_root = utils.get_data_root() / "denoise-metrics" strategy_order = list(utils.GRID_LOCATION.values()) -group_order = {'ds000228': ['adult', 'child'], 'ds000030': ['control', 'ADHD', 'bipolar', 'schizophrenia']} -datasets = ['ds000228', 'ds000030'] -datasets_baseline = {'ds000228': 'adult', 'ds000030': 'control'} +group_order = { + "ds000228": ["adult", "child"], + "ds000030": ["control", "ADHD", "bipolar", "schizophrenia"], +} +datasets = ["ds000228", "ds000030"] +datasets_baseline = {"ds000228": "adult", "ds000030": "control"} ``` # Results: dataset level Here we provides alternative visualisation of the benchmark results from the manuscript. -Please click on the launch botton to lunch the Binder instance for interactive data viewing. +Please click on the launch button to lunch the Binder instance for interactive data viewing. -The benchmark was performed on two Long-Term Support (LTS) versions of fMRIPrep (20.2.1 and 20.2.5) and two OpenNeuro datasets (ds000228 and ds000030). +The benchmark was performed on two Long-Term Support (LTS) versions of fMRIPrep (`20.2.1` and `20.2.5`) and two OpenNeuro datasets (`ds000228` and `ds000030`). For the demographic information and gross mean framewise displacement, it is possible to generate the report based on three levels of quality control filters (no filter, minimal, stringent). ## Sample and subgroup size change based on quality control criteria -We would like to perform the benchmark on subjects with reasonable qulaity of data to reflect the descisions researchers make in data analysis. +We would like to perform the benchmark on subjects with reasonable qulaity of data to reflect the decisions researchers make in data analysis. We modified the criteria for filtering data from Parkes 2018 to suit our dataset better and ensure enough time points for functional connectivity analysis. The stringent threshold removes subjects based on two criteria: 1. removes subjects with mean framewise displacement above 0.25 mm 2. removes subjects with more than 80% of the volumes missing when filtering the time series with a 0.2 mm framewise displacement. -Parkes 2018 used a stricter criteria for remaining volumes (20%). However this will removed close to or more than 50% of the subjects from the datasets. +Parkes 2018 used a stricter criteria for remaining volumes (20%). However this will removed close to or more than 50% of the subjects from the datasets. In addition, we included the minimal threshold from Parkes 2018 (removes subjects with mean framewise displacement above 0.55 mm) for readers to expore. -```{code-cell} ipython3 +```{code-cell} :tags: [hide-input] import pandas as pd from fmriprep_denoise.visualization import tables from fmriprep_denoise.features.derivatives import get_qc_criteria + def demographic_table(criteria_name, fmriprep_version): criteria = get_qc_criteria(criteria_name) - ds000228 = tables.lazy_demographic('ds000228', fmriprep_version, path_root, **criteria) - ds000030 = tables.lazy_demographic('ds000030', fmriprep_version, path_root, **criteria) - - desc = pd.concat({'ds000228': ds000228, 'ds000030': ds000030}, axis=1, names=['dataset']) + ds000228 = tables.lazy_demographic( + "ds000228", fmriprep_version, path_root, **criteria + ) + ds000030 = tables.lazy_demographic( + "ds000030", fmriprep_version, path_root, **criteria + ) + + desc = pd.concat( + {"ds000228": ds000228, "ds000030": ds000030}, axis=1, names=["dataset"] + ) desc = desc.style.set_table_attributes('style="font-size: 12px"') print("Generating new tables...") display(desc) + criteria_name = widgets.Dropdown( - options=['stringent', 'minimal', None], - value='stringent', - description='Threshould: ', - disabled=False + options=["stringent", "minimal", None], + value="stringent", + description="Threshould: ", + disabled=False, ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, +) +interactive( + demographic_table, criteria_name=criteria_name, fmriprep_version=fmriprep_version ) -interactive(demographic_table, criteria_name=criteria_name, fmriprep_version=fmriprep_version) ``` You can also use different exclusion criteria to explore the motion profiles of different subgroups in the dataset. @@ -89,286 +103,345 @@ You can also use different exclusion criteria to explore the motion profiles of ## Motion profile of each dataset -We can see overall the adults have less gross motion than children in ds000228. -Between different clinical groups in ds000030, the schizophrania group displays a marked difference in motion comparing to the healthy control. +We can see overall the adults have less gross motion than children in `ds000228`. +Between different clinical groups in `ds000030`, the schizophrania group displays a marked difference in motion comparing to the healthy control. -```{code-cell} ipython3 +```{code-cell} :tags: [hide-input] from fmriprep_denoise.visualization import mean_framewise_displacement def notebook_plot_mean_fd(criteria_name, fmriprep_version): - stats = mean_framewise_displacement.load_data(path_root, criteria_name, fmriprep_version) + stats = mean_framewise_displacement.load_data( + path_root, criteria_name, fmriprep_version + ) mean_framewise_displacement.plot_stats(stats) - + criteria_name = widgets.Dropdown( - options=['stringent', 'minimal', None], - value='stringent', - description='Threshould: ', - disabled=False + options=["stringent", "minimal", None], + value="stringent", + description="Threshould: ", + disabled=False, ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, +) +interactive( + notebook_plot_mean_fd, + criteria_name=criteria_name, + fmriprep_version=fmriprep_version, ) -interactive(notebook_plot_mean_fd, criteria_name=criteria_name, fmriprep_version=fmriprep_version) ``` ## Similarity amongst denoised connectomes We plotted the correlations among connectomes denoised with different denoisng strategies to get a general sense of the data. -We see connectome denoised with or without global signal regressor.formed two separate clusters. -The baseline and ICA-AROMA denoised connectome do not belong to any clusters. +We see connectome denoised with or without global signal regressor formed two separate clusters. +The baseline and ICA-AROMA denoised connectome do not belong to any clusters. ICA-AROMA potentially captures much more different source of noise than the others. -```{code-cell} ipython3 +```{code-cell} from fmriprep_denoise.visualization import connectivity_similarity + def notebook_plot_connectomes(fmriprep_version): - average_connectomes = connectivity_similarity.load_data(path_root, datasets, fmriprep_version) + average_connectomes = connectivity_similarity.load_data( + path_root, datasets, fmriprep_version + ) connectivity_similarity.plot_stats(average_connectomes) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) interactive(notebook_plot_connectomes, fmriprep_version=fmriprep_version) ``` ## Loss of temporal degrees of freedom -```{code-cell} ipython3 +As any denoising strategy aims at a particular trade-off between the amount of noise removed and the preservation of degrees of freedom for signals, first and foremost, we would like to presentthe loss of temporal degrees of freedom. + +This is an important consideration accompanying the remaining metrics. + +```{code-cell} :tags: [hide-input] from fmriprep_denoise.visualization import degrees_of_freedom_loss + def notebook_plot_loss_degrees_of_freedom(criteria_name, fmriprep_version): - data = degrees_of_freedom_loss.load_data(path_root, datasets, criteria_name, fmriprep_version) + data = degrees_of_freedom_loss.load_data( + path_root, datasets, criteria_name, fmriprep_version + ) degrees_of_freedom_loss.plot_stats(data) + criteria_name = widgets.Dropdown( - options=['stringent', 'minimal', None], - value='stringent', - description='Threshould: ', - disabled=False + options=["stringent", "minimal", None], + value="stringent", + description="Threshould: ", + disabled=False, ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_loss_degrees_of_freedom, criteria_name=criteria_name, fmriprep_version=fmriprep_version) +interactive( + notebook_plot_loss_degrees_of_freedom, + criteria_name=criteria_name, + fmriprep_version=fmriprep_version, +) ``` ## Quality control / functional connectivity (QC-FC) -```{code-cell} ipython3 +QC-FC (Power et al., 2015) quantifies the correlation between mean framewise displacement and functional connectivity. +This is calculated by a partial correlation between mean framewise displacement and connectivity, with age and sex as covariates. +The denoising methods should aim to reduce the QC-FC value. +Significance tests associated with the partial correlations were performed, +and correlations with P-values above the threshold of = 0.05 deemed significant. + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_qcfc(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'p_values') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "p_values" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) + fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_qcfc, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_qcfc, criteria_name="stringent", fmriprep_version=fmriprep_version +) ``` ### False discovery rate corrected QC-FC -```{code-cell} ipython3 +A version of this analysis corrected for multiple comparisons using the false discovery rate (Benjamini & Hochberg, 1995) is available here. + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_qcfc_fdr(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'fdr_p_values') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "fdr_p_values" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_qcfc_fdr, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_qcfc_fdr, criteria_name="stringent", fmriprep_version=fmriprep_version +) ``` ### Medians of absolute values of QC-FC -```{code-cell} ipython3 +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_qcfc_median(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'median') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "median" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_qcfc_median, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_qcfc_median, + criteria_name="stringent", + fmriprep_version=fmriprep_version, +) ``` ## Residual distance-dependent effects of subject motion on functional connectivity (DM-FC) -```{code-cell} ipython3 +To determine the residual distance-dependence of subject movement, we first calculated the Euclidean distance between the centers of mass of each pair of parcels (Power et al., 2012). +Closer parcels generally exhibit greater impact of motion on connectivity. +We then correlated the distance separating each pair of parcels and the associated QC-FC correlation of the edge connecting those parcels. +We report the absolute correlation values and expect to see a general trend toward zero correlation after confound regression. + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_distance(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'distance') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "distance" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_distance, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_distance, criteria_name="stringent", fmriprep_version=fmriprep_version +) ``` ## Louvain network modularity -```{code-cell} ipython3 +Confound regressors have the potential to remove real signals in addition to motion-related noise. +In order to evaluate this possibility, we computed modularity quality, +an explicit quantification of the degree to which there are structured subnetworks in a given network - in this case the denoised connectome (Satterthwaite et al., 2012). +Modularity quality is quantified by graph community detection based on the Louvain method (Rubinov & Sporns, 2010), +implemented in the Brain Connectivity Toolbox (Rubinov & Sporns, 2010). + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_modularity(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'modularity') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "modularity" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_modularity, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_modularity, + criteria_name="stringent", + fmriprep_version=fmriprep_version, +) ``` -### Average Pearson’s correlation between mean framewise displacement and Louvain network modularity after denoising +### Average Pearson's correlation between mean framewise displacement and Louvain network modularity after denoising -```{code-cell} ipython3 +If confound regression and censoring were removing real signals in addition to motion-related noise, we would expect modularity to decline. +To understand the extent of correlation between modularity and motion, +we computed the partial correlation between subjects' modularity values and mean framewise displacement, +with age and sex as covariates. + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_modularity_motion(criteria_name, fmriprep_version): - data, measure = motion_metrics.load_data(path_root, datasets, criteria_name, fmriprep_version, 'modularity_motion') + data, measure = motion_metrics.load_data( + path_root, datasets, criteria_name, fmriprep_version, "modularity_motion" + ) motion_metrics.plot_stats(data, measure) - -# criteria_name = widgets.Dropdown( -# options=['stringent', 'minimal', None], -# value='stringent', -# description='Threshould: ', -# disabled=False -# ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) -interactive(notebook_plot_modularity_motion, criteria_name='stringent', fmriprep_version=fmriprep_version) +interactive( + notebook_plot_modularity_motion, + criteria_name="stringent", + fmriprep_version=fmriprep_version, +) ``` ### Correlation between mean framewise displacement and Louvain network modularity after denoising. -```{code-cell} ipython3 +In both datasets, the data-driven strategies and strategies with GSR performed consistently worse than baseline. +The overall trend across strategies is similar to QC-FC with the exception of the baseline strategy. +The reason behind this observation could be a reduction of variance in the Louvain network modularity metric for GSR-based denoising strategies. + +Hence, we plotted the correlations of baseline, a base strategy, a GSR variation from one parcellation scheme (DiFuMo 64 components)to demonstrate this lack of variance. + +```{code-cell} from fmriprep_denoise.visualization import motion_metrics + def notebook_plot_joint_scatter(dataset, base_strategy, fmriprep_version): - motion_metrics.plot_joint_scatter(path_root, dataset, base_strategy, fmriprep_version) + motion_metrics.plot_joint_scatter( + path_root, dataset, base_strategy, fmriprep_version + ) + - dataset = widgets.Dropdown( - options=['ds000228', 'ds000030'], - value='ds000228', - description='Dataset: ', - disabled=False + options=["ds000228", "ds000030"], + value="ds000228", + description="Dataset: ", + disabled=False, ) fmriprep_version = widgets.Dropdown( - options=['fmriprep-20.2.1lts', 'fmriprep-20.2.5lts'], - value='fmriprep-20.2.1lts', - description='Preporcessing version : ', - disabled=False + options=["fmriprep-20.2.1lts", "fmriprep-20.2.5lts"], + value="fmriprep-20.2.1lts", + description="Preporcessing version : ", + disabled=False, ) base_strategy = widgets.Dropdown( - options=['simple', 'srubbing.5', 'srubbing.2', 'aroma'], - value='simple', - description='Base denoise strategy ', - disabled=False + options=["simple", "srubbing.5", "srubbing.2"], + value="simple", + description="Base denoise strategy ", + disabled=False, ) -interactive(notebook_plot_joint_scatter, dataset=dataset, base_strategy=base_strategy, fmriprep_version=fmriprep_version) +interactive( + notebook_plot_joint_scatter, + dataset=dataset, + base_strategy=base_strategy, + fmriprep_version=fmriprep_version, +) ``` ## Ranking strategies from best to worst, based on four benchmark metrics -```{code-cell} ipython3 +We ranked four metrics from best to worst. +Larger circles with brighter color represent higher ranking. +Metric "correlation between network modularity and motion" has been excluded from the summary as it is potentially a poor measure. +Loss of temporal degrees of freedom is a crucial measure that should be taken into account alongside the metric rankings. + +```{code-cell} from fmriprep_denoise.visualization import strategy_ranking data = strategy_ranking.load_data(path_root, datasets)