Memory and Resting-State Connectivity in Acute Transient Global Amnesia: A Case-Control fMRI Study.
The 5 matches
- [1] § Materials and Methods › Statistical Analysis ↔ analysis/functions.py, lines 129–219 · score 0.76 · Aligned Rank Transform, Post hoc, Shapiro, ART, ANOVA, scores
- [2] § Results › Functional MRI ↔ analysis/ICA.ipynb, lines 50–65 · score 0.73 · dorsal DMN, ventral DMN, right SN, voxel, ECN, ICA
- [3] § Materials and Methods › Neuropsychological Battery ↔ analysis/main_analysis.ipynb, lines 81–200 · score 0.58 · cued recall, free recall, anterograde memory, incidental, clap, Mnemosyne
- [4] § Materials and Methods › Statistical Analysis ↔ analysis/functions.py, lines 129–219 · score 0.58 · post hoc, Linear, predictors, variables, fitted, Model
- [5] § Results › Neuropsychological Results ↔ analysis/main_analysis.ipynb, lines 81–200 · score 0.54 · cued recall, free recall, Anterograde memory, incidental, AES, scores
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 785 lines · 34 KB · no license · 2 matches
- import numpy as np
- import math
- from scipy import stats
- import scipy
- import scipy.io
- from scipy import stats
- import scipy.cluster.hierarchy as sch
- import statsmodels.stats.api as sms
- import statsmodels.formula.api as smf
- from statsmodels.stats.anova import AnovaRM
- import pingouin as pg
- from scipy.stats import shapiro, levene, rankdata
- import pandas as pd
- import matplotlib.pyplot as plt
- import seaborn as sns
- import plotly.figure_factory as ff
- import os
- import warnings
- toyDict = {}
- # To change backslashes : follow path by .replace(os.sep, '/')
- cwd = os.getcwd()
- fMRI_dataroot = cwd + '/../data/fMRI_data'
- neuropsy_dataroot = cwd + '/../data/neuropsy_data/Comportement/Bases de données/'
- IRMs_datapath = cwd + '/../data/sMRI/ANALYSE-ICTUS-5AOUT-15_editedElias.ods'
- #plots_path = cwd + '/../results/plots/'
- plots_path = cwd + '/../plots/'
- #plots_path = 'C:/Users/Lenovo/Desktop/Ictus/analysis/fMRI_neuropsy_analysis/../results/plots/'
- def gather(param, pT1 = 'pT1', pT2 = 'pT2', pT3 = 'pT3', cT1 = 'cT1', cT2 = 'cT2', cT3 = 'cT3', trans = toyDict, df = pd.DataFrame()):
- translated = trans.loc[param]
- if translated[pT1] == 'NaN' : pT1values = [np.nan]*20
- else : pT1values = df[pT1][translated[pT1]]
- if translated[pT2] == 'NaN' : pT2values = [np.nan]*20
- else : pT2values = df[pT2][translated[pT2]]
- if translated[pT3] == 'NaN' : pT3values = [np.nan]*20
- else : pT3values = df[pT3][translated[pT3]]
- if translated[cT1] == 'NaN' : cT1values = [np.nan]*20
- else : cT1values = df[cT1][translated[cT1]]
- if translated[cT2] == 'NaN' : cT2values = [np.nan]*20
- else : cT2values = df[cT2][translated[cT2]]
- if translated[cT3] == 'NaN' : cT3values = [np.nan]*20
- else : cT3values = df[cT3][translated[cT3]]
- return [pT1values, pT2values, pT3values, cT1values, cT2values, cT3values]
- ## STATISTICAL ANALYSIS ##
- ##########################
- def confint(data, confidence=0.95):
- a = 1.0 * np.array(data)
- n = len(a)
- m, se = np.mean(a), scipy.stats.sem(a)
- h = se * scipy.stats.t.ppf((1 + confidence) / 2., n-1)
- return m, m-h, m+h
- def aligned_rank_transform(df, subject_col, dv, within, between):
- """
- Perform the Aligned Rank Transform on the data.
- Parameters:
- df : DataFrame
- Data containing the variables.
- subject_col : str
- The column name representing subjects.
- dv : str
- The dependent variable column name.
- within : str
- The within-subject factor column name.
- between : str
- The between-subject factor column name.
- Returns:
- DataFrame
- The transformed data with an added column for aligned ranks.
- """
- # Align the data
- #global overall_mean, aligned_data, within_means, between_means, cell_means
- overall_mean = df[dv].mean()
- aligned_data = df.copy()
- # Calculate marginal means for the main effects and interaction
- within_means = df.groupby(within)[dv].transform('mean')
- between_means = df.groupby(between)[dv].transform('mean')
- cell_means = df.groupby([within, between])[dv].transform('mean')
- # Align data for main effects and interaction
- #aligned_within = df[dv] - within_means + overall_mean
- #aligned_between = df[dv] - between_means + overall_mean
- #aligned_interaction = df[dv] - cell_means + overall_mean
- residuals = df[dv] - cell_means
- aligned_within = residuals + within_means - overall_mean
- aligned_between = residuals + between_means - overall_mean
- aligned_interaction = residuals + cell_means - overall_mean
- # Verify that each column of aligned responses sums to zero
- within_bool = np.isclose(aligned_within.sum(), 0), "Aligned within responses do not sum to zero"
- between_bool = np.isclose(aligned_between.sum(), 0), "Aligned between responses do not sum to zero"
- interaction_bool = np.isclose(aligned_interaction.sum(), 0), "Aligned interaction responses do not sum to zero"
- for boolean, name in zip((within_bool, between_bool, interaction_bool), ('within', 'betweenn', 'interaction')) :
- if not boolean : print('WARNING : {} alignement does not sum to zero'.format(name))
- # Rank the aligned data
- aligned_data['AlignedRankWithin'] = rankdata(aligned_within)
- aligned_data['AlignedRankBetween'] = rankdata(aligned_between)
- aligned_data['AlignedRankInteraction'] = rankdata(aligned_interaction)
- return aligned_data
- def myANOVA(data, display = False, perform_parametric_anova = False): # 2nd argument : perform regular anova whatever Shapiro's results
- if type(data) != type(np.array(0)) : data = np.array(data)
- # Flatten the array into a long format
- data_flat = data.flatten()
- # Generate the Subject, Group, and Time labels correctly
- subjects = np.hstack( (np.tile(np.arange(1, 21), 3), np.tile(np.arange(21, 41), 3))) # Each subject appears 6 times (3 times per group)
- times = np.tile(['T1']*20 + ['T2']*20 + ['T3']*20, 2) # Each time point repeats for all subjects in both groups
- groups = np.array(['Patient']*60 + ['Control']*60) # Each group label is repeated for 3 time points for all 20 subjects
- # Creating the DataFrame
- df = pd.DataFrame({
- 'Subject': subjects,
- 'Group': groups,
- 'Time': times,
- 'Score': data_flat
- })
- # ASSUMPTIONS CHECK
- ###################
- # Convert categorical variables to dummy variables for regression
- df_dummies = pd.get_dummies(df, columns=['Group', 'Time'], drop_first=True)
- # Fit a linear regression model with dummy variables
- results = pg.linear_regression(df_dummies[['Group_Patient', 'Time_T2', 'Time_T3']], df_dummies['Score'])
- df_dummies['predicted'] = results['coef'].values[0] + np.dot(df_dummies[['Group_Patient', 'Time_T2', 'Time_T3']], results['coef'].values[1:])
- df['residuals'] = df['Score'] - df_dummies['predicted']
- # Normality test on the residuals
- normality = shapiro(df['residuals'])
- # Homogeneity of variances test
- homoscedasticity = levene(df[df['Time'] == 'T1']['Score'],
- df[df['Time'] == 'T2']['Score'],
- df[df['Time'] == 'T3']['Score'])
- # Sphericity test using Mauchly's test in pingouin
- sphericity = pg.sphericity(df, dv='Score', subject='Subject', within='Time')
- # ART-transfrom (ranking within each combination of Group and Time for each Subject) if data non normal
- #if normality.pvalue < 0.05 :
- #df['Score'] = df.groupby(['Subject', 'Group', 'Time'])['Score'].rank(method='average')
- #df['Score'] = df.groupby(['Group', 'Time'])['Score'].rank(method='average')
- #return df, normality, homoscedasticity, sphericity
- # Perform the two-way repeated measures ANOVA
- #############################################
- if (normality.pvalue < 0.05 and not perform_parametric_anova) :
- # Apply Aligned Rank Transform
- print('Performing ART ANOVA...')
- artDf = aligned_rank_transform(df, subject_col='Subject', dv='Score', within='Time', between='Group')
- aov_between = pg.mixed_anova(dv='AlignedRankBetween', between='Group', within='Time', subject='Subject', data=artDf)
- aov_between = aov_between.loc[aov_between['Source'] == 'Group']
- aov_within = pg.mixed_anova(dv='AlignedRankWithin', between='Group', within='Time', subject='Subject', data=artDf)
- aov_within = aov_within.loc[aov_within['Source'] == 'Time']
- aov_interaction = pg.mixed_anova(dv='AlignedRankInteraction', between='Group', within='Time', subject='Subject', data=artDf)
- aov_interaction = aov_interaction.loc[aov_interaction['Source'] == 'Interaction']
- aov = pd.concat([aov_within, aov_between, aov_interaction], axis=0, ignore_index=True)
- else:
- dv = aov = pg.mixed_anova(dv='Score', between='Group', within='Time', subject='Subject', data=df)
- #df['Group_Time'] = df['Group'] + '_' + df['Time']
- #tukey = pg.pairwise_tukey(data=df, dv='Score', between='Group_Time')
- # Post-hoc tests within subjects with FDR correction (Benjamini-Hochberg)
- #post_hoc_within = pg.pairwise_ttests(data=df, dv='value', within='time', subject='subject', padjust='fdr_bh')
- # (nice but studies only one factor...)
- # rem to do Games-Howell post-hoc tests if homoscedasticity not met !!! (if it exists for mixed models...)
- if display :
- print("ANOVA Table:")
- print(aov)
- print("\nNormality test (Shapiro-Wilk) on residuals:")
- print(f"Statistic: {normality.statistic}, p-value: {normality.pvalue}")
- print("\nLevene's Test for Homogeneity of variances across time points:")
- print(f"Statistic: {homoscedasticity.statistic}, p-value: {homoscedasticity.pvalue}")
- print("\nSphericity test (Mauchly's):")
- print(f"W-value: {sphericity[0]}, p-value: {sphericity[1]}, is sphericity met: {sphericity[2]}")
- return aov, normality, homoscedasticity, sphericity #, tukey
- def cluster_corr(corr_array, inplace=False):
- """
- Rearranges the correlation matrix, corr_array, so that groups of highly
- correlated variables are next to eachother
- Parameters
- ----------
- corr_array : pandas.DataFrame or numpy.ndarray
- a NxN correlation matrix
- Returns
- -------
- pandas.DataFrame or numpy.ndarray
- a NxN correlation matrix with the columns and rows rearranged
- """
- pairwise_distances = sch.distance.pdist(corr_array)
- linkage = sch.linkage(pairwise_distances, method='complete')
- cluster_distance_threshold = pairwise_distances.max()/2
- idx_to_cluster_array = sch.fcluster(linkage, cluster_distance_threshold,
- criterion='distance')
- idx = np.argsort(idx_to_cluster_array)
- if not inplace:
- corr_array = corr_array.copy()
- if isinstance(corr_array, pd.DataFrame):
- return corr_array.iloc[idx, :].T.iloc[idx, :]
- return corr_array[idx, :][:, idx]
- #DON'T FORGET we've included data computations in the function
- def compute_pairwise_tests(data, anova_res, sign_threshold, nsessions):
- ## Determine, from ANOVA results, what comparisons should be made
- if not type(anova_res) == type(pd.DataFrame()) : aov = anova_res[0] # Take only anova results, without shapiro, Levene...
- else : aov = anova_res
- pvalues = np.empty((nsessions*2,nsessions*2))
- pvalues[:] = np.nan
- if ( (aov['Source'] == 'No anova provided').any() \
- or (aov.loc[aov['Source'] == 'Interaction']['p-unc'] < sign_threshold).any() \
- or ( (aov.loc[aov['Source'] == 'Time']['p-unc'] < sign_threshold).any() \
- and (aov.loc[aov['Source'] == 'Group']['p-unc'] < sign_threshold).any())) :
- indexes_to_compare = [(0,1), (1,2), (0,2), (3,4), (4,5), (3,5), (0,3), (1,4), (2,5)]
- comparisons = ['PxP', 'PxP', 'PxP_wide', 'CxC', 'CxC', 'CxC_wide', 'PxC', 'PxC', 'PxC']
- else :
- if ( aov.loc[aov['Source'] == 'Time']['p-unc'] < sign_threshold ).any() :
- indexes_to_compare = [(0,1), (1,2), (0,2), (3,4), (4,5), (3,5)]
- comparisons = ['PxP', 'PxP', 'PxP_wide', 'CxC', 'CxC', 'CxC_wide']
- elif ( aov.loc[aov['Source'] == 'Group']['p-unc'] < sign_threshold ).any() :
- indexes_to_compare = [(0,3), (1,4), (2,5)]
- comparisons = ['PxC', 'PxC', 'PxC']
- else :
- indexes_to_compare = []
- comparisons = []
- ## Perform pairwise T tests
- for (x, y) in indexes_to_compare : # We could use the comparisons list here
- if abs(x - y) >= nsessions : # Between-group comparison
- pvalues[(x,y)] = stats.ttest_ind(data[x], data[y], equal_var=False).pvalue
- else : #Within-group comparison
- pvalues[(x,y)] = stats.ttest_rel(data[x], data[y]).pvalue
- return pvalues, indexes_to_compare, comparisons
- def plot_pairwise_tests(data, anova_res, sign_threshold, nsessions, xPositions,
- plot_type, confint_upper_bounds = np.zeros(6), confint_lower_bounds = np.zeros(6), lower_controls_asterisks = 0):
- # Plots pairwise comparisons and returns the min and max y values of the plotted comparisons, along with the scale and scale divider
- if plot_type == 'boxplot' :
- maxvalue = np.max(data)
- minvalue = np.min(data)
- minvalue_except_pT1 = np.min(data[1:]) # We won't consider pT1 min value for plotting within-controls significativity
- elif plot_type == 'graphchart' :
- maxvalue = np.max([np.nanmean(data[i]) + confint_upper_bounds[i] for i in range(len(data))])
- minvalue = np.min([np.nanmean(data[i]) - confint_lower_bounds[i] for i in range(len(data))])
- minvalue_except_pT1 = np.min(np.nanmean(data[1:,:], axis = 1) - confint_lower_bounds[1:]) # We won't consider pT1 min value for plotting within-controls significativity
- else :
- raise ValueError('Choose a plot type between graphchart and boxplot')
- scale = (maxvalue - minvalue)
- #plt.ylim([minvalue - 0.15, maxvalue+scale/5])
- #plt.ylim(60)
- # Generic prototype supporting two sessions : [(x,y) for (x,y) in itertools.product('twice the list...') if x != y]
- # We want to compare :
- # Les p entre eux -> (0,1), (1,2), (0,2)
- # Les c entre eux -> (3,4), (4,5), (3,5)
- # Les p et c appariés -> (0,3), (1,4), (2,5)
- pvalues, indexes_to_compare, comparisons = compute_pairwise_tests(data, anova_res, sign_threshold, nsessions)
- # Determine display from pairwise comparison results
- y_loc_asterisk_max = 0 # will be modified if asterisks are plotted. Will determine the top limit of the y axis
- y_loc_asterisk_min = minvalue # will be modified if asterisks are below mean value. Legend and anova results will be plotted below if plotted
- scdvd = 12 #scale divider, modulates vertical spacing of significance lines
- for (x,y), comparison in zip(indexes_to_compare, comparisons) :
- pvalue = pvalues[x,y]
- if np.isnan(pvalue) : print('NaN pvalue')
- if pvalue < 0.005 : asterisk = '*\u2009*\u2009*'
- elif pvalue < 0.01 : asterisk = '*\u2009*'
- elif pvalue < 0.05 : asterisk = '*'
- else : asterisk = 'ns'
- #offset = 0.05 * (pvalue < 0.01)
- #y_loc_asterisk = scale/3 + max([data_means[i]+yerr[i] for i in [session, session+nsessions]])
- if pvalue >=0.05 :
- weight = 'normal'
- fontsize = 10
- else :
- weight = 'bold'
- fontsize = 12
- # Y_locations
- spacing = 1.5*scale/scdvd # Average spacing between max data points and lines, and between lines
- yloc_lowest_upper_line = np.array((maxvalue + scale/scdvd, maxvalue+ scale/scdvd)) \
- - spacing * (not any(['PxC' in comp for comp in comparisons])) # If no b/w grp comparisons we lower within-patients comparisons
- yloc_lower_line = np.array((minvalue_except_pT1 - scale/scdvd, minvalue_except_pT1 - scale/scdvd))
- if comparison == 'PxC' : # Between-group comparison
- yloc_line = yloc_lowest_upper_line
- elif comparison == 'PxP' :
- yloc_line = yloc_lowest_upper_line + spacing
- elif comparison == 'PxP_wide' :
- yloc_line = yloc_lowest_upper_line + 2*spacing
- elif comparison == 'CxC' :
- yloc_line = yloc_lower_line + lower_controls_asterisks
- elif comparison == 'CxC_wide' :
- yloc_line = yloc_lower_line - spacing + lower_controls_asterisks
- groupwise_xPositions = [xPositions[i] for i in (0,2,4,1,3,5)]# x positions ordered according to group orders in data
- #groupwise_xPositions = [xPositions[i] for i in (1,3,5,1,3,5)]
- # x_locations
- if comparison in ('PxP', 'CxC') :
- lag = 0.02 #Add some space between adjacent lines
- if y in (1,4) : xloc_line = ((groupwise_xPositions[x], groupwise_xPositions[y]-lag))
- elif x in (1,4) : xloc_line = ((groupwise_xPositions[x]+lag, groupwise_xPositions[y]))
- else : print('PROBLEM')
- else :
- intergroup_comp_wider = 0 # Only useful for graphcharts, see below
- if plot_type == "graphchart" :
- if abs(y - x) == 3 : # Means intergroups comparison
- intergroup_comp_wider = 0.03 # otherwise intergroup comparison lines too short
- xloc_line = ((groupwise_xPositions[x]-intergroup_comp_wider, groupwise_xPositions[y]+intergroup_comp_wider))
- # Colors
- if comparison in ('CxC', 'CxC_wide') : color = 'steelblue'
- elif comparison in ('PxP', 'PxP_wide') : color = 'indianred'
- else : color = 'black'
- y_loc_asterisk = yloc_line[0] + 0.2*scale/scdvd
- if y_loc_asterisk > y_loc_asterisk_max : y_loc_asterisk_max = y_loc_asterisk
- if y_loc_asterisk < y_loc_asterisk_min : y_loc_asterisk_min = y_loc_asterisk
- #return asterisk, weight, fontsize, color, xloc_line, yloc_line, y_loc_asterisk
- plt.text(sum(xloc_line)/2, y_loc_asterisk, asterisk, horizontalalignment = 'center',
- size = fontsize, weight = weight, color = color)
- plt.plot(xloc_line,
- yloc_line, color = color, linewidth = 1)
- #if y_loc_asterisk_max != 0 : plt.ylim(top = y_loc_asterisk_max + scale/scdvd )
- return y_loc_asterisk_min, y_loc_asterisk_max, scale, scdvd
- def niceGraphChart(data, title = 'Title', ylabel = 'Mean $\\rho$',
- xlabels = 'default', legend_loc = 'lower left', yerr = 'confint',
- save_as = 'do_not_save', plots_path = plots_path, show = True, sign = False,
- anova_res = pd.DataFrame(['No anova provided'], [0], ['Source']), sign_threshold = 0.05, fullsize=False,
- lower_controls_asterisks = 0, display_aov_text = False, x_aov_text = 1, y_aov_text = 1): # lower_controls_asterisk : DYI solution for lowering the comparison lines when misplaced (e.g. cross the patients data lines...). Enter negative values
- nsessions = int(len(data) /2)
- if xlabels == 'default' :
- if nsessions == 2 : xlabels = ('Day 0', 'Day 3')
- else : xlabels = ("Day 0", "Day 3", "Day 90")
- data_means = [np.nanmean(elem) for elem in data]
- pData_means=data_means[:nsessions]
- cData_means=data_means[nsessions:]
- print(pData_means)
- confints = []
- for sessionTime in range(6):
- confints.append(confint(data[sessionTime]))
- # Get the upper and lower spans from confints and mean
- upper_confint_spans = [confint[2] - confint[0] for confint in confints]
- lower_confint_spans = [confint[0] - confint[1] for confint in confints]
- #if yerr == 'std' : yerr = [np.std(elem) for elem in data]
- interstice = 0.05 # Between the two datapoints of two groups at one session
- if fullsize : fig = plt.figure(dpi=300)
- else : fig = plt.figure()
- Controls = plt.errorbar(
- x=(np.arange(nsessions) + interstice),#xlabels,
- y=cData_means,
- yerr=(lower_confint_spans[nsessions:], upper_confint_spans[nsessions:]),#yerr[nsessions:],#std_cT1vT2sign[3:],
- capsize=4,
- marker='o',
- color='steelblue',
- markersize=4,
- linewidth=2,
- zorder = 1,
- linestyle='-') # alternative : '--' for dashed
- Patients = plt.errorbar(
- x=xlabels,
- y=pData_means,
- yerr=(lower_confint_spans[:nsessions], upper_confint_spans[:nsessions]),#yerr[:nsessions],
- capsize=4,
- marker='s',
- color='indianred',
- markersize=4,
- linewidth=2,
- zorder = 2,
- linestyle='-')
- xPositions = [(x - interstice/2, x + interstice/2) for x in range(nsessions)]
- xPositions = [x for tup in xPositions for x in tup]
- if sign :
- y_loc_asterisk_min, y_loc_asterisk_max, scale, scdvd = plot_pairwise_tests(data, anova_res, sign_threshold, nsessions, xPositions,
- 'graphchart', upper_confint_spans, lower_confint_spans, lower_controls_asterisks )
- '''
- if sign :
- maxvalue = max(np.add(data_means,yerr))
- minvalue = min(np.subtract(data_means,yerr))
- scale = (maxvalue - minvalue) /5
- #plt.ylim([minvalue - 0.15, maxvalue+1])
- plt.ylim([minvalue - 0.15*scale, maxvalue+scale])
- for session in range(int(len(data_means)/2)):
- pvalue = stats.ttest_ind(data[session], data[session+nsessions], equal_var=False).pvalue
- if pvalue < 0.005 : asterisk = '*\u2009*\u2009*'
- elif pvalue < 0.01 : asterisk = '*\u2009*'
- elif pvalue < 0.05 : asterisk = '*'
- else : asterisk = 'ns'
- offset = 0.05 * (pvalue < 0.01)
- y_loc_asterisk = scale/3 + max([data_means[i]+yerr[i] for i in [session, session+nsessions]])
- if pvalue >=0.05 : weight = 'normal'
- else : weight = 'bold'
- plt.text(session - offset, y_loc_asterisk, asterisk, size = 12, weight = weight)
- '''
- if sign :
- if y_loc_asterisk_max != 0 : plt.ylim(bottom = y_loc_asterisk_min - scale/scdvd, top = y_loc_asterisk_max + scale/scdvd)
- plt.xlim(-0.15,nsessions -1 +0.15)
- legend = plt.legend((Patients, Controls),("Patients","Controls"), loc = legend_loc)
- #plot aov results :
- if display_aov_text and not (anova_res[0]['Source'] == 'No anova provided').any():
- aov_res = anova_res[0]
- aov_text_time = f"T : F({aov_res['DF1'][0]},{aov_res['DF2'][0]}) = {np.round(aov_res['F'][0], 2)}, p = {np.round(aov_res['p-unc'][0], 2)}"
- aov_text_group = f"G : F({aov_res['DF1'][1]},{aov_res['DF2'][1]}) = {np.round(aov_res['F'][1], 2)}, p = {np.round(aov_res['p-unc'][1], 2)}"
- aov_text_int = f"X : F({aov_res['DF1'][2]},{aov_res['DF2'][2]}) = {np.round(aov_res['F'][2], 2)}, p = {np.round(aov_res['p-unc'][2], 2)}"
- aov_text = '\n'.join([aov_text_time, aov_text_group, aov_text_int])
- # Place text box horizontally aligned to legend
- # Get the bounding box of the legend in display coordinates
- bbox = legend.get_window_extent()
- # Get the transformation to convert display coordinates to data coordinates
- trans = plt.gca().transData.inverted()
- # Transform the bounding box to data coordinates
- bbox_in_data = bbox.transformed(trans)
- # Get the coordinates of the legend (x, y, width, height) in data coordinates
- legend_coordinates_data = bbox_in_data.bounds
- y_aov_text = legend_coordinates_data[1] + legend_coordinates_data[3] / 2 # Adjust y to match the center of the legend box
- x_aov_text = 2.1
- text_box_height = legend_coordinates_data[3] # The height of the legend
- # Add text with a matching box height
- plt.text(x_aov_text, y_aov_text, aov_text, size=8, bbox=dict(facecolor='none', edgecolor='gray', boxstyle=f'round,pad={text_box_height/2}'),
- horizontalalignment='right', verticalalignment='center')
- plt.ylabel(ylabel)
- plt.title(title)
- ## widen both limits to give some whitespace to the plot
- #plt.ylim(-5, 105)
- #plt.xlim(-0.2, 3.2)
- # plt.savefig('Fig2.png', dpi=300, bbox_inches='tight')
- #plt.margins(5,5)
- if not save_as == 'do_not_save':
- plt.savefig(plots_path + save_as, dpi=300, bbox_inches='tight')
- print('Saved at' + str(plots_path+save_as))
- if show : plt.show()
- def niceBoxplot(data, title = 'Title', ylabel = 'Score',
- xlabels = 'default', legend_loc = 'lower left', yerr = 'default', scatter = True, notch = True,
- save_as = 'do_not_save', plots_path = plots_path, show = True, sign = False,
- anova_res = pd.DataFrame(['No anova provided'], [0], ['Source']),
- sign_threshold = 0.05, fullsize=False, lower_controls_asterisks = 0, display_aov_text = False) :
- nsessions = int(len(data) /2)
- if xlabels == 'default' :
- if nsessions == 2 : xlabels = ('Day 0', 'Day 3')
- else : xlabels = ('Day 0', 'Day 3', 'Day 90')
- if fullsize : fig = plt.figure(dpi=300)
- else : fig = plt.figure()
- #data = [data[i] for i in [index in tup for tup in [(0+session, 0+session +nsessions) for session in range(nsessions)] for index in tup]]
- nsessions = int(len(data)/2)
- order = [index for tup in [(0+session, 0+session +nsessions) for session in range(nsessions)] for index in tup]
- data_reordered = [data[index] for index in order]
- interstice = 0.3
- xPositions = [(x-interstice/2, x+interstice/2) for x in range(nsessions)]
- xPositions = [x for tup in xPositions for x in tup]
- xs = [np.random.normal(x , 0.05, len(data[0])) for x in xPositions]
- colored_plots = not scatter # We'll fill the boxes if we don't scatter
- box = plt.boxplot(data_reordered, positions = xPositions, showfliers = False, autorange = True, widths = 0.25, notch = notch, \
- patch_artist = colored_plots)#, labels=xlabels)
- palette = [color for tup in [('indianred', 'steelblue')*nsessions] for color in tup]
- if scatter :
- for x, val, c in zip(xs, data_reordered, palette):
- plt.scatter(x, val, alpha=0.8, color=c, s = 10)
- else :
- for patch, color in zip(box['boxes'], palette):
- patch.set_facecolor(color)
- if sign : y_loc_asterisk_min, y_loc_asterisk_max, scale, scdvd = plot_pairwise_tests(data, anova_res, sign_threshold, nsessions, xPositions, 'boxplot',
- lower_controls_asterisks = lower_controls_asterisks)
- '''
- if sign :
- maxvalue = np.max(data)
- minvalue = np.min(data)
- minvalue_except_pT1 = np.min(data[1:]) # We won't consider pT1 min value for plotting within-controls sign
- scale = (maxvalue - minvalue)
- plt.ylim([minvalue - 0.15, maxvalue+scale/5])
- #plt.ylim([minvalue - 0.15, maxvalue+1])
- #plt.ylim([minvalue - 0.15*scale, maxvalue+scale])
- for session in [2*i for i in range(nsessions)]:
- pvalue = stats.ttest_ind(data[session], data[session+1], equal_var=False).pvalue
- if pvalue < 0.005 : asterisk = '*\u2009*\u2009*'
- elif pvalue < 0.01 : asterisk = '*\u2009*'
- elif pvalue < 0.05 : asterisk = '*'
- else : asterisk = 'ns'
- #offset = 0.05 * (pvalue < 0.01)
- #y_loc_asterisk = scale/3 + max([data_means[i]+yerr[i] for i in [session, session+nsessions]])
- y_loc_asterisk = maxvalue + scale/10
- if pvalue >=0.05 : weight = 'normal'
- else : weight = 'bold'
- plt.text(int(session/2), y_loc_asterisk, asterisk, horizontalalignment = 'center', size = 12, weight = weight)
- plt.plot((xPositions[session], xPositions[session+1]),
- (maxvalue + scale/12, maxvalue+scale/12), color = 'black', linewidth = 1)
- '''
- #plt.xlim(-0.15,nsessions -1 +0.15)
- #plt.legend(("Patients","Controls"), colors = ('steelblue', 'indianred'), loc = legend_loc)
- from matplotlib.lines import Line2D
- colors = ('indianred', 'steelblue')
- lines = [Line2D([0], [0], color=c, linewidth=1, linestyle='None', marker = 'o', markersize = 3) for c in colors]
- labels = ['Patients', 'Controls']
- legend = plt.legend(lines, labels, loc = legend_loc, handletextpad = 0.1, handlelength=1, borderaxespad=0.5, fontsize = 8)
- if sign :
- if y_loc_asterisk_max != 0 and y_loc_asterisk_min < y_loc_asterisk_max:
- plt.ylim(bottom = y_loc_asterisk_min - scale/scdvd, top = y_loc_asterisk_max + scale/scdvd)
- #plt.xlim(-0.15,nsessions -1 +0.15)
- #legend = plt.legend((Patients, Controls),("Patients","Controls"), loc = legend_loc)
- #plot aov results :
- if display_aov_text and not (anova_res[0]['Source'] == 'No anova provided').any():
- aov_res = anova_res[0]
- aov_text_time = f"T : F({aov_res['DF1'][0]},{aov_res['DF2'][0]}) = {np.round(aov_res['F'][0], 2)}, p = {np.round(aov_res['p-unc'][0], 2)}"
- aov_text_group = f"G : F({aov_res['DF1'][1]},{aov_res['DF2'][1]}) = {np.round(aov_res['F'][1], 2)}, p = {np.round(aov_res['p-unc'][1], 2)}"
- aov_text_int = f"X : F({aov_res['DF1'][2]},{aov_res['DF2'][2]}) = {np.round(aov_res['F'][2], 2)}, p = {np.round(aov_res['p-unc'][2], 2)}"
- aov_text = '\n'.join([aov_text_time, aov_text_group, aov_text_int])
- # Place text box horizontally aligned to legend
- # Get the bounding box of the legend in display coordinates
- bbox = legend.get_window_extent()
- # Get the transformation to convert display coordinates to data coordinates
- trans = plt.gca().transData.inverted()
- # Transform the bounding box to data coordinates
- bbox_in_data = bbox.transformed(trans)
- # Get the coordinates of the legend (x, y, width, height) in data coordinates
- legend_coordinates_data = bbox_in_data.bounds
- y_aov_text = legend_coordinates_data[1] + legend_coordinates_data[3] / 2 # Adjust y to match the center of the legend box
- x_aov_text = 2.6
- text_box_height = legend_coordinates_data[3] # The height of the legend
- # Add text with a matching box height
- plt.text(x_aov_text, y_aov_text, aov_text, size=8, bbox=dict(facecolor='none', edgecolor='gray', boxstyle=f'round,pad={text_box_height/2}'),
- horizontalalignment='right', verticalalignment='center')
- plt.ylabel(ylabel)
- plt.xticks(ticks = range(len(xlabels)), labels=xlabels)
- plt.title(title)
- if not save_as == 'do_not_save' : plt.savefig(plots_path + save_as)
- plt.show()
- def RLvsRI_plot(RL, RI, RECO = np.zeros((6,20)), save_as = 'do_not_save', title = 'Title', ylabel = 'score', session = 1, nsessions = 3,
- need_to_add_RI_to_RL = True, sign = True):
- session -= 1
- if need_to_add_RI_to_RL :
- pT1_RI_sum = np.add(RI[session], RL[session])
- cT1_RI_sum = np.add(RI[session+nsessions], RL[session+nsessions])
- pT1_RECO_sum = np.add(RECO[session], pT1_RI_sum)
- cT1_RECO_sum = np.add(RECO[session+nsessions], cT1_RI_sum)
- else :
- pT1_RI_sum = RI[session]
- cT1_RI_sum = RI[session+nsessions]
- pT1_RECO_sum = RECO[session]
- cT1_RECO_sum = RECO[session+nsessions]
- fig, ax = plt.subplots(dpi=300)
- pT1_RL_data = np.mean(RL[session])
- cT1_RL_data = np.mean(RL[session+nsessions])
- pT1_RI_data = np.mean(pT1_RI_sum)
- cT1_RI_data = np.mean(cT1_RI_sum)
- pT1_RECO_data = np.mean(pT1_RECO_sum)
- cT1_RECO_data = np.mean(cT1_RECO_sum)
- ax.bar('Controls', cT1_RECO_data, color = 'moccasin')
- ax.bar('Controls', cT1_RI_data, color = 'orange')
- ax.bar('Controls', cT1_RL_data, color = 'blue')
- ax.bar('Patients', pT1_RECO_data, color = 'moccasin')
- ax.bar('Patients', pT1_RI_data, color = 'orange')
- ax.bar('Patients', pT1_RL_data, color = "blue")
- ax.legend(('RECO', 'RI', 'RL'))
- if sign :
- maxvalue = max(pT1_RI_data, cT1_RI_data)
- minvalue = 0
- scale = (maxvalue - minvalue) /5
- #plt.ylim([minvalue - 0.15, maxvalue+1])
- plt.ylim([minvalue - 0.15*scale, maxvalue+scale])
- pvalue = stats.ttest_ind(pT1_RI_sum, cT1_RI_sum, equal_var=False).pvalue
- if pvalue < 0.005 : asterisk = '*\u2009*\u2009*'
- elif pvalue < 0.01 : asterisk = '*\u2009*'
- elif pvalue < 0.05 : asterisk = '*'
- else : asterisk = 'ns'
- offset = 0.05 * (pvalue < 0.01)
- #y_loc_asterisk = scale/3 + max([data_means[i]+yerr[i] for i in [session, session+nsessions]])
- y_loc_asterisk = maxvalue + scale/2
- if pvalue >=0.05 : weight = 'normal'
- else : weight = 'bold'
- plt.text(0.5 - offset, y_loc_asterisk, asterisk, size = 12, weight = weight)
- plt.plot((0,1), (y_loc_asterisk - scale/8, y_loc_asterisk - scale/8), color = 'black')
- ax.set_ylabel(ylabel)
- ax.set_title(title)
- if not save_as == 'do_not_save' : plt.savefig(plots_path + save_as)
- plt.show()
- def niceScatterplot(data1, data2, plotEdges = True, title = 'Title', ylabel = 'Score', showMeans = False,
- xlabels = ('T1', 'T2'), legend_loc = 'upper right', yerr = 'default', zscores = False,
- save_as = 'do_not_save', plots_path = plots_path, show = True, sign = False, fullsize=False):
- fig, ax = plt.subplots(tight_layout=True, dpi = 100)
- #colors = ["cornflowerblue", "salmon"]
- #colors = ["cornflowerblue", "cornflowerblue"]
- colors = ['darkseagreen', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
- 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
- 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
- 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson']
- colors = ['DarkRed', 'DarkOrange', 'DarkGreen', 'DarkCyan','DarkBlue','LightSalmon',
- 'LightGoldenRodYellow',
- 'LightGreen',
- 'LightSkyBlue',
- 'LightSlateGray',
- 'Salmon',
- 'SandyBrown',
- 'MediumSeaGreen',
- 'CornflowerBlue',
- 'SlateGray',
- 'Tomato',
- 'Gold',
- 'LimeGreen',
- 'SkyBlue',
- 'SteelBlue']
- width=0.3
- dotsize = 25
- #plt.xlim(-0.5, 1.5)
- plt.tick_params(axis='x', which='major', labelsize='10')
- #diffT1T2 = np.array([cDiff_T1vT2[:32], pDiff_T1vT2[:32]]).transpose()
- if zscores : data1, data2 = stats.zscore(data1), stats.zscore(data2)
- data = np.array([data1, data2])
- x_store = np.array([np.ones(data1.shape), np.ones(data1.shape)])
- y_store = np.array([np.ones(data1.shape), np.ones(data1.shape)])
- for i, l in enumerate(xlabels):
- x = np.ones(data.shape[1])*i + (np.random.rand(data.shape[1])*width-width/2.)
- ax.scatter(x, data[i], color=colors, s=dotsize)
- x_store[i] = x
- y_store[i] = data[i]
- median = np.median(data[i])#.mean()
- if showMeans : ax.plot([i-width/2. - 0.1, i+width/2. +0.1],[median,median], color="k")
- if plotEdges :
- for i in range(data.shape[1]):
- plt.plot([x_store[0][i], x_store[1][i]],[y_store[0][i], y_store[1][i]], color = colors[i])
- ax.set_xticks(range(len(xlabels)))
- ax.set_xticklabels(xlabels)
- ax.set_ylabel(ylabel, fontsize=11)
- ax.set_title(title, fontsize=12)
- def linregPlot(X = None, Y = None):
- reg = stats.linregress(X, Y)
- x_pred = np.arange(min(X), max(X), 0.01)
- y_pred = np.multiply(reg.slope, x_pred) + reg.intercept
- plt.scatter(X, Y)
- plt.plot(x_pred, y_pred, color = 'red')
- summary_stats = 'R² : ' + str(np.round(reg.rvalue, decimals = 2)) + '\np-value : ' + str(np.round(reg.pvalue, decimals = 2))
- scale = (max(X) - min(X))/4
- plt.text(max(X)- scale, max(Y), s = summary_stats, horizontalalignment = 'left', verticalalignment = 'top', size = 12, c = 'r')
functions.py at commit c950a5a, no license · at the source
Overview
- ToNIC Toulouse NeuroImaging Center, UMR 1214, Universit. De Toulouse, INSERM, Paul Sabatier University (UT3) Toulouse France
- CNRS, Cerco Toulouse France
- Department of Neurology Neuroscience Centre, Toulouse‐Purpan University Hospital Toulouse Cedex France
- Department of Emergency Medicine University Hospital of Toulouse Toulouse France
- Laboratory of Epidemiology and Analyses in Public Health UMR 1295 Inserm, Toulouse University France
- Department of Neurolog Clinical Investigation Center, CIC1436, Toulouse University Hospital Toulouse France
- Department of Neuroradiology University Hospital of Toulouse Toulouse France
Abstract
Background and Objectives: Transient global amnesia (TGA) is a striking model of isolated amnesia. While hippocampal lesions are well described, the network‐level mechanisms and the precise neuropsychological profile remain debated. Our objective was thus to characterize functional and neuropsychological correlates of acute TGA and their longitudinal evolution.
Methods: Prospective, single‐center case–control study of 20 patients with acute TGA and 20 age‐ and sex‐matched healthy controls. All participants completed neuropsychological testing and underwent structural and functional MRI at three time points: acute phase (< 24 h from onset), day 3, and 3 months. Primary outcomes were neuropsychological performance across episodic, semantic, and metamemory domains and resting‐state fMRI connectivity within the episodic memory network. Secondary outcomes were functional connectivity within the Default Mode (DMN), Executive (ECN), and Salience (SN) networks.
Results: A total of 40 participants were included (20 patients with TGA, mean age 65.5 years, 45% women; 20 controls, mean age 64.3 years, 45% women). In patients, median delay from symptoms' onset to MRI was 6.67 h. Neuropsychologically, patients showed profound multimodal anterograde amnesia during the acute phase, resolving by 3 months. This deficit was largely isolated, sparing semantic memory and metamemory. Structurally, small bilateral lesions were present in most patients. Functionally, acute hypoconnectivity was observed within the extended hippocampal system, particularly between parahippocampal and cingulate cortices, normalizing by 3 months. No consistent disruption was found in large‐scale networks (default mode, executive control, salience).
Interpretation: TGA is associated with transient, selective hypoconnectivity within the mesiotemporal–cingulate episodic memory network, aligning with previous reports and further precising the functional anatomy. The finding of a profound anterograde amnesia was replicated and its recovery timecourse was elucidated. Semantic memory and metamemory remain preserved, clarifying inconsistencies in prior reports. These findings suggest that TGA reflects a transient limbic dysconnectivity syndrome rather than a diffuse network disorder, reconciling structural lesions with clinical and functional data.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.
EliasElOtmani/TGA
c950a5a092e4dcf92e29236d88503057babccfae, 13 February 2026Availability: 1 check, the latest on 29 September 2026: the link answers
- 29 September 2026: the link answers
11 files
- analysis/
.ipynb_checkpoints/ , Jupyter, 72 linesICA-checkpoint.ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 75 linesdemographics-checkpoint. ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 1,330 linesfMRI_neuropsy_notebook-C opy1-checkpoint.ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 1,643 linesfMRI_neuropsy_notebook-C opy2-checkpoint.ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 2,067 linesfMRI_neuropsy_notebook-c heckpoint.ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 1,774 linesmain_analysis-checkpoint .ipynb - analysis/
.ipynb_checkpoints/ , Jupyter, 32 linessMRI_analysis-checkpoint .ipynb - analysis/
ICA.ipynb , Jupyter, 73 lines, 1 match - analysis/
demographics.ipynb , Jupyter, 75 lines - analysis/
functions.py , Python, 785 lines, 2 matches - analysis/
main_analysis.ipynb , Jupyter, 1,774 lines, 2 matches - repository limit reached (2,000 files or 30 MB): the rest is at the source (1 files)
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 11 scripts, each with its path and the digest of its content;
- 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data Availability Statement
Light data such as neuropsychological data, 1st‐level preprocessed fMRI ROI‐to‐ROI data and python codes are available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 29 September 2026: the first record
Recorded: type, language, journal, pages, dates, 11 authors, 3 keywords, 3 funders, 45 references.
Cite
This paper
El Otmani, E., Barbeau, E., Lemesle, B., Milongo‐Rigal, E., Fernandez, S., Charpentier, S., Albucher, J., Raposo, N., Bonneville, F., Péran, P., & Pariente, J. (2026). Memory and Resting-State Connectivity in Acute Transient Global Amnesia: A Case-Control fMRI Study. Annals of clinical and translational neurology, 10.1002/
BibTeX
@article{elotmani2026mem
author = {El Otmani, Elias and Barbeau, Emmanuel and Lemesle, Béatrice and Milongo‐Rigal, Emilie and Fernandez, Sophie and Charpentier, Sandrine and Albucher, Jean‐François and Raposo, Nicolas and Bonneville, Fabrice and Péran, Patrice and Pariente, Jérémie},
title = {{Memory and Resting-State Connectivity in Acute Transient Global Amnesia: A Case-Control fMRI Study}},
journal = {Annals of clinical and translational neurology},
year = {2026},
month = apr,
pages = {10.1002/
publisher = {Wiley},
issn = {2328-9503},
doi = {10.1002/
url = {https://
pmid = {41958247},
pmcid = {PMC13394162}
}
RIS
TY - JOUR
AU - El Otmani, Elias
AU - Barbeau, Emmanuel
AU - Lemesle, Béatrice
AU - Milongo‐Rigal, Emilie
AU - Fernandez, Sophie
AU - Charpentier, Sandrine
AU - Albucher, Jean‐François
AU - Raposo, Nicolas
AU - Bonneville, Fabrice
AU - Péran, Patrice
AU - Pariente, Jérémie
TI - Memory and Resting-State Connectivity in Acute Transient Global Amnesia: A Case-Control fMRI Study
T2 - Annals of clinical and translational neurology
J2 - Ann Clin Transl Neurol
PY - 2026
DA - 2026/
SP - 10.1002/
SN - 2328-9503
PB - Wiley
DO - 10.1002/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1002/
"type": "article-journal",
"title": "Memory and Resting-State Connectivity in Acute Transient Global Amnesia: A Case-Control fMRI Study",
"container-title": "Annals of clinical and translational neurology",
"author": [
{
"family": "El Otmani",
"given": "Elias"
},
{
"family": "Barbeau",
"given": "Emmanuel"
},
{
"family": "Lemesle",
"given": "Béatrice"
},
{
"family": "Milongo‐Rigal",
"given": "Emilie"
},
{
"family": "Fernandez",
"given": "Sophie"
},
{
"family": "Charpentier",
"given": "Sandrine"
},
{
"family": "Albucher",
"given": "Jean‐François"
},
{
"family": "Raposo",
"given": "Nicolas"
},
{
"family": "Bonneville",
"given": "Fabrice"
},
{
"family": "Péran",
"given": "Patrice"
},
{
"family": "Pariente",
"given": "Jérémie"
}
],
"container-title-short":
"page": "10.1002/
"DOI": "10.1002/
"PMID": "41958247",
"PMCID": "PMC13394162",
"ISSN": "2328-9503",
"publisher": "Wiley",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
10
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41467-026-75662-w [code]
- Distinct Roles of Deep and Superficial Cortical Layers in Tone Prediction, Comparison, and Adaptation in Human Auditory Cortices.Journal: Nature communicationsIn common: Pingouin, Nilearn, statsmodels, 6 other tools, cognitive, 1 reference
- [2] doi:10.1038/s41467-026-74566-z [code]
- Low-dimensional and optimised representations of high-level information in the expert brain.Journal: Nature communicationsIn common: Pingouin, Nilearn, Plotly, 7 other tools, cognitive
- [3] doi:10.1162/imag.a.1269 [code]
- From early to contemporary normative modeling: Mapping individual differences in neurophysiological signals.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Pingouin, Nilearn, Plotly, 7 other tools
- [4] doi:10.1162/imag.a.105 [code]
- Right posterior theta reflects human parahippocampal phase resetting by salient cues during goal-directed navigationJournal: n/aIn common: Pingouin, Nilearn, statsmodels, 6 other tools, fMRI, cognitive
- [5] doi:10.1002/agm2.70073 [code]
- Foreign Language Learning in Older Adults Modifies Resting-State Functional Connectivity Between the Subcortical Structures and the Cortex.Journal: Aging medicine (Milton (N.S.W))In common: Nilearn, statsmodels, NiBabel, 5 other tools, fMRI, 2 references
- [6] doi:10.1162/netn.a.544 [code]
- Brain network reconfiguration during reward prediction error processing.Journal: Network neuroscience (Cambridge, Mass.)In common: Nilearn, Plotly, statsmodels, 6 other tools, fMRI, cognitive
- [7] doi:10.1016/j.xcrm.2026.102793 [code]
- A predictive corticospinal model for pain perception.Journal: Cell reports. MedicineIn common: Pingouin, Nilearn, statsmodels, 6 other tools, fMRI
- [8] doi:10.1038/s41597-026-07377-y [code]
- An open-access multi-site fMRI dataset for investigating conscious visual perception.Journal: Scientific dataIn common: Pingouin, Nilearn, statsmodels, 6 other tools, fMRI
- [9] doi:10.1162/imag.a.1321 [code]
- Phase similarity between similar objects indicates representational merging across retrieval training but not sleep.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Pingouin, Nilearn, Plotly, 6 other tools, cognitive
- [10] doi:10.1002/alz.71365 [code]
- Benchmarking speech biomarkers of Alzheimer's against cognitive and neural measures.Journal: Alzheimer's & dementia : the journal of the Alzheimer's AssociationIn common: Pingouin, statsmodels, seaborn, 4 other tools, fMRI, cognitive, 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 11 scripts, and 5 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:8896fde34ae84df7…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
