Spatial analysis of paraneoplastic cerebellar degeneration in ovarian cancer with anti-Yo syndrome and SCA1.
The 12 matches
- [1] § Methods › Analysis ↔ notebooks/3d_thickness_analysis.ipynb, lines 604–650 · score 0.93 · Lobule III, Lobule VIIIA, Lobule IX, Lobule VIIB, Lobule VIIIB, Lobule Crus
- [2] § Methods › Analysis ↔ notebooks/network_analysis.ipynb, lines 397–441 · score 0.92 · Lobule III, Lobule VIIIA, Lobule IX, Lobule VIIB, Lobule VIIIB, Lobule Crus
- [3] § Methods › Analysis ↔ notebooks/group_classification.ipynb, lines 409–515 · score 0.88 · Random Forest classifier, class weights, residualized feature, age residualized, CV, stratified
- [4] § Methods › Analysis ↔ notebooks/network_analysis.ipynb, lines 915–957 · score 0.79 · absolute thresholds, proportional thresholding, NetworkX, strongest, network metric, density
- [5] § Methods › Analysis ↔ notebooks/group_differences.ipynb, lines 358–428 · score 0.76 · bootstrap cluster stability, silhouette scores, Adjusted Rand, ARI, patient
- [6] § Results › Classification of patient groups ↔ notebooks/group_classification.ipynb, lines 409–515 · score 0.74 · random forest classifier, age residualized features, class weights, Permutation, shuffles, fit
- [7] § Results › Graph-based metrics ↔ notebooks/network_analysis.ipynb, lines 865–913 · score 0.73 · correlation thresholds, global efficiency, network metric, node strength, global clustering, density
- [8] § Results › Graph-based metrics ↔ notebooks/network_analysis.ipynb, lines 915–957 · score 0.71 · proportional thresholding, global efficiency, node strength, Global clustering, absolute, edge
- [9] § Results › Cortical thickness analysis ↔ notebooks/group_differences.ipynb, lines 358–428 · score 0.58 · silhouette score, Adjusted Rand, Cluster stability, patients, PCD
- [10] § Results › Classification of patient groups ↔ notebooks/group_classification.ipynb, lines 125–173 · score 0.57 · random forest classifier, ROC curves, folds, AUCs, residualized
- [11] § Methods › Analysis ↔ notebooks/network_analysis.ipynb, lines 518–579 · score 0.57 · Node strength, clustering coefficient, shortest, efficiency, edge, weights
- [12] § Methods › Analysis ↔ notebooks/network_analysis.ipynb, lines 518–579 · score 0.54 · NetworkX, graph metrics, Connectivity
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
Jupyter notebook · 1,059 lines · 34 KB · no license · 6 matches
- # %%
- import nibabel as nib
- import os
- import numpy as np
- import pandas as pd
- from sklearn.linear_model import LinearRegression
- from statsmodels.api import OLS, add_constant
- from statsmodels.stats.multitest import multipletests
- import matplotlib.pyplot as plt
- from matplotlib.colors import ListedColormap
- from nilearn.plotting import plot_stat_map
- from nilearn.image import load_img
- import scipy.stats as stats
- from nilearn import plotting, datasets
- from nilearn.plotting import plot_anat, plot_stat_map, view_img
- from scipy.ndimage import center_of_mass
- from nilearn.image import resample_to_img
- from scipy import stats
- from netplotbrain import plot as netplot
- plt.rcParams.update({
- 'font.size': 12,
- 'axes.titlesize': 14,
- 'axes.labelsize': 12,
- 'xtick.labelsize': 10,
- 'ytick.labelsize': 10,
- 'legend.fontsize': 10,
- 'figure.dpi': 100,
- 'savefig.dpi': 900,
- 'font.family': 'sans-serif',
- 'font.sans-serif': ['Arial', 'DejaVu Sans'],
- 'pdf.fonttype': 42,
- })
- # %%
- def compute_barycenters(mask_path, exclude_regions, target_affine):
- """
- Compute barycenters for regions in a given NIfTI mask, aligned to the target atlas space.
- """
- mask_img = nib.load(mask_path)
- mask_data = mask_img.get_fdata()
- unique_regions = np.unique(mask_data)[1:] # Exclude background (0)
- coords = []
- included_regions = []
- for region in unique_regions:
- if region not in exclude_regions:
- region_mask = (mask_data == region)
- barycenter = center_of_mass(region_mask)
- coords.append(barycenter)
- included_regions.append(region)
- # Transform barycenters to target atlas space
- coords = np.array(coords)
- transformed_coords = nib.affines.apply_affine(target_affine, coords)
- return transformed_coords, included_regions
- def extract_region_thickness(data_path, subject_files, mask_path, included_regions):
- """
- Extract region-wise cortical thickness data using a custom mask.
- """
- mask_img = nib.load(mask_path)
- mask_data = mask_img.get_fdata()
- region_thickness = []
- for path in subject_files:
- subject_img = nib.load(data_path + path)
- resampled_img = resample_to_img(subject_img, mask_img, interpolation="nearest")
- resampled_data = resampled_img.get_fdata()
- subject_region_means = [
- np.median(resampled_data[mask_data == region]) for region in included_regions
- ]
- region_thickness.append(subject_region_means)
- return np.array(region_thickness)
- def compute_structural_covariance(data):
- """
- Compute structural covariance as pairwise correlations between nodes.
- """
- n_regions = data.shape[1]
- corr_matrix = np.zeros((n_regions, n_regions))
- for i in range(n_regions):
- for j in range(i, n_regions):
- if np.std(data[:, i]) == 0 or np.std(data[:, j]) == 0:
- corr_matrix[i, j] = corr_matrix[j, i] = 0 # Avoid divide by zero
- else:
- corr_matrix[i, j] = corr_matrix[j, i] = np.corrcoef(data[:, i], data[:, j])[0, 1]
- return corr_matrix
- def plot_network_on_brain(coords, adj_matrix, title, filename, template=None):
- """
- Plot the network on the brain using NetPlotBrain.
- """
- edges = []
- for i in range(adj_matrix.shape[0]):
- for j in range(i + 1, adj_matrix.shape[1]):
- if adj_matrix[i, j] != 0:
- edges.append({"i": i, "j": j, "weight": adj_matrix[i, j]})
- edges_df = pd.DataFrame(edges)
- nodes_df = pd.DataFrame(coords, columns=["x", "y", "z"])
- netplot(
- template="MNI152NLin2009cAsym",
- nodes=nodes_df,
- edges=edges_df,
- node_size=5,
- edge_color="weight",
- edge_cmap="coolwarm",
- margin=0.05,
- #view="preset-6",
- view = 'LRSP',
- savename=filename,
- )
- # %%
- # Paths to thickness data for two groups
- group1_paths = [
- "IXI158.nii", "IXI204.nii", "IXI237.nii", "IXI251.nii", "IXI288.nii",
- "IXI383.nii", "IXI384.nii", "IXI399.nii", "IXI420.nii", "IXI433.nii",
- "IXI462.nii", "IXI464.nii", "IXI476.nii", "IXI491.nii", "IXI498.nii",
- "IXI518.nii", "IXI538.nii"
- ]
- group2_paths = [
- "Patient1.nii", "Patient2.nii", "Patient3.nii", "Patient4.nii",
- "Patient5.nii", "Patient6.nii", "Patient8.nii", "Patient9.nii",
- "Patient10.nii", "Patient11.nii", "Patient12.nii"
- ]
- group3_paths = ["SCA013.nii", "SCA029.nii", "SCA033.nii", "SCA039.nii",
- "SCA068.nii", "SCA069.nii", "SCA076.nii", "SCA077.nii",
- "SCA083.nii", "SCA084.nii", "SCA087.nii", "SCA090.nii",
- "SCA093.nii", "SCA094.nii", "SCA095.nii", "SCA096.nii",
- "SCA097.nii"
- ]
- data_path="../data/normal_yo_SCA/"
- # %%
- # Load mask and compute barycenters
- mask_path = "../data/mni_structures_job1687583.nii"
- mask_img = nib.load(mask_path)
- atlas = datasets.fetch_atlas_schaefer_2018()
- target_affine = mask_img.affine
- #target_affine = nib.load(atlas["maps"]).affine # Get affine from atlas
- exclude_regions = [13, 113] # Exclude regions
- coords, included_regions = compute_barycenters(mask_path, exclude_regions, target_affine)
- # %%
- # Extract region-wise cortical thickness
- group1_data = extract_region_thickness(data_path, group1_paths, mask_path, included_regions)
- group2_data = extract_region_thickness(data_path, group2_paths, mask_path, included_regions)
- group3_data = extract_region_thickness(data_path, group3_paths, mask_path, included_regions)
- # %%
- np.save('../data/group1_data.npy', group1_data)
- np.save('../data/group2_data.npy', group2_data)
- np.save('../data/group3_data.npy', group3_data)
- # Load the array
- group1_data = np.load('../data/group1_data.npy')
- group2_data = np.load('../data/group2_data.npy')
- group3_data = np.load('../data/group3_data.npy')
- # %%
- # Compute structural covariance matrices
- corr_matrix_group1 = compute_structural_covariance(group1_data)
- corr_matrix_group2 = compute_structural_covariance(group2_data)
- corr_matrix_group3 = compute_structural_covariance(group3_data)
- # %%
- threshold = 0.0
- adj_matrix_group1 = np.where(np.abs(corr_matrix_group1) > threshold, corr_matrix_group1, 0)
- adj_matrix_group2 = np.where(np.abs(corr_matrix_group2) > threshold, corr_matrix_group2, 0)
- adj_matrix_group3 = np.where(np.abs(corr_matrix_group3) > threshold, corr_matrix_group3, 0)
- # %%
- # Compute difference matrix
- diff_matrix = adj_matrix_group2 - adj_matrix_group1
- diff_matrix_13 = adj_matrix_group3 - adj_matrix_group1
- diff_matrix_23 = adj_matrix_group2 - adj_matrix_group3
- # %%
- from scipy.stats import ttest_ind
- # %%
- # Perform pairwise t-tests with FDR correction
- n_nodes = group1_data.shape[1]
- p_values = []
- indices = []
- # Collect p-values
- for i in range(n_nodes):
- for j in range(i + 1, n_nodes):
- t_stat, p_value = ttest_ind(group1_data[:, i], group2_data[:, j]) # Pairwise comparison
- p_values.append(p_value)
- indices.append((i, j))
- # Apply FDR correction
- rejected, p_values_corrected, _, _ = multipletests(p_values, alpha=0.05, method="fdr_bh")
- # Update significance matrix
- sig_matrix = np.zeros((n_nodes, n_nodes))
- for idx, (i, j) in enumerate(indices):
- if rejected[idx]:
- sig_matrix[i, j] = sig_matrix[j, i] = 1 - p_values_corrected[idx]
- # %%
- # Perform pairwise t-tests with FDR correction
- n_nodes = group1_data.shape[1]
- p_values = []
- indices = []
- # Collect p-values
- for i in range(n_nodes):
- for j in range(i + 1, n_nodes):
- t_stat, p_value = ttest_ind(group1_data[:, i], group3_data[:, j])
- p_values.append(p_value)
- indices.append((i, j))
- # Apply FDR correction
- rejected, p_values_corrected, _, _ = multipletests(p_values, alpha=0.05, method="fdr_bh")
- # Update significance matrix
- sig_matrix_13 = np.zeros((n_nodes, n_nodes))
- for idx, (i, j) in enumerate(indices):
- if rejected[idx]:
- sig_matrix_13[i, j] = sig_matrix_13[j, i] = 1 - p_values_corrected[idx]
- # %%
- # Perform pairwise t-tests with FDR correction
- n_nodes = group1_data.shape[1]
- p_values = []
- indices = []
- # Collect p-values
- for i in range(n_nodes):
- for j in range(i + 1, n_nodes):
- t_stat, p_value = ttest_ind(group2_data[:, i], group3_data[:, j])
- p_values.append(p_value)
- indices.append((i, j))
- # Apply FDR correction
- rejected, p_values_corrected, _, _ = multipletests(p_values, alpha=0.05, method="fdr_bh")
- # Update significance matrix
- sig_matrix_23 = np.zeros((n_nodes, n_nodes))
- for idx, (i, j) in enumerate(indices):
- if rejected[idx]:
- sig_matrix_23[i, j] = sig_matrix_23[j, i] = 1 - p_values_corrected[idx]
- # %%
- def plot_combined_adjacency_matrices(adj_group1, adj_group2, diff_matrix, sig_matrix, filename, groupname_1, groupname_2):
- """
- Plot adjacency matrices for two groups, their difference, and the significant clusters in a single layout.
- """
- fig, ax = plt.subplots(1, 4, figsize=(24, 6))
- cmap = "RdBu_r"
- vmin, vmax = -1, 1 # Adjusted for correlation range
- ax[0].imshow(adj_group1, cmap=cmap, vmin=vmin, vmax=vmax)
- ax[0].set_title(groupname_1)
- ax[0].set_xlabel("Nodes")
- ax[0].set_ylabel("Nodes")
- ax[1].imshow(adj_group2, cmap=cmap, vmin=vmin, vmax=vmax)
- ax[1].set_title(groupname_2)
- ax[1].set_xlabel("Nodes")
- ax[2].imshow(diff_matrix, cmap="RdBu_r", vmin=-1, vmax=1)
- ax[2].set_title("Difference Matrix")
- ax[2].set_xlabel("Nodes")
- ax[3].imshow(sig_matrix, cmap="binary", interpolation="nearest")
- ax[3].set_title("Significant Differences")
- ax[3].set_xlabel("Nodes")
- plt.tight_layout()
- plt.savefig(filename, bbox_inches='tight', dpi=300)
- plt.savefig(filename.replace('.svg', '.png'), bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- labels = 4*["anterior"]+8*['posterior']+4*["anterior"]+8*['posterior']
- # %%
- # Create combined adjacency matrix plot
- plot_combined_adjacency_matrices(
- adj_matrix_group1, adj_matrix_group2, diff_matrix, sig_matrix,
- "../results/Combined_Adjacency_Matrices_with_Significance_12.png",
- "Healthy Group (Median)", "anti-Yo PCD Group (Median)",
- )
- # %%
- from graspologic.plot import heatmap
- def plot_combined_adjacency_matrices(
- adj_group1, adj_group2, diff_matrix, sig_matrix, filename, groupname_1, groupname_2, labels
- ):
- """
- Plot adjacency matrices for two groups, their difference, and the significant clusters in a single layout using graspologic's heatmap.
- """
- fig, axes = plt.subplots(1, 4, figsize=(30, 10))
- font_scale = 1.5
- hier_label_fontsize = 20
- # Group 1
- heatmap(
- adj_group1,
- ax=axes[0],
- inner_hier_labels=labels,
- sort_nodes=True,
- cbar=False,
- title=groupname_1,
- font_scale=font_scale,
- hier_label_fontsize=hier_label_fontsize
- )
- axes[0].set_xlabel("Nodes")
- axes[0].set_ylabel("Nodes")
- # Group 2
- heatmap(
- adj_group2,
- ax=axes[1],
- inner_hier_labels=labels,
- sort_nodes=True,
- cbar=False,
- title=groupname_2,
- font_scale=font_scale,
- hier_label_fontsize=hier_label_fontsize
- )
- axes[1].set_xlabel("Nodes")
- # Difference Matrix
- heatmap(
- diff_matrix,
- ax=axes[2],
- inner_hier_labels=labels,
- sort_nodes=True,
- cbar=False,
- title="Difference Matrix",
- font_scale=font_scale,
- hier_label_fontsize=hier_label_fontsize
- )
- axes[2].set_xlabel("Nodes")
- # Significant Differences
- heatmap(
- sig_matrix,
- ax=axes[3],
- inner_hier_labels=labels,
- sort_nodes=True,
- cbar=False,
- title="Significant Differences",
- font_scale=font_scale,
- hier_label_fontsize=hier_label_fontsize
- )
- axes[3].set_xlabel("Nodes")
- plt.tight_layout()
- plt.savefig(filename, bbox_inches='tight', dpi=300)
- plt.savefig(filename.replace('.svg', '.png'), bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- # Create combined adjacency matrix plot
- plot_combined_adjacency_matrices(
- adj_matrix_group1, adj_matrix_group2, diff_matrix, sig_matrix,
- "../results/Combined_Adjacency_Matrices_with_Significance_12.svg",
- "Control", "PCD",
- labels=labels
- )
- # %%
- # Create combined adjacency matrix plot
- plot_combined_adjacency_matrices(
- adj_matrix_group1, adj_matrix_group3, diff_matrix_13, sig_matrix_13,
- "../results/Combined_Adjacency_Matrices_with_Significance_13.svg", "Control", "SCA",
- labels
- )
- # %%
- # Create combined adjacency matrix plot
- plot_combined_adjacency_matrices(
- adj_matrix_group3, adj_matrix_group2, diff_matrix_23, sig_matrix_23, "../results/Combined_Adjacency_Matrices_with_Significance_23.svg",
- "SCA", "PCD",
- labels
- )
- # %% [markdown]
- # ### Network
- # %% [markdown]
- # ### Network analysis
- # %%
- import networkx as nx
- import matplotlib.patches as mpatches
- # Color mapping for labels
- color_dict = {
- 'posterior': '#aff8df',
- 'anterior': '#ffcbc1'
- }
- # Define the mapping for node labels
- lobule_mapping = {
- 0: 'Lobule I-II',
- 1: 'Lobule III',
- 2: 'Lobule IV',
- 3: 'Lobule V',
- 4: 'Lobule VI',
- 5: 'Lobule Crus I',
- 6: 'Lobule Crus II',
- 7: 'Lobule VIIB',
- 8: 'Lobule VIIIA',
- 9: 'Lobule VIIIB',
- 10: 'Lobule IX',
- 11: 'Lobule X',
- 12: 'Lobule I-II (R)',
- 13: 'Lobule III (R)',
- 14: 'Lobule IV (R)',
- 15: 'Lobule V (R)',
- 16: 'Lobule VI (R)',
- 17: 'Lobule Crus I (R)',
- 18: 'Lobule Crus II (R)',
- 19: 'Lobule VIIB (R)',
- 20: 'Lobule VIIIA (R)',
- 21: 'Lobule VIIIB (R)',
- 22: 'Lobule IX (R)',
- 23: 'Lobule X (R)'
- }
- collabels = 4*["anterior"]+8*['posterior']+4*["anterior"]+8*['posterior']
- # %%
- coords_2d = coords[:,[0,2]]
- def create_graph(adj_matrix, lobule_mapping, collabels):
- A = adj_matrix.copy()
- np.fill_diagonal(A, 0)
- g = nx.from_numpy_array(A)
- for i in range(len(g.nodes)):
- g.nodes[i]['lobule'] = lobule_mapping[i]
- g.nodes[i]['lobulenr'] = list(lobule_mapping.keys())[i]
- g.nodes[i]['color'] = collabels[i]
- return g
- # List of adjacency matrices
- threshold = 0.5
- adj_matrix_group1 = np.where(np.abs(corr_matrix_group1) > threshold, corr_matrix_group1, 0)
- adj_matrix_group2 = np.where(np.abs(corr_matrix_group2) > threshold, corr_matrix_group2, 0)
- adj_matrix_group3 = np.where(np.abs(corr_matrix_group3) > threshold, corr_matrix_group3, 0)
- adj_matrices = [adj_matrix_group1, adj_matrix_group2, adj_matrix_group3]
- titles = ["Control", "PCD", "SCA"]
- # Create the plot
- fig, axes = plt.subplots(1, 3, figsize=(15, 5))
- for idx, (adj_matrix, ax) in enumerate(zip(adj_matrices, axes)):
- g = create_graph(adj_matrix, lobule_mapping, collabels)
- # Get node colors directly from the graph
- node_colors = [color_dict[g.nodes[n]['color']] for n in g.nodes()]
- nx.draw_networkx(
- g,
- pos=coords_2d,
- labels=nx.get_node_attributes(g, 'lobulenr'),
- node_size=200,
- node_color=node_colors,
- with_labels=True,
- font_weight='bold',
- font_size=6,
- width=0.6,
- ax=ax
- )
- ax.set_title(titles[idx])
- ax.axis('off')
- # Create the main legend for posterior and anterior
- legend_tiles = [
- mpatches.Patch(color="#aff8df", label="posterior"),
- mpatches.Patch(color="#ffcbc1", label="anterior"),
- ]
- # Add the main legend to the first subplot
- axes[0].legend(handles=legend_tiles, loc="lower right")
- # Create the lobule legend
- lobule_legend_labels = [f"{key}: {value}" for key, value in lobule_mapping.items()]
- lobule_legend_patches = [mpatches.Patch(color='white', label=label) for label in lobule_legend_labels]
- # Add the lobule legend outside the plot
- fig.legend(handles=lobule_legend_patches, loc="upper left", bbox_to_anchor=(1, 0.95), fontsize=9)
- # Adjust layout to fit legends
- plt.tight_layout()
- plt.savefig('../results/network_graph.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/network_graph.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- g1 = create_graph(adj_matrix_group1, lobule_mapping, collabels)
- g2 = create_graph(adj_matrix_group2, lobule_mapping, collabels)
- g3 = create_graph(adj_matrix_group3, lobule_mapping, collabels)
- # %%
- def calculate_graph_metrics(g):
- metrics = {}
- # Number of nodes and edges
- metrics['num_nodes'] = g.number_of_nodes()
- metrics['num_edges'] = g.number_of_edges()
- # Check if the graph is connected
- metrics['is_connected'] = nx.is_connected(g)
- metrics['num_components'] = nx.number_connected_components(g)
- # Global clustering coefficient
- metrics['global_clustering_coefficient'] = nx.average_clustering(g)
- # Global efficiency
- metrics['global_efficiency'] = nx.global_efficiency(g)
- # Small-worldness (if connected)
- if metrics['is_connected']:
- C = nx.average_clustering(g)
- L = nx.average_shortest_path_length(g)
- n = g.number_of_nodes()
- k = 2 * g.number_of_edges() / n
- C_rand = k / n
- L_rand = np.log(n) / np.log(k)
- metrics['small_worldness'] = (C / C_rand) / (L / L_rand)
- else:
- metrics['small_worldness'] = "Not applicable (disconnected graph)"
- # Node-level metrics
- metrics['node_strength'] = dict(g.degree(weight='weight'))
- metrics['betweenness_centrality'] = nx.betweenness_centrality(g)
- metrics['clustering_coefficient'] = nx.clustering(g)
- # Average shortest path length (for each component)
- component_path_lengths = []
- for component in nx.connected_components(g):
- subgraph = g.subgraph(component)
- if len(subgraph) > 1:
- component_path_lengths.append(nx.average_shortest_path_length(subgraph))
- metrics['avg_shortest_path_length'] = component_path_lengths
- # Participation coefficient (if the graph has communities)
- try:
- communities = list(nx.community.greedy_modularity_communities(g))
- metrics['participation_coefficient'] = nx.algorithms.participation_coefficient(g, communities)
- except:
- metrics['participation_coefficient'] = "Not calculated (requires community structure)"
- return metrics
- # Example usage
- # Assuming g is your NetworkX graph
- # g = nx.Graph() # Replace this with your actual graph
- # Calculate metrics
- metrics = calculate_graph_metrics(g)
- # Print results
- for metric, value in metrics.items():
- print(f"{metric}: {value}")
- # %%
- # Calculate metrics
- metrics1 = calculate_graph_metrics(g1)
- metrics2 = calculate_graph_metrics(g2)
- metrics3 = calculate_graph_metrics(g3)
- # %%
- def create_boxplot(data1, data2, data3, title, ax, name):
- df = pd.DataFrame({
- 'Control': data1,
- 'PCD': data2,
- 'SCA': data3
- })
- df_melted = df.melt(var_name='Group', value_name=name)
- custom_palette = {'PCD': 'cornflowerblue', 'Control': 'turquoise', 'SCA': 'orange'}
- sns.boxplot(
- x='Group', y=name, data=df_melted, palette=custom_palette, ax=ax,
- width=0.5, fliersize=0, linewidth=1.0, saturation=0.45,
- )
- sns.stripplot(
- x='Group', y=name, data=df_melted, palette=custom_palette, ax=ax,
- size=4.5, jitter=0.12, edgecolor='black', linewidth=0.4, alpha=0.9,
- )
- _, p12 = stats.ttest_ind(data1, data2, equal_var=False)
- _, p13 = stats.ttest_ind(data1, data3, equal_var=False)
- _, p23 = stats.ttest_ind(data2, data3, equal_var=False)
- y_max = df_melted[name].max()
- add_significance_bar(0, 1, y_max*1.05, p12, ax)
- add_significance_bar(1, 2, y_max*1.15, p23, ax)
- add_significance_bar(0, 2, y_max*1.25, p13, ax)
- ax.set_title(title, fontsize=14)
- ax.set_xlabel(None)
- ax.set_ylabel(None)
- ax.set_ylim(0, y_max*1.4)
- def format_pvalue(p_value):
- if p_value < 0.001:
- return "p < 0.001"
- elif p_value < 0.01:
- return f"p = {p_value:.3f}"
- else:
- return f"p = {p_value:.2f}"
- def add_significance_bar(start, end, height, p_value, ax):
- x1, x2 = start, end
- y, h = height, height * 0.05
- ax.plot([x1, x1, x2, x2], [y, y+h, y+h, y], lw=1.5, c='black')
- ax.text((x1+x2)*.5, y+h, format_pvalue(p_value), ha='center', va='bottom', fontsize=10)
- # Function to filter nodes based on color
- def filter_nodes(g, metrics, color, metric):
- return [metrics[metric][n] for n in g.nodes() if g.nodes[n]['color'] == color]
- # %%
- import seaborn as sns
- metric_to_plot = 'node_strength'
- # Create the main figure
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 4))
- plt.subplots_adjust(wspace=0.08)
- # All nodes
- create_boxplot(
- list(metrics1[metric_to_plot].values()),
- list(metrics2[metric_to_plot].values()),
- list(metrics3[metric_to_plot].values()),
- 'All Nodes', ax1, 'Node Strength'
- )
- # Anterior nodes
- create_boxplot(
- filter_nodes(g1, metrics1, 'anterior', metric_to_plot),
- filter_nodes(g2, metrics2, 'anterior', metric_to_plot),
- filter_nodes(g3, metrics3, 'anterior', metric_to_plot),
- 'Anterior Nodes', ax2, 'Node Strength'
- )
- # Posterior nodes
- create_boxplot(
- filter_nodes(g1, metrics1, 'posterior', metric_to_plot),
- filter_nodes(g2, metrics2, 'posterior', metric_to_plot),
- filter_nodes(g3, metrics3, 'posterior', metric_to_plot),
- 'Posterior Nodes', ax3, 'Node Strength'
- )
- # Share a single y-axis across all subplots, displayed on the far right only
- global_ymax = max(ax.get_ylim()[1] for ax in (ax1, ax2, ax3))
- for ax in (ax1, ax2, ax3):
- ax.set_ylim(0, global_ymax)
- ax.spines['top'].set_visible(False)
- for ax in (ax1, ax2):
- ax.spines['left'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
- ax.tick_params(axis='x', which='both', bottom=False, labelbottom=False)
- ax3.spines['left'].set_visible(False)
- ax3.spines['right'].set_visible(True)
- ax3.yaxis.tick_right()
- ax3.yaxis.set_label_position('right')
- ax3.set_ylabel('Node Strength', fontsize=14, labelpad=8)
- plt.tight_layout()
- plt.savefig('../results/node_strength.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/node_strength.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- metric_to_plot = 'betweenness_centrality'
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 4))
- plt.subplots_adjust(wspace=0.08)
- def normalize(x):
- return (x - np.min(x)) / (np.max(x) - np.min(x))
- create_boxplot(
- np.log1p(list(metrics1[metric_to_plot].values())),
- np.log1p(list(metrics2[metric_to_plot].values())),
- np.log1p(list(metrics3[metric_to_plot].values())),
- 'All Nodes', ax1, 'Log Betweenness Centrality'
- )
- create_boxplot(
- np.log1p(filter_nodes(g1, metrics1, 'anterior', metric_to_plot)),
- np.log1p(filter_nodes(g2, metrics2, 'anterior', metric_to_plot)),
- np.log1p(filter_nodes(g3, metrics3, 'anterior', metric_to_plot)),
- 'Anterior Nodes', ax2, 'Log Betweenness Centrality'
- )
- create_boxplot(
- np.log1p(filter_nodes(g1, metrics1, 'posterior', metric_to_plot)),
- np.log1p(filter_nodes(g2, metrics2, 'posterior', metric_to_plot)),
- np.log1p(filter_nodes(g3, metrics3, 'posterior', metric_to_plot)),
- 'Posterior Nodes', ax3, 'Log Betweenness Centrality'
- )
- # Share a single y-axis across all subplots, displayed on the far right only
- global_ymax = max(ax.get_ylim()[1] for ax in (ax1, ax2, ax3))
- for ax in (ax1, ax2, ax3):
- ax.set_ylim(0, global_ymax)
- ax.spines['top'].set_visible(False)
- for ax in (ax1, ax2):
- ax.spines['left'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
- ax.tick_params(axis='x', which='both', bottom=False, labelbottom=False)
- ax3.spines['left'].set_visible(False)
- ax3.spines['right'].set_visible(True)
- ax3.yaxis.tick_right()
- ax3.yaxis.set_label_position('right')
- ax3.set_ylabel('Log Betweenness Centrality', fontsize=14, labelpad=8)
- plt.tight_layout()
- plt.savefig('../results/betweenness_centrality.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/betweenness_centrality.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- metric_to_plot = 'clustering_coefficient'
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 4))
- plt.subplots_adjust(wspace=0.08)
- create_boxplot(
- list(metrics1[metric_to_plot].values()),
- list(metrics2[metric_to_plot].values()),
- list(metrics3[metric_to_plot].values()),
- 'All Nodes', ax1, 'Clustering Coefficient'
- )
- create_boxplot(
- filter_nodes(g1, metrics1, 'anterior', metric_to_plot),
- filter_nodes(g2, metrics2, 'anterior', metric_to_plot),
- filter_nodes(g3, metrics3, 'anterior', metric_to_plot),
- 'Anterior Nodes', ax2, 'Clustering Coefficient'
- )
- create_boxplot(
- filter_nodes(g1, metrics1, 'posterior', metric_to_plot),
- filter_nodes(g2, metrics2, 'posterior', metric_to_plot),
- filter_nodes(g3, metrics3, 'posterior', metric_to_plot),
- 'Posterior Nodes', ax3, 'Clustering Coefficient'
- )
- # Share a single y-axis across all subplots, displayed on the far right only
- global_ymax = max(ax.get_ylim()[1] for ax in (ax1, ax2, ax3))
- for ax in (ax1, ax2, ax3):
- ax.set_ylim(0, global_ymax)
- ax.spines['top'].set_visible(False)
- for ax in (ax1, ax2):
- ax.spines['left'].set_visible(False)
- ax.spines['right'].set_visible(False)
- ax.tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
- ax.tick_params(axis='x', which='both', bottom=False, labelbottom=False)
- ax3.spines['left'].set_visible(False)
- ax3.spines['right'].set_visible(True)
- ax3.yaxis.tick_right()
- ax3.yaxis.set_label_position('right')
- ax3.set_ylabel('Clustering Coefficient', fontsize=14, labelpad=8)
- plt.tight_layout()
- plt.savefig('../results/clustering_coefficient.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/clustering_coefficient.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- def create_barplot(data1, data2, data3, title, ax, name):
- df = pd.DataFrame({
- 'Control': [data1],
- 'PCD': [data2],
- 'SCA': [data3]
- })
- df_melted = df.melt(var_name='Group', value_name=name)
- custom_palette = {'PCD': 'cornflowerblue', 'Control': 'turquoise', 'SCA': 'orange'}
- sns.barplot(
- x='Group', y=name, data=df_melted, palette=custom_palette, ax=ax,
- width=0.5, saturation=0.6,
- )
- ax.set_title(title, fontsize=14)
- ax.set_xlabel(None)
- ax.set_ylabel(None)
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 4))
- plt.subplots_adjust(wspace=0.35)
- metric_to_plot = 'num_edges'
- create_barplot(
- metrics1[metric_to_plot],
- metrics2[metric_to_plot],
- metrics3[metric_to_plot],
- 'Number of edges', ax1, 'Number of edges'
- )
- metric_to_plot = 'global_clustering_coefficient'
- create_barplot(
- metrics1[metric_to_plot],
- metrics2[metric_to_plot],
- metrics3[metric_to_plot],
- 'Global clustering coefficient', ax2, 'Global clustering coefficient'
- )
- metric_to_plot = 'global_efficiency'
- create_barplot(
- metrics1[metric_to_plot],
- metrics2[metric_to_plot],
- metrics3[metric_to_plot],
- 'Global efficiency', ax3, 'Global efficiency'
- )
- # Show x-axis group labels only on the rightmost subplot; keep all y-axes (different scales)
- for ax in (ax1, ax2):
- ax.tick_params(axis='x', which='both', bottom=False, labelbottom=False)
- plt.tight_layout()
- plt.savefig('../results/edges_clustering_coefficient_global_efficiency.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/edges_clustering_coefficient_global_efficiency.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %% [markdown]
- # ### Other
- # %%
- # ──────────────────────────────────────────────────────────────
- # SENSITIVITY ANALYSIS: effect of correlation threshold on
- # key network metrics (Reviewer Major Point 3)
- # ──────────────────────────────────────────────────────────────
- sensitivity_thresholds = [0.3, 0.4, 0.5, 0.6, 0.7]
- sensitivity_rows = []
- for thr in sensitivity_thresholds:
- adj_g1 = np.where(np.abs(corr_matrix_group1) > thr, corr_matrix_group1, 0)
- adj_g2 = np.where(np.abs(corr_matrix_group2) > thr, corr_matrix_group2, 0)
- adj_g3 = np.where(np.abs(corr_matrix_group3) > thr, corr_matrix_group3, 0)
- np.fill_diagonal(adj_g1, 0)
- np.fill_diagonal(adj_g2, 0)
- np.fill_diagonal(adj_g3, 0)
- _g1 = nx.from_numpy_array(adj_g1)
- _g2 = nx.from_numpy_array(adj_g2)
- _g3 = nx.from_numpy_array(adj_g3)
- for label, _g in [('Control', _g1), ('PCD', _g2), ('SCA1', _g3)]:
- n = _g.number_of_nodes()
- sensitivity_rows.append({
- 'Threshold': thr,
- 'Group': label,
- 'Edge Count': _g.number_of_edges(),
- 'Density': nx.density(_g),
- 'Global Clustering': nx.average_clustering(_g),
- 'Global Efficiency': nx.global_efficiency(_g),
- 'Avg Node Strength': sum(dict(_g.degree(weight='weight')).values()) / n,
- 'Avg Betweenness Centrality': float(np.mean(list(nx.betweenness_centrality(_g).values()))),
- })
- sensitivity_df = pd.DataFrame(sensitivity_rows)
- print("=== Sensitivity Analysis: Network Metrics Across Thresholds ===\n")
- for thr in sensitivity_thresholds:
- sub = sensitivity_df[sensitivity_df['Threshold'] == thr]
- print(f"\n--- Threshold |r| > {thr} ---")
- print(sub.to_string(index=False))
- print()
- sensitivity_df.to_csv('../results/sensitivity_threshold_analysis.csv', index=False)
- print("\nSaved to ../results/sensitivity_threshold_analysis.csv")
- # %%
- # ──────────────────────────────────────────────────────────────
- # PROPORTIONAL THRESHOLDING (Reviewer Major Point 3 supplement)
- # Keep the top X% strongest edges, compare with absolute thresholds.
- # ──────────────────────────────────────────────────────────────
- density_targets = [0.10, 0.20, 0.30, 0.40, 0.50]
- prop_rows = []
- for group_label, corr_mat in [('Control', corr_matrix_group1),
- ('PCD', corr_matrix_group2),
- ('SCA1', corr_matrix_group3)]:
- n = corr_mat.shape[0]
- upper = np.abs(corr_mat[np.triu_indices(n, k=1)])
- for target_density in density_targets:
- n_edges_target = int(target_density * len(upper))
- if n_edges_target == 0:
- continue
- sorted_vals = np.sort(upper)[::-1]
- cutoff = sorted_vals[min(n_edges_target - 1, len(sorted_vals) - 1)]
- adj = np.where(np.abs(corr_mat) >= cutoff, corr_mat, 0)
- np.fill_diagonal(adj, 0)
- g = nx.from_numpy_array(adj)
- prop_rows.append({
- 'Group': group_label,
- 'Target Density': target_density,
- 'Actual Density': nx.density(g),
- 'Edge Count': g.number_of_edges(),
- 'Global Clustering': nx.average_clustering(g),
- 'Global Efficiency': nx.global_efficiency(g),
- 'Avg Node Strength': sum(dict(g.degree(weight='weight')).values()) / n,
- })
- prop_df = pd.DataFrame(prop_rows)
- print("=== Proportional Thresholding: Network Metrics ===\n")
- for grp in ['Control', 'PCD', 'SCA1']:
- sub = prop_df[prop_df['Group'] == grp]
- print(f"\n--- {grp} ---")
- print(sub.to_string(index=False))
- prop_df.to_csv('../results/proportional_threshold_analysis.csv', index=False)
- print("\nSaved to ../results/proportional_threshold_analysis.csv")
- # %%
- # threshold sensitivity
- import seaborn as sns
- sens = pd.read_csv('../results/sensitivity_threshold_analysis.csv')
- custom_palette = {'PCD': 'cornflowerblue',
- 'Control': 'turquoise',
- 'SCA1': 'orange'}
- non_metric_cols = {'Threshold', 'Group'}
- metrics = [(col, col) for col in sens.columns if col not in non_metric_cols]
- n_metrics = len(metrics)
- ncols = 6
- nrows = int(np.ceil(n_metrics / ncols))
- fig, axes = plt.subplots(nrows, ncols, figsize=(2.8 * ncols, 3.0 * nrows), sharex=True)
- axes_flat = axes.ravel() if nrows > 1 else axes
- for ax, (col, label) in zip(axes_flat, metrics):
- for group, color in custom_palette.items():
- sub = sens[sens['Group'] == group].sort_values('Threshold')
- ax.plot(sub['Threshold'], sub[col], marker='o', markersize=5,
- linewidth=1.6, color=color, label=group)
- ax.axvline(0.5, color='gray', linestyle='--', lw=1, alpha=0.7)
- ax.set_ylabel(label)
- ax.grid(True, axis='y', alpha=0.25)
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- for ax in axes_flat[n_metrics:]:
- ax.set_visible(False)
- axes_flat[0].set_xlabel('|r| threshold')
- axes_flat[0].legend(loc='best', fontsize=9, frameon=False)
- plt.tight_layout()
- plt.savefig('../results/sensitivity_threshold.svg', bbox_inches='tight', dpi=300)
- plt.savefig('../results/sensitivity_threshold.png', bbox_inches='tight', dpi=600)
- plt.show()
- # %%
- def compute_network_metrics(g):
- node_count = len(g.nodes)
- edge_count = len(g.edges)
- avg_degree = sum(dict(g.degree()).values()) / node_count
- density = nx.density(g)
- clustering_coefficient = nx.average_clustering(g)
- if nx.is_connected(g):
- avg_path_length = nx.average_shortest_path_length(g)
- else:
- avg_path_length = float('inf') # If the graph is not connected
- assortativity = nx.degree_assortativity_coefficient(g)
- if nx.is_connected(g):
- diameter = nx.diameter(g)
- else:
- diameter = float('inf') # If the graph is not connected
- avg_node_strength = sum(dict(g.degree(weight='weight')).values()) / node_count
- return {
- 'Edge Count': edge_count,
- 'Average Degree': avg_degree,
- 'Density': density,
- 'Clustering Coefficient': clustering_coefficient,
- 'Average Path Length': avg_path_length,
- 'Assortativity': assortativity,
- 'Diameter': diameter,
- 'Average Node Strength': avg_node_strength
- }
- control_metrics = compute_network_metrics(g1)
- anti_yo_pcd_metrics = compute_network_metrics(g2)
- sca_metrics = compute_network_metrics(g3)
- # %%
- metrics_dict = {
- 'Control': control_metrics,
- 'Anti-yo PCD': anti_yo_pcd_metrics,
- 'SCA': sca_metrics
- }
- df = pd.DataFrame.from_dict(metrics_dict, orient='index')
- # Convert the DataFrame to LaTeX format
- latex_output = df.to_latex(index=True, float_format="%.2f")
- # Display or save the LaTeX output
- print(latex_output)
- with open("../results/network_results.tex", "w") as f:
- f.write(latex_output)
network_analysis.ipynb at commit 6b7297b, no license · at the source
Overview
- ICM, INSERM U 1127, CNRS UMR 7225, UMRS 1127, Paris Brain Institute, Sorbonne University, Paris, France
- Neurological Department, Groupe Hospitalier Paris Saint-Joseph, Paris, France
- Université Paris Cité, Paris, France
- Charles Foix, DMU Neurosciences, Service de Neuro-Oncologie-Institut de Neurologie, AP-HP, Hôpitaux Universitaires La Pitié Salpêtrière, Paris, France
- Department of Neuroradiology, APHP, La Pitié-Salpêtrière Hospital, Sorbonne University, F-75013 Paris, France
- APHP-Salpêtrière Hospital, DMU BioGem, CNRS, INSERM, Paris Brain Institute, Sorbonne University, Paris, France
Abstract
Background: Anti-Yo paraneoplastic cerebellar degeneration (PCD) is a rare autoimmune disorder linked to ovarian and breast cancers. Neurological symptoms often precede cancer diagnosis, yet conventional imaging techniques may fail to detect early cerebellar changes. This study quantitatively assessed cerebellar atrophy and network alterations in anti-Yo PCD patients compared to healthy controls and patients with spinocerebellar ataxia type 1 (SCA1).
Methods: We analyzed structural MRI data from 11 antiYo PCD patients, 17 healthy controls, and 17 SCA1 patients. Cerebellar lobular segmentation and cortical thickness measurements were conducted. Structural covariance networks were built using inter-lobular Pearson correlation coefficients (threshold |
Results: AntiYo PCD patients showed pronounced anterior cortical thinning, while SCA1 atrophy was milder and more posterior. Two PCD subtypes emerged: one with severe atrophy, another with nearnormal thickness. Network analysis revealed increased node strength and clustering coefficients, but reduced betweenness centrality in PCD, suggesting altered network hierarchy and widespread clustering that may reflect pathological reorganization. In cross-validated analysis, regional cerebellar features distinguished PCD, SCA1, and controls with promising AUC values.
Conclusions: Anti-Yo PCD is characterized by anterior cerebellar vulnerability and network reorganization distinct from SCA1. These morphometric and connectivity markers are candidate imaging biomarkers for early diagnosis and subgroup stratification in paraneoplastic cerebellar degeneration.
Supplementary Information: The online version contains supplementary material available at 10.1007/
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 12 matches between paragraphs and lines of code.
tamelenak/pcd-spatial-analysis
6b7297ba30111482bd35ca183a4707d7f10175d4, 6 May 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
6 files
- notebooks/
3d_thickness_analysis.ip , Jupyter, 721 lines, 1 matchynb - notebooks/
group_classification.ipy , Jupyter, 515 lines, 3 matchesnb - notebooks/
group_differences.ipynb , Jupyter, 492 lines, 2 matches - notebooks/
network_analysis.ipynb , Jupyter, 1,059 lines, 6 matches - notebooks/
statistical_analysis.ipy , Jupyter, 760 linesnb - repository limit reached (2,000 files or 30 MB): the rest is at the source (1 files)
- README.md, Text, 34 lines
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;
- 5 scripts, each with its path and the digest of its content;
- 12 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
Datasets cited
- zenodo:16094263, at Zenodo; found in “Data availability”
Data availability
The dataset is available under 10.5281/
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 2, 28 September 2026
- Publisher: n/a → Springer Science+Business Media
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 10 authors, 4 keywords, 14 MeSH terms, 2 funders, 27 references.
Cite
This paper
Künzle, T., Rincon de la Rosa, L., Vialatte de Pémille, C., Leprince-Laurenge, A., Picca, A., Coarelli, G., Leclercq, D., Dürr, A., Psimaras, D., & Alentorn, A. (2026). Spatial analysis of paraneoplastic cerebellar degeneration in ovarian cancer with anti-Yo syndrome and SCA1. Journal of neurology, 273(8), 493. https://
BibTeX
@article{kunzle2026spati
author = {Künzle, Tamara and Rincon de la Rosa, Lucas and Vialatte de Pémille, Clément and Leprince-Laurenge, Alice and Picca, Alberto and Coarelli, Giulia and Leclercq, Delphine and Dürr, Alexandra and Psimaras, Dimitri and Alentorn, Agusti},
title = {{Spatial analysis of paraneoplastic cerebellar degeneration in ovarian cancer with anti-Yo syndrome and SCA1}},
journal = {Journal of neurology},
year = {2026},
month = jul,
volume = {273},
number = {8},
pages = {493},
publisher = {Springer Science+Business Media},
issn = {0340-5354},
doi = {10.1007/
url = {https://
pmid = {42509533},
pmcid = {PMC13407450}
}
RIS
TY - JOUR
AU - Künzle, Tamara
AU - Rincon de la Rosa, Lucas
AU - Vialatte de Pémille, Clément
AU - Leprince-Laurenge, Alice
AU - Picca, Alberto
AU - Coarelli, Giulia
AU - Leclercq, Delphine
AU - Dürr, Alexandra
AU - Psimaras, Dimitri
AU - Alentorn, Agusti
TI - Spatial analysis of paraneoplastic cerebellar degeneration in ovarian cancer with anti-Yo syndrome and SCA1
T2 - Journal of neurology
J2 - J Neurol
PY - 2026
DA - 2026/
VL - 273
IS - 8
SP - 493
SN - 0340-5354
PB - Springer Science+Business Media
DO - 10.1007/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1007/
"type": "article-journal",
"title": "Spatial analysis of paraneoplastic cerebellar degeneration in ovarian cancer with anti-Yo syndrome and SCA1",
"container-title": "Journal of neurology",
"author": [
{
"family": "Künzle",
"given": "Tamara"
},
{
"family": "Rincon de la Rosa",
"given": "Lucas"
},
{
"family": "Vialatte de Pémille",
"given": "Clément"
},
{
"family": "Leprince-Laurenge",
"given": "Alice"
},
{
"family": "Picca",
"given": "Alberto"
},
{
"family": "Coarelli",
"given": "Giulia"
},
{
"family": "Leclercq",
"given": "Delphine"
},
{
"family": "Dürr",
"given": "Alexandra"
},
{
"family": "Psimaras",
"given": "Dimitri"
},
{
"family": "Alentorn",
"given": "Agusti"
}
],
"container-title-short":
"volume": "273",
"issue": "8",
"page": "493",
"DOI": "10.1007/
"PMID": "42509533",
"PMCID": "PMC13407450",
"ISSN": "0340-5354",
"publisher": "Springer Science+Business Media",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
27
]
]
}
}
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-73996-z [code]
- Genetic architecture of white matter microstructure captured by unsupervised deep representation learning of fractional anisotropy maps.Journal: Nature communicationsIn common: Nilearn, Plotly, NiBabel, 7 other tools, structural MRI / diffusion, 1 reference
- [2] doi:10.1073/pnas.2531706123 [code]
- Metabolism-weighted brain connectome reveals synaptic integration and vulnerability to neurodegeneration.Journal: Proceedings of the National Academy of Sciences of the United States of AmericaIn common: Nilearn, NetworkX, Plotly, 8 other tools, other condition
- [3] doi:10.1038/s41467-026-71428-6 [code]
- Binding items to contexts through conjunctive neural representations with the method of loci.Journal: Nature communicationsIn common: Nilearn, Plotly, NiBabel, 7 other tools, 1 reference
- [4] doi:10.1162/imag.a.1276 [code]
- High-resolution whole-brain magnetic resonance spectroscopic imaging in youth at risk for psychosis.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Nilearn, NetworkX, Plotly, 7 other tools, clinical / translational
- [5] doi:10.1162/imag.a.1164 [code]
- Bias and generalizability of brain age prediction models: A multi-cohort evaluation with anatomical and interpretability insights.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Nilearn, Plotly, NiBabel, 7 other tools, structural MRI / diffusion
- [6] doi:10.1002/hbm.70469 [code]
- VarCoNet: A Variability-Aware Self-Supervised Framework for Functional Connectome Extraction From Resting-State fMRI.Journal: Human brain mappingIn common: Nilearn, NetworkX, Plotly, 7 other tools
- [7] doi:10.1038/s41398-026-04157-5 [code]
- Association of glymphatic function with 40-Hz neural oscillations, systemic metabolic markers, and cognitive performance in healthy aging adults: An EEG and MRI study.Journal: Translational psychiatryIn common: Nilearn, NetworkX, NiBabel, 6 other tools, structural MRI / diffusion, clinical / translational
- [8] doi:10.1212/wnl.0000000000218472 [code]
- Lesion-Level Subtypes of White Matter Hyperintensity Evolution Beyond Spatial Location.Journal: NeurologyIn common: Nilearn, Plotly, NiBabel, 6 other tools, structural MRI / diffusion, clinical / translational
- [9] doi:10.1038/s41467-026-72931-6 [code]
- Three parsimonious spatiotemporal patterns in cerebellum reveal individual traits in function and behavior.Journal: Nature communicationsIn common: Nilearn, NiBabel, statsmodels, 6 other tools, 1 reference
- [10] doi:10.1038/s41467-026-75959-w [code]
- Charting higher-order models of brain function beyond pairwise interactions.Journal: Nature communicationsIn common: Nilearn, NetworkX, NiBabel, 7 other tools
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, 5 scripts, and 12 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:0201e067fdde836f…
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.
