Charting higher-order models of brain function beyond pairwise interactions.
The 23 matches
- [1] § Methods › Data sources and preprocessing › Brain maps from neuromaps ↔ Paper/Figure3/Fig3_clean.ipynb, lines 114–141 · score 0.97 · HT1a, HT1b, HT2a, VAChT, mGluR5, CB1
- [2] § Results › Higher-order taxonomy ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 812–865 · score 0.69 · classical FC, TScaffold, structural connectivity, PED Syn, PED Red, PhiID
- [3] § Results › Higher-order taxonomy ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 556–651 · score 0.65 · complete linkage, TScaffold, PED Syn, PED Red, PhiID, Pscaff
- [4] § Methods › Data sources and preprocessing › Brain parcellation ↔ 01_example_surface_plots.ipynb, lines 99–104 · score 0.61 · dorsal attention, ventral attention, limbic, somatomotor, frontoparietal, parcellation
- [5] § Methods › Higher-order frameworks › Integrated information decomposition (Phi ID): PhiID Red and PhiID Syn ↔ hoi/metrics/phiid_red.py, lines 27–59 · score 0.60 · Minimum Mutual Information, redundancy atom, MMI, PhiID
- [6] § Methods › Higher-order frameworks › Integrated information decomposition (Phi ID): PhiID Red and PhiID Syn ↔ hoi/metrics/phiid_atoms.py, lines 105–142 · score 0.60 · Minimum Mutual Information, redundancy atom, MMI, PhiID
- [7] § Methods › Clustering ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 531–553 · score 0.59 · Spearman correlation, hierarchical clustering, complete linkage, dendrogram, nodal, distance
- [8] § Methods › Data sources and preprocessing › Brain parcellation ↔ Paper/Figure3/Fig3_clean.ipynb, lines 175–216 · score 0.58 · subcortical regions, DA, VIS, SM, atlas, VA
- [9] § Results › Multimodal characterization of topological and informational gradients ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 699–743 · score 0.58 · TScaffold, scaffold frequency, PED Syn, PED Red, PhiID, profiles
- [10] § Results › FC decomposition and brain-behavior analysis ↔ Paper/Figure5-6/Fig5_FC_reconstruction.ipynb, lines 245–280 · score 0.57 · Euclidean distance, Task flexibility, centroid, positions, space, synergistic
- [11] § Results › Multimodal characterization of topological and informational gradients ↔ Paper/Figure3/Fig3_clean.ipynb, lines 684–734 · score 0.56 · HOI axis, axis correlates, Box, whiskers, Scatter, transporters
- [12] § Methods › Higher-order frameworks › Integrated information decomposition (Phi ID): PhiID Red and PhiID Syn ↔ hoi/metrics/phiid_red.py, lines 27–59 · score 0.55 · redundancy atom, mutual information, variables, PhiID
- [13] § Methods › Higher-order frameworks › Integrated information decomposition (Phi ID): PhiID Red and PhiID Syn ↔ hoi/metrics/phiid_atoms.py, lines 105–142 · score 0.55 · redundancy atom, mutual information, variables, PhiID
- [14] § Results › Brain fingerprinting and task decoding ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 345–418 · score 0.54 · Yeo resting state, resting state network, Box, DA, VIS, SM
- [15] § Results › Brain fingerprinting and task decoding ↔ Paper/Figure4/Fig4_tasks.ipynb, lines 40–86 · score 0.54 · Task decoding, PhiID, DA, VIS, SM, VA
- [16] § Methods › Higher-order frameworks › Triangles and temporal scaffold ↔ High_order_TS_with_scaffold/persistent_homology_calculation.py, lines 117–156 · score 0.53 · persistent homology, edge weight, cycles, filtration, dimensional, scaffold
- [17] § Methods › Higher-order frameworks › Triangles and temporal scaffold ↔ High_order_TS_with_scaffold/simplicial_multivariate.py, lines 36–95 · score 0.53 · simplicial complex, edge weight, violation, violating, filtration, triangles
- [18] § Results ↔ Paper/Figure2/Fig2_analyses_clean.ipynb, lines 1–73 · score 0.53 · structural functional cartography, Partial Entropy Decomposition, TScaffold, homological scaffolds, fMRI, PhiID
- [19] § Methods › Higher-order frameworks › Partial entropy decomposition (PED): PED Red and PED Syn ↔ Code/04_PED/ped_module.py, lines 36–64 · score 0.52 · Partial Entropy Decomposition, joint entropy, discrete, PED, Syn
- [20] § Methods › Higher-order frameworks › Triangles and temporal scaffold ↔ High_order_TS/simplicial_multivariate.py, lines 33–86 · score 0.52 · simplicial complex, edge weight, violation, violating, filtration, triangles
- [21] § Methods › Data sources and preprocessing › Brain maps from neuromaps ↔ utils_neuromaps_brain.py, lines 53–202 · score 0.51 · cortical surface, brain maps, neuromaps, Schaefer, parcellated
- [22] § Results › FC decomposition and brain-behavior analysis ↔ Paper/Figure5-6/Fig5_FC_reconstruction.ipynb, lines 325–372 · score 0.51 · dopamine transporter, task flexibility, DAT, correlated, FC
- [23] § Methods › Higher-order frameworks › Triangles and temporal scaffold ↔ High_order_TS_with_scaffold/simplicial_multivariate.py, lines 36–95 · score 0.51 · persistent homology, edge weight, filtration, dimensional, scaffold, triangle
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 · 932 lines · 38 KB · no license · 6 matches
- # %% [markdown]
- # # Figure 2 — Higher-order information dynamics in resting-state fMRI
- #
- # This notebook reproduces Figure 2, which characterises eleven higher-order
- # functional connectivity (HOI) measures computed on HCP resting-state fMRI data
- # (Schaefer 100-region cortical parcellation + 16 subcortical regions, N = 100 subjects).
- #
- # **Measures compared**
- #
- # | Label | Method |
- # |---|---|
- # | O-Red / O-Syn | O-information redundancy / synergy |
- # | PED Red / PED Syn | Partial Entropy Decomposition |
- # | PhiID Red / PhiID Syn | Integrated Information Decomposition |
- # | Triangles | Local TDA triangle count |
- # | TScaffold | Topological scaffold (local TDA) |
- # | Fscaff / Pscaff | Homological scaffold – frequency / persistence |
- # | FC | Classical pairwise functional connectivity |
- #
- # **Figure panels produced**
- #
- # - **(a)** Edge-level connectivity matrices with overlaid brain maps
- # - **(b)** Edge-level pairwise Spearman similarity matrix
- # - **(c)** Hierarchical clustering dendrogram
- # - **(d)** Structure–function cartography scatter plot
- #
- # > Set the paths in **Section 1 – Configuration** before running.
- # %% [markdown]
- # ## 1. Imports
- # %%
- %load_ext autoreload
- %autoreload 2
- import numpy as np
- import h5py
- import sys
- import glob
- import os
- import re
- import scipy.io as sio
- import pandas as pd
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- import matplotlib.colors as mcolors
- import seaborn as sns
- from collections import OrderedDict
- from scipy.spatial.distance import squareform
- from scipy.stats import spearmanr, rankdata
- from scipy.cluster.hierarchy import dendrogram, linkage
- from scipy.cluster.hierarchy import leaves_list as hc_leaves_list
- from matplotlib.gridspec import GridSpec
- sys.path.append("../utils/")
- from utils import (
- extract_red_syn_from_Oinfo_optimized,
- triangle_projection,
- edge_projection,
- upper_tri_masking,
- )
- from utils_neuromaps_brain import normal_view_top
- # Typography — Helvetica preferred (Arial fallback), sans-serif math, embedded PDF fonts
- mpl.rcParams.update({
- "font.family": "sans-serif",
- "font.sans-serif": ["Helvetica", "Arial", "DejaVu Sans"],
- "mathtext.fontset": "stixsans", # sans-serif math glyphs
- "axes.linewidth": 1.5,
- "pdf.fonttype": 42, # embed as TrueType in PDF (required by journals)
- "ps.fonttype": 42,
- })
- # %% [markdown]
- # ## 2. Configuration — set paths here
- # %%
- # ── Paths to pre-computed HOI results ────────────────────────────────────────
- BASE_PATH = "../../../"
- DATA_PATH = f"{BASE_PATH}Results/08_HCP_Diano_preprocessing/REST_subc/"
- FC_PATH = f"{BASE_PATH}Dataset/08_HCP_Diano_preprocessing/REST_reordered_SC/"
- # Structural connectivity CSV files (copied to data/SC/ — see README)
- SC_PATH = "./data/SC/"
- # Output folder for figures
- FIG_PATH = "./Figures/"
- os.makedirs(FIG_PATH, exist_ok=True)
- # ── Atlas parameters ──────────────────────────────────────────────────────────
- N_ROIS = 116 # 100 cortical (Schaefer) + 16 subcortical
- N_SUBC = 16 # subcortical ROIs appended after cortical ones
- # ── Colour-map used for all edge matrices / brain maps ────────────────────────
- _n, _c = 50, 0.1
- _arr = (1 - _c) * plt.get_cmap("BuPu")(np.linspace(0, 1, _n)) + _c * np.ones((_n, 4))
- CMAP_STANDARD = mcolors.ListedColormap(_arr)
- # ── Measure display names (order determines panels b, c ordering) ─────────────
- MEASURES = [
- ("classical_FC_proj", "FC"),
- ("triangles_proj", "Triangles"),
- ("Red", "O-Red"),
- ("PED_Red_proj", "PED Red"),
- ("phiIDRed_proj", "PhiID Red"),
- ("scaffold_freq_proj","Fscaff"),
- ("scaffold_pers_proj","Pscaff"),
- ("scaffold_proj", "TScaffold"),
- ("Syn", "O-Syn"),
- ("PED_Syn_proj", "PED Syn"),
- ("phiIDSyn_proj", "PhiID Syn"),
- ]
- LABELS = [lbl for _, lbl in MEASURES]
- # ── Plotting style (markers, colours) for structure-function scatter ──────────
- MARKER_STYLE = {
- "O-Red": ("o", "#E41A1C", 120),
- "O-Syn": ("s", "#377EB8", 100),
- "Triangles":("^", "#4DAF4A", 140),
- "TScaffold":("D", "#984EA3", 100),
- "Fscaff": ("v", "#FF7F00", 140),
- "Pscaff": ("<", "#FFFF33", 140),
- "PED Red": (">", "#A65628", 140),
- "PED Syn": ("p", "#F781BF", 150),
- "PhiID Syn":("h", "#999999", 150),
- "PhiID Red":("8", "#66C2A5", 150),
- "FC": ("*", "#FC8D62", 160),
- }
- # %% [markdown]
- # ## 3. Data loading
- # %%
- def load_and_project_data(proj="nodal",
- data_path=DATA_PATH,
- fc_path=FC_PATH,
- n_rois=N_ROIS,
- n_subc=N_SUBC):
- """Load and project all HOI measures for one projection type.
- Parameters
- ----------
- proj : 'nodal' | 'edges'
- 'nodal' → each measure is a vector of length n_rois (node strength).
- 'edges' → each measure is a condensed upper-triangle vector of length
- C(n_rois, 2), suitable for squareform().
- data_path : str
- Directory with sub-folders 01_Red_Syn/, 02_local_TDA/, etc.
- fc_path : str
- Directory of per-subject time-series CSV files.
- n_rois, n_subc : int
- Total ROIs and number of subcortical ROIs appended at the end.
- Returns
- -------
- dict keys → measure name, values → ndarray (n_subjects, feature_size)
- """
- n_cortical = n_rois - n_subc
- # Pre-compute triplet → edge index mapping (needed for edge projection)
- from itertools import combinations as _comb
- all_comb = np.array(list(_comb(np.arange(n_rois), 3)))
- if proj == "edges":
- indices = np.array([
- np.intersect1d(np.where(all_comb == i)[0],
- np.where(all_comb == j)[0])
- for i, j in _comb(np.arange(n_rois), 2)
- ])
- else:
- indices = None # triangle_projection computes its own nodal indices
- print(f"Loading data (proj='{proj}') …")
- # ── 1. O-information: Redundancy and Synergy ─────────────────────────────
- Oinfo = {}
- with h5py.File(f"{data_path}01_Red_Syn/Oinfo.hdf5", "r") as f:
- for key in f:
- Oinfo[key] = np.ravel(f[key][:])
- Red_d, Syn_d = extract_red_syn_from_Oinfo_optimized(
- Oinfo, nROIs=n_rois, proj=proj, normalized=False, indices=indices
- )
- Red = np.array(list(Red_d.values()))
- Syn = np.array(list(Syn_d.values()))
- print(" ✓ O-information (Red / Syn)")
- # ── 2. Local TDA (scaffold and triangles) ────────────────────────────────
- def _load_npz_dict(pattern, key):
- result = OrderedDict()
- for path in sorted(glob.glob(pattern)):
- fname = os.path.basename(path).split(".")[0]
- day = (re.search(r"REST(\d+)", fname) or type("", (), {"group": lambda s, _: ""})()).group(1)
- lr = (re.search(r"(LR|RL)", fname) or type("", (), {"group": lambda s, _: ""})()).group(1)
- subj = (re.search(r"(\d{6})", fname) or type("", (), {"group": lambda s, _: ""})()).group(1)
- sid = f"{subj}_{lr}_{day}"
- result[sid] = np.load(path)[key]
- return result
- scaffold_d = _load_npz_dict(f"{data_path}02_local_TDA/*scaffold*", "scaffold")
- triangles_d = _load_npz_dict(f"{data_path}02_local_TDA/*triangles*", "triangles")
- scaffold_proj = np.array([edge_projection(scaffold_d[s], proj=proj, nROIs=n_rois) for s in scaffold_d])
- triangles_proj = np.array([triangle_projection(triangles_d[s], proj=proj, nROIs=n_rois, indices=indices) for s in triangles_d])
- print(" ✓ Local TDA (scaffold / triangles)")
- # ── 3. Homological scaffolds (frequency and persistence) ─────────────────
- def _load_npy_dir(folder):
- result = OrderedDict()
- for fname in sorted(os.listdir(folder)):
- if not fname.startswith("."):
- result[fname] = np.load(folder + fname)
- return result
- freq_d = _load_npy_dir(f"{data_path}03_scaffold/freq/")
- pers_d = _load_npy_dir(f"{data_path}03_scaffold/pers/")
- scaffold_freq_proj = np.array([edge_projection(freq_d[s], proj=proj, nROIs=n_rois) for s in freq_d])
- scaffold_pers_proj = np.array([edge_projection(pers_d[s], proj=proj, nROIs=n_rois) for s in pers_d])
- print(" ✓ Homological scaffolds (freq / pers)")
- # ── 4. PED ───────────────────────────────────────────────────────────────
- PED_Red_d, PED_Syn_d = {}, {}
- with h5py.File(f"{data_path}04_PED/Red.hdf5", "r") as f:
- for key in f:
- PED_Red_d[key] = f[key][:]
- with h5py.File(f"{data_path}04_PED/Syn.hdf5", "r") as f:
- for key in f:
- PED_Syn_d[key] = f[key][:]
- PED_Red_proj = np.array([triangle_projection(PED_Red_d[s], proj=proj, nROIs=n_rois, indices=indices) for s in PED_Red_d])
- PED_Syn_proj = np.array([triangle_projection(PED_Syn_d[s], proj=proj, nROIs=n_rois, indices=indices) for s in PED_Syn_d])
- print(" ✓ PED (Red / Syn)")
- # ── 5. PhiID ─────────────────────────────────────────────────────────────
- phiID_Red_d, phiID_Syn_d = {}, {}
- with h5py.File(f"{data_path}05_phiID/Red.hdf5", "r") as f:
- for key in f:
- phiID_Red_d[key] = f[key][:]
- with h5py.File(f"{data_path}05_phiID/Syn.hdf5", "r") as f:
- for key in f:
- phiID_Syn_d[key] = f[key][:]
- # PhiID is stored as a list of (value, …) tuples — extract first element
- if proj == "edges":
- def _phiID_to_edge(d):
- mat = squareform(np.array([row[0] for row in d]))[:n_rois, :n_rois]
- return edge_projection(mat, proj=proj, nROIs=n_rois)
- phiIDRed_proj = np.array([_phiID_to_edge(phiID_Red_d[s]) for s in phiID_Red_d])
- phiIDSyn_proj = np.array([_phiID_to_edge(phiID_Syn_d[s]) for s in phiID_Syn_d])
- else:
- phiIDRed_proj = np.array([np.mean(squareform(np.array([row[0] for row in phiID_Red_d[s]])), axis=0)
- for s in phiID_Red_d])
- phiIDSyn_proj = np.array([np.mean(squareform(np.array([row[0] for row in phiID_Syn_d[s]])), axis=0)
- for s in phiID_Syn_d])
- print(" ✓ PhiID (Red / Syn)")
- # ── 6. Classical FC (from time series) ───────────────────────────────────
- FC_d = OrderedDict()
- for fname in sorted(os.listdir(fc_path)):
- token = fname.split(".")[0]
- day = (re.search(r"REST(\d+)", token) or type("", (), {"group": lambda s, _: ""})()).group(1)
- lr = (re.search(r"(LR|RL)", token) or type("", (), {"group": lambda s, _: ""})()).group(1)
- sid = (re.search(r"(\d{6})", token) or type("", (), {"group": lambda s, _: ""})()).group(1)
- sid = f"{sid}_{lr}_{day}"
- FC_d[sid] = np.corrcoef(np.loadtxt(fc_path + fname))
- classical_FC_proj = np.array([edge_projection(FC_d[s], proj=proj, nROIs=n_rois) for s in FC_d])
- print(" ✓ Classical FC")
- print(f" Done — {len(Red)} scans loaded.")
- return {
- "Red": Red,
- "Syn": Syn,
- "triangles_proj": triangles_proj,
- "scaffold_proj": scaffold_proj,
- "scaffold_freq_proj":scaffold_freq_proj,
- "scaffold_pers_proj":scaffold_pers_proj,
- "PED_Red_proj": PED_Red_proj,
- "PED_Syn_proj": PED_Syn_proj,
- "phiIDRed_proj": phiIDRed_proj,
- "phiIDSyn_proj": phiIDSyn_proj,
- "classical_FC_proj": classical_FC_proj,
- }
- # %%
- # Nodal projection (used for brain maps and Yeo distributions)
- data_nodal = load_and_project_data(proj="nodal")
- Red_nodal = data_nodal["Red"]
- Syn_nodal = data_nodal["Syn"]
- triangles_nodal = data_nodal["triangles_proj"]
- scaffold_nodal = data_nodal["scaffold_proj"]
- scaffold_freq_nodal= data_nodal["scaffold_freq_proj"]
- scaffold_pers_nodal= data_nodal["scaffold_pers_proj"]
- PED_Red_nodal = data_nodal["PED_Red_proj"]
- PED_Syn_nodal = data_nodal["PED_Syn_proj"]
- phiIDRed_nodal = data_nodal["phiIDRed_proj"]
- phiIDSyn_nodal = data_nodal["phiIDSyn_proj"]
- classical_FC_nodal = data_nodal["classical_FC_proj"]
- # %%
- # Edge projection (used for similarity analysis and structure-function plots)
- data_edges = load_and_project_data(proj="edges")
- Red_edges = data_edges["Red"]
- Syn_edges = data_edges["Syn"]
- triangles_edges = data_edges["triangles_proj"]
- scaffold_edges = data_edges["scaffold_proj"]
- scaffold_freq_edges = data_edges["scaffold_freq_proj"]
- scaffold_pers_edges = data_edges["scaffold_pers_proj"]
- PED_Red_edges = data_edges["PED_Red_proj"]
- PED_Syn_edges = data_edges["PED_Syn_proj"]
- phiIDRed_edges = data_edges["phiIDRed_proj"]
- phiIDSyn_edges = data_edges["phiIDSyn_proj"]
- classical_FC_edges = data_edges["classical_FC_proj"]
- # %%
- # Load structural connectivity matrices (100 subjects, 116×116 parcellation).
- # The CSV files are in parcellation order: first 16 rows/cols = subcortical,
- # rows 16–116 = Schaefer cortical parcels. We reorder so that cortical comes
- # first (rows 0–99) and subcortical last (rows 100–115) to match the HOI data.
- list_SC_edges = {}
- for sc_path in sorted(glob.glob(SC_PATH + "SC_100_*nof*csv")):
- subj_id = sc_path.split("/")[-1].split("_")[3]
- raw = np.loadtxt(sc_path, delimiter=",")
- SC = np.zeros((N_ROIS, N_ROIS))
- SC[:100, :100] = raw[16:116, 16:116] # cortical–cortical
- SC[100:, 100:] = raw[:16, :16] # subcortical–subcortical
- SC[100:, :100] = raw[:16, 16:] # subcortical–cortical
- SC += SC.T # symmetrise
- list_SC_edges[subj_id] = upper_tri_masking(SC)
- SC_arr = np.array(list(list_SC_edges.values()))
- avg_SC = np.mean(SC_arr, axis=0)
- print(f"SC loaded — {SC_arr.shape[0]} subjects, {SC_arr.shape[1]} edges each")
- # %% [markdown]
- # ## 4. Panel (a) — Brain maps and Yeo network distributions
- #
- # Each HOI measure is projected to node strength, ranked across regions, and
- # visualised on an inflated cortical surface. Distributions across the seven
- # Yeo resting-state networks (+ subcortical) are also shown.
- # %%
- # ── Yeo parcellation ─────────────────────────────────────────────────────────
- def load_yeo(filename="../utils/yeo_RS7_Schaefer100S.mat", n_rois=N_ROIS):
- """Return yeoOrder, yeoROIs array, and per-network ROI index dict."""
- mat = sio.loadmat(filename)
- yeo_order = np.array([i - 1 for i in mat["yeoOrder"]])[:n_rois]
- yeo_rois = np.array([i[0] - 1 for i in mat["yeoROIs"]])[:n_rois]
- yeo_names = ["VIS", "SM", "DA", "VA", "L", "FP", "DMN", "SC"]
- yeo_dict = {name: np.where(yeo_rois == k)[0]
- for k, name in enumerate(yeo_names)}
- # Subcortical: merge Yeo label 7 with any label 8 entries
- yeo_dict["SC"] = np.concatenate([yeo_dict["SC"], np.where(yeo_rois == 8)[0]])
- return yeo_order, yeo_rois, yeo_dict
- yeo_order, yeo_rois, yeo_dict = load_yeo()
- # Force subcortical to the 16 appended regions
- yeo_dict["SC"] = np.arange(100, N_ROIS)
- # ── Helper functions ──────────────────────────────────────────────────────────
- def compute_ranks(v):
- """Return floor ranks of absolute values."""
- return np.floor(rankdata(np.abs(v), method="average"))
- def aggregate_yeo_ranks(data, yeo_dict):
- """Per-subject rank each nodal vector, then average within each network."""
- result = {net: [] for net in yeo_dict}
- for subj in data:
- r = compute_ranks(subj)
- for net in yeo_dict:
- result[net].append(np.mean(r[yeo_dict[net]]))
- return result
- SIZE_LARGE, SIZE_SMALL = 26, 19
- def plot_brain_map(data, filename, force_white=False, graymap_rev=True, n_rois=100):
- """Plot mean ranked node strength on a cortical surface."""
- mean_ranks = np.mean([compute_ranks(v) for v in data], axis=0)[:n_rois]
- vmin = np.nanpercentile(mean_ranks, 10)
- vmax = np.nanpercentile(mean_ranks, 90)
- fig = normal_view_top(
- mean_ranks, edges=True, brightness=0.85,
- parcellation=100, center_cbar=True, graymap_rev=graymap_rev,
- cmap=CMAP_STANDARD, alpha_graymap=1, parcellation_name="schaefer",
- exp_form=False, vmin=vmin, vmax=vmax, force_white=force_white,
- surftype="inflated",
- )
- fig.axes[1].set_xlabel(r"$\langle s_i \rangle$" + "\n\npercentile",
- labelpad=-70, fontsize=SIZE_LARGE)
- fig.axes[1].set_xticks([vmin, vmax])
- fig.axes[1].set_xticklabels(["10", "90"], fontsize=SIZE_LARGE)
- fig.savefig(f"{FIG_PATH}{filename}.png", dpi=300, bbox_inches="tight", transparent=True)
- plt.close(fig)
- def plot_yeo_distribution(data, filename):
- """Strip + box plot of ranked node strength per Yeo network."""
- df = pd.DataFrame(aggregate_yeo_ranks(data, yeo_dict))
- fig, ax = plt.subplots(1, 1, figsize=(6, 2.5), dpi=150)
- sns.stripplot(data=df, alpha=1, edgecolor="w", linewidth=1, zorder=-10,
- ax=ax, palette="muted", size=5.5)
- sns.boxplot(data=df, fill=False, width=0.5, ax=ax, showfliers=False)
- ax.spines[["top", "right"]].set_visible(False)
- ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha="center", fontsize=SIZE_SMALL)
- ax.set_yticks(np.arange(0, 122, 40))
- ax.set_yticklabels(np.arange(0, 122, 40), fontsize=SIZE_SMALL)
- plt.tight_layout()
- plt.savefig(f"{FIG_PATH}{filename}_yeo.png", dpi=300, bbox_inches="tight", transparent=True)
- plt.close(fig)
- # %%
- # Generate brain maps and Yeo distributions for all measures.
- # Brain maps use inflated surface; Synergy is plotted with absolute values
- # because it is negative-valued (synergy-dominated triplets have O-info < 0).
- brain_map_specs = [
- # (data, filename, force_white, graymap_rev)
- (Red_nodal, "Redundancy", False, True),
- (np.abs(Syn_nodal), "Synergy", True, False),
- (triangles_nodal, "Triangles", True, False),
- (scaffold_nodal, "HO_Scaffold", False, True),
- (scaffold_freq_nodal, "Scaffold_freq", True, True),
- (scaffold_pers_nodal, "Scaffold_pers", True, True),
- (PED_Red_nodal, "PED_Red", True, False),
- (PED_Syn_nodal, "PED_Syn", True, False),
- (phiIDRed_nodal, "PhiID_Red", True, False),
- (phiIDSyn_nodal, "PhiID_Syn", True, True),
- (classical_FC_nodal, "Classical_FC", True, True),
- ]
- for data, fname, fw, gr in brain_map_specs:
- plot_brain_map(data, fname, force_white=fw, graymap_rev=gr)
- plot_yeo_distribution(data, fname)
- print(f" ✓ {fname}")
- print("All brain maps saved.")
- # %% [markdown]
- # ## 5. Panel (a) — Edge-level connectivity matrices
- #
- # Lower-triangular visualisation of the mean edge-level connectivity matrix for
- # each HOI measure. Rows and columns correspond to brain regions.
- # %%
- # --- Note: Matplotlib rcParams for font may not always have effect, especially for non-PDF outputs or if font is not found ---
- def plot_edge_matrix(edge_data, save_path):
- """Plot the group-average edge matrix as a lower-triangular image."""
- mean_vec = np.mean(edge_data, axis=0)
- sq = squareform(mean_vec)
- # Mask upper triangle (including diagonal)
- mask = np.triu(np.ones_like(sq, dtype=bool))
- sq[mask] = np.nan
- vmin = np.percentile(mean_vec, 10)
- vmax = np.percentile(mean_vec, 90)
- # NOTE: Explicitly set font in this plot function for axes
- fig, ax = plt.subplots(figsize=(8, 8))
- ax.imshow(sq, vmin=vmin, vmax=vmax, cmap=CMAP_STANDARD)
- n = sq.shape[0]
- ax.plot([-0.25, n - 0.75], [-0.25, n - 0.75], "k-", linewidth=2)
- # Thin white grid lines clipped precisely at the diagonal (data coordinates)
- for i in range(1, n):
- ax.plot([-0.5, i - 0.5], [i - 0.5, i - 0.5], "w-", lw=0.25) # horizontal → diagonal
- ax.plot([i - 0.5, i - 0.5], [i - 0.5, n - 0.5], "w-", lw=0.25) # vertical ↓ bottom
- ax.spines[["top", "right"]].set_visible(False)
- ax.spines[["bottom", "left"]].set_linewidth(2)
- ax.set_xticks([])
- ax.set_yticks([])
- # Try to force Helvetica/Arial via set_fontname on tick labels (if rcParams isn't working)
- for label in ax.get_xticklabels() + ax.get_yticklabels():
- label.set_fontname('Helvetica') # will fallback if not available
- plt.tight_layout()
- plt.savefig(save_path, dpi=300, transparent=True, bbox_inches="tight")
- plt.close(fig)
- # Generate all edge matrices
- edge_matrix_specs = [
- (Red_edges, "Red_edges"),
- (Syn_edges, "Syn_edges"),
- (triangles_edges, "Triangles_edges"),
- (scaffold_edges, "Scaffold_edges"),
- (scaffold_freq_edges, "Scaffold_freq_edges"),
- (scaffold_pers_edges, "Scaffold_pers_edges"),
- (PED_Red_edges, "PED_Red_edges"),
- (PED_Syn_edges, "PED_Syn_edges"),
- (phiIDRed_edges, "PhiID_Red_edges"),
- (phiIDSyn_edges, "PhiID_Syn_edges"),
- (classical_FC_edges, "Classical_FC_edges"),
- ]
- for data, fname in edge_matrix_specs:
- plot_edge_matrix(data, f"{FIG_PATH}{fname}.png")
- print(f" ✓ {fname}")
- # Standalone colourbar
- fig, ax = plt.subplots(figsize=(6, 0.3))
- fig.subplots_adjust(bottom=0.5)
- norm = mcolors.Normalize(vmin=0, vmax=1)
- cbar = plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=CMAP_STANDARD),
- cax=ax, orientation="horizontal")
- cbar.ax.set_xticks([])
- cbar.ax.set_yticks([])
- # Explicitly set font for colorbar, too (in case global rcParams isn't working)
- for label in cbar.ax.get_xticklabels() + cbar.ax.get_yticklabels():
- label.set_fontname('Helvetica')
- plt.savefig(f"{FIG_PATH}colorbar.png", dpi=300, bbox_inches="tight", transparent=True)
- plt.close(fig)
- print("Edge matrices and colourbar saved.")
- # %% [markdown]
- # ## 6. Panels (b) & (c) — Edge-level similarity matrix and hierarchical clustering
- #
- # Panel (b): Spearman correlation between the group-average edge profiles of each
- # measure pair. Panel (c): Complete-linkage dendrogram of those distances.
- # %%
- # Compute mean edge vector per measure (absolute value for Syn to reflect magnitude)
- nodal_all = np.array([
- np.mean(np.abs(data_edges[key]), axis=0) if key == "Syn"
- else np.mean(data_edges[key], axis=0)
- for key, _ in MEASURES
- ])
- # Spearman correlation matrix (symmetric by construction)
- n_meas = len(MEASURES)
- corr_matrix = np.zeros((n_meas, n_meas))
- for i in range(n_meas):
- for j in range(n_meas):
- corr_matrix[i, j], _ = spearmanr(nodal_all[i], nodal_all[j])
- corr_matrix = (corr_matrix + corr_matrix.T) / 2 # enforce symmetry numerically
- print("Spearman correlation matrix computed.")
- # %%
- # ── Panel (b) + (c): lower-triangle correlation matrix + complete-linkage dendogram ──
- # Cluster-group colours for labels and branches
- SYNERGY_SET = {"O-Syn", "PED Syn", "PhiID Syn"}
- REDUNDANCY_SET= {"FC", "Triangles", "O-Red", "PED Red", "PhiID Red"}
- TOPOLOGY_SET = {"Fscaff", "Pscaff", "TScaffold"}
- def _group_color(label):
- if label in SYNERGY_SET: return "blue"
- if label in REDUNDANCY_SET: return "red"
- if label in TOPOLOGY_SET: return "purple"
- return "black"
- # Complete-linkage clustering
- dist_sq = np.sqrt(2 * np.clip(1 - corr_matrix, 0, None)) # correlation → distance
- Z_complete = linkage(squareform(dist_sq, checks=False), method="complete")
- def _leaf_group_color(node_idx, Z, n_leaves):
- """Color a dendrogram branch by the group of its descendant leaves."""
- def _leaves(idx):
- if idx < n_leaves:
- return {idx}
- l, r = int(Z[idx - n_leaves][0]), int(Z[idx - n_leaves][1])
- return _leaves(l) | _leaves(r)
- leaf_set = _leaves(node_idx)
- groups = {_group_color(LABELS[i]) for i in leaf_set}
- groups.discard("black")
- return groups.pop() if len(groups) == 1 else "gray"
- fig = plt.figure(dpi=150, figsize=(16, 7))
- gs = plt.GridSpec(1, 8)
- # ─ Left: lower-triangle Spearman matrix ─
- ax1 = fig.add_subplot(gs[0, :5])
- mask_upper = np.triu(np.ones_like(corr_matrix, dtype=bool), k=0)
- import seaborn as sns
- sns.heatmap(
- np.round(corr_matrix, 2),
- annot=True, fmt=".2f", cmap="RdYlBu_r",
- mask=mask_upper, ax=ax1, cbar=False,
- linewidths=0., square=True,
- annot_kws={
- "size": 13,
- "fontname": "Helvetica"
- }
- )
- ax1.set_yticks(np.arange(n_meas) + 0.5)
- ax1.set_yticklabels(LABELS, rotation=0, fontname='Helvetica')
- ax1.set_xticks(np.arange(n_meas - 1) + 0.5)
- ax1.set_xticklabels(LABELS[:-1], rotation=45, fontname='Helvetica')
- plt.setp(ax1.get_yticklabels(), rotation=45, ha="right", rotation_mode="anchor", fontsize=14, fontname="Helvetica")
- plt.setp(ax1.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor", fontsize=14, fontname="Helvetica")
- ax1.tick_params(length=7, width=1.5)
- bw = 1.5
- for i in range(1, n_meas):
- ax1.plot([i-1, i], [i, i], "k-", lw=bw, zorder=100, clip_on=False)
- ax1.plot([i, i], [i, i+1], "k-", lw=bw, zorder=100, clip_on=False)
- ax1.plot([0, 0], [1, n_meas], "k-", lw=bw+0.5, zorder=100, clip_on=False)
- ax1.plot([0, n_meas-1], [n_meas, n_meas], "k-", lw=bw+0.5, zorder=100, clip_on=False)
- for x in range(1, n_meas):
- ax1.axvline(x, ymin=0, ymax=1 - 0.1*x, color="white", lw=bw)
- ax1.axhline(x, xmin=0, xmax=0.09*x, color="white", lw=bw)
- ax1.set_ylim(n_meas, 1)
- # ─ Right: complete-linkage dendrogram ─
- ax2 = fig.add_subplot(gs[0, 5:])
- n_leaves = len(LABELS)
- dendro = dendrogram(
- Z_complete, labels=LABELS, orientation="top",
- color_threshold=0,
- link_color_func=lambda k: _leaf_group_color(k, Z_complete, n_leaves),
- ax=ax2, leaf_rotation=45,
- )
- ax2.spines[["top", "left", "right"]].set_visible(False)
- ax2.spines["bottom"].set_linewidth(1.5)
- ax2.set_yticks([])
- for tick in ax2.get_xticklabels():
- tick.set_color(_group_color(tick.get_text()))
- # Set font to Helvetica, fallback to Arial if not available
- try:
- tick.set_fontname("Helvetica")
- except Exception:
- tick.set_fontname("Arial")
- ax2.tick_params(length=10, width=1)
- plt.xticks(rotation=45, ha="right", fontsize=13, fontname="Helvetica")
- plt.subplots_adjust(wspace=0)
- plt.savefig(f"{FIG_PATH}Fig2_bc_similarity_dendrogram_complete.pdf",
- dpi=300, bbox_inches="tight", transparent=True)
- plt.savefig(f"{FIG_PATH}Fig2_bc_similarity_dendrogram_complete.svg")
- print("Panel (b)+(c) [complete linkage] saved.")
- # %%
- # ── Alternative: Ward-linkage clustering with ordered heatmap ─────────────────
- # This version reorders the correlation matrix rows/columns according to the
- # Ward dendrogram, making cluster structure visible directly in the heatmap.
- Z_ward = linkage(squareform(dist_sq, checks=False), method="ward", optimal_ordering=True)
- idx = hc_leaves_list(Z_ward)
- # Reorder matrix and labels by dendrogram leaf order
- corr_ordered = corr_matrix[np.ix_(idx[::-1], idx[::-1])]
- labels_ordered= [LABELS[i] for i in idx[::-1]]
- fig = plt.figure(figsize=(16, 7), dpi=150)
- gs = GridSpec(1, 20, figure=fig)
- ax_hm = fig.add_subplot(gs[0, :19])
- sns.heatmap(corr_ordered, annot=True, fmt=".2f", cmap="RdYlBu_r",
- ax=ax_hm, cbar=False, linewidths=0.5, square=True,
- annot_kws={"size": 12})
- ax_hm.set_xticks(np.arange(n_meas) + 0.5)
- ax_hm.set_yticks(np.arange(n_meas) + 0.5)
- ax_hm.set_xticklabels(labels_ordered, rotation=45, ha="right", fontsize=13)
- ax_hm.set_yticklabels(labels_ordered, rotation=0, fontsize=13)
- for tick in ax_hm.get_xticklabels():
- tick.set_color(_group_color(tick.get_text()))
- for tick in ax_hm.get_yticklabels():
- tick.set_color(_group_color(tick.get_text()))
- # Ward dendrogram on the right
- _ward_colors = (["darkred"]*11 + ["red"]*2 + ["purple"] + ["red"]*2 +
- ["blue"]*2 + ["purple"] + ["gray"]*5)
- ax_dg = fig.add_subplot(gs[0, 19:])
- dendrogram(Z_ward, orientation="right", labels=LABELS, leaf_font_size=13,
- ax=ax_dg, color_threshold=2.5,
- link_color_func=lambda k: _ward_colors[k])
- ax_dg.spines[["top", "right", "bottom"]].set_visible(False)
- ax_dg.set_yticks([])
- ax_dg.set_xticks([])
- plt.subplots_adjust(wspace=-0.8775)
- plt.savefig(f"{FIG_PATH}Fig2_bc_similarity_dendrogram_ward.pdf",
- dpi=300, bbox_inches="tight", transparent=True)
- print("Panel (b)+(c) [Ward linkage] saved.")
- # %% [markdown]
- # ## 7. Panel (d) — Structure–function cartography
- #
- # Each HOI measure is characterised by two Spearman correlations computed from
- # its group-average edge-level profile:
- # - **x-axis**: correlation with mean structural connectivity (SC)
- # - **y-axis**: correlation with mean functional connectivity (FC)
- # %%
- # Average edge-level profiles across subjects (used for scatter)
- ROIs_used = N_ROIS
- def _avg_edge(arr):
- """Mean over subjects of the upper-triangle restricted to ROIs_used × ROIs_used."""
- return np.mean([upper_tri_masking(squareform(arr[i])[:ROIs_used, :ROIs_used])
- for i in range(len(arr))], axis=0)
- avg_FC = _avg_edge(classical_FC_edges)
- avg_Red = _avg_edge(Red_edges)
- avg_Syn = _avg_edge(np.abs(Syn_edges)) # absolute value for magnitude
- avg_tri = _avg_edge(triangles_edges)
- avg_scaf = _avg_edge(scaffold_edges)
- avg_freq = _avg_edge(scaffold_freq_edges)
- avg_pers = _avg_edge(scaffold_pers_edges)
- avg_PEDR = _avg_edge(PED_Red_edges)
- avg_PEDS = _avg_edge(PED_Syn_edges)
- avg_phiS = _avg_edge(phiIDSyn_edges)
- avg_phiR = _avg_edge(phiIDRed_edges)
- SF = {
- "O-Red": (spearmanr(avg_SC, avg_Red).statistic, spearmanr(avg_FC, avg_Red).statistic),
- "O-Syn": (spearmanr(avg_SC, avg_Syn).statistic, spearmanr(avg_FC, avg_Syn).statistic),
- "Triangles":(spearmanr(avg_SC, avg_tri).statistic, spearmanr(avg_FC, avg_tri).statistic),
- "TScaffold":(spearmanr(avg_SC, avg_scaf).statistic, spearmanr(avg_FC, avg_scaf).statistic),
- "Fscaff": (spearmanr(avg_SC, avg_freq).statistic, spearmanr(avg_FC, avg_freq).statistic),
- "Pscaff": (spearmanr(avg_SC, avg_pers).statistic, spearmanr(avg_FC, avg_pers).statistic),
- "PED Red": (spearmanr(avg_SC, avg_PEDR).statistic, spearmanr(avg_FC, avg_PEDR).statistic),
- "PED Syn": (spearmanr(avg_SC, avg_PEDS).statistic, spearmanr(avg_FC, avg_PEDS).statistic),
- "PhiID Syn":(spearmanr(avg_SC, avg_phiS).statistic, spearmanr(avg_FC, avg_phiS).statistic),
- "PhiID Red":(spearmanr(avg_SC, avg_phiR).statistic, spearmanr(avg_FC, avg_phiR).statistic),
- "FC": (spearmanr(avg_SC, avg_FC).statistic, spearmanr(avg_FC, avg_FC).statistic),
- }
- for name, (r_SC, r_FC) in SF.items():
- print(f" {name:12s} SC: {r_SC:+.3f} FC: {r_FC:+.3f}")
- # %%
- fig, ax = plt.subplots(figsize=(6.75, 6), dpi=150)
- for spine in ax.spines.values():
- spine.set_linewidth(1.5)
- for method, (r_SC, r_FC) in SF.items():
- mk, col, sz = MARKER_STYLE[method]
- ax.scatter(
- r_SC, r_FC, label=method, marker=mk, s=sz, c=col,
- edgecolor="black", linewidth=1
- )
- ax.axvline(0, color="black", lw=1, ls=":", alpha=0.1)
- ax.axhline(0, color="black", lw=1, ls=":", alpha=0.1)
- ax.set_xlabel(
- "Structural connectivity", fontsize=20, labelpad=5,
- fontname="Helvetica"
- )
- ax.set_ylabel(
- "Functional connectivity", fontsize=20, labelpad=0,
- fontname="Helvetica"
- )
- ax.tick_params(width=1.5, length=6, labelsize=16)
- for label in (ax.get_xticklabels() + ax.get_yticklabels()):
- label.set_fontname("Helvetica")
- ax.set_xlim(-1.15, 1.15)
- ax.set_ylim(-1.15, 1.15)
- leg = ax.legend(
- loc="upper left", bbox_to_anchor=(-0.005, 1.005), ncol=2,
- columnspacing=1., handletextpad=0.0, labelspacing=1,
- fontsize=11.5, markerscale=1.1, frameon=True, fancybox=True, shadow=True
- )
- for text in leg.get_texts():
- text.set_fontname("Helvetica")
- plt.tight_layout()
- plt.savefig(
- f"{FIG_PATH}Fig2d_structure_function_edge.pdf",
- dpi=300, bbox_inches="tight", transparent=True
- )
- print("Panel (d) saved.")
- # %% [markdown]
- # ## 8. Supplementary — Nodal-level analyses
- #
- # Repeats the similarity matrix, dendrogram, and structure–function scatter at
- # the nodal (node-strength) projection level instead of edge level.
- # %%
- # Nodal SC: per-subject degree-strength (mean SC per node), then group average
- list_SC_nodal = {}
- for sc_path in sorted(glob.glob(SC_PATH + "santo_100_*nof*csv")):
- subj_id = sc_path.split("/")[-1].split("_")[3]
- raw = np.loadtxt(sc_path, delimiter=",")
- SC = np.zeros((N_ROIS, N_ROIS))
- SC[:100, :100] = raw[16:116, 16:116]
- SC[100:, 100:] = raw[:16, :16]
- SC[100:, :100] = raw[:16, 16:]
- SC += SC.T
- list_SC_nodal[subj_id] = np.mean(SC, axis=0)
- SC_nodal_arr = np.array(list(list_SC_nodal.values()))
- avg_SC_nodal = np.mean(SC_nodal_arr, axis=0)
- print(f"Nodal SC loaded — {SC_nodal_arr.shape[0]} subjects, {SC_nodal_arr.shape[1]} nodes each")
- # %%
- # Nodal structure-function correlations
- def _avg_nodal(arr):
- """Group-average nodal profile, restricted to ROIs_used."""
- return np.mean([np.mean(squareform(arr[i])[:ROIs_used, :ROIs_used], axis=0)
- for i in range(len(arr))], axis=0)
- avg_FC_n = _avg_nodal(classical_FC_edges)
- avg_Red_n = _avg_nodal(Red_edges)
- avg_Syn_n = _avg_nodal(np.abs(Syn_edges))
- avg_tri_n = _avg_nodal(triangles_edges)
- avg_scaf_n = _avg_nodal(scaffold_edges)
- avg_freq_n = _avg_nodal(scaffold_freq_edges)
- avg_pers_n = _avg_nodal(scaffold_pers_edges)
- avg_PEDR_n = _avg_nodal(PED_Red_edges)
- avg_PEDS_n = _avg_nodal(PED_Syn_edges)
- avg_phiS_n = _avg_nodal(phiIDSyn_edges)
- avg_phiR_n = _avg_nodal(phiIDRed_edges)
- SF_nodal = {
- "O-Red": (spearmanr(avg_SC_nodal, avg_Red_n).statistic, spearmanr(avg_FC_n, avg_Red_n).statistic),
- "O-Syn": (spearmanr(avg_SC_nodal, avg_Syn_n).statistic, spearmanr(avg_FC_n, avg_Syn_n).statistic),
- "Triangles":(spearmanr(avg_SC_nodal, avg_tri_n).statistic, spearmanr(avg_FC_n, avg_tri_n).statistic),
- "TScaffold":(spearmanr(avg_SC_nodal, avg_scaf_n).statistic, spearmanr(avg_FC_n, avg_scaf_n).statistic),
- "Fscaff": (spearmanr(avg_SC_nodal, avg_freq_n).statistic, spearmanr(avg_FC_n, avg_freq_n).statistic),
- "Pscaff": (spearmanr(avg_SC_nodal, avg_pers_n).statistic, spearmanr(avg_FC_n, avg_pers_n).statistic),
- "PED Red": (spearmanr(avg_SC_nodal, avg_PEDR_n).statistic, spearmanr(avg_FC_n, avg_PEDR_n).statistic),
- "PED Syn": (spearmanr(avg_SC_nodal, avg_PEDS_n).statistic, spearmanr(avg_FC_n, avg_PEDS_n).statistic),
- "PhiID Syn":(spearmanr(avg_SC_nodal, avg_phiS_n).statistic, spearmanr(avg_FC_n, avg_phiS_n).statistic),
- "PhiID Red":(spearmanr(avg_SC_nodal, avg_phiR_n).statistic, spearmanr(avg_FC_n, avg_phiR_n).statistic),
- "FC": (spearmanr(avg_SC_nodal, avg_FC_n).statistic, spearmanr(avg_FC_n, avg_FC_n).statistic),
- }
- fig, ax = plt.subplots(figsize=(6.75, 6), dpi=150)
- for spine in ax.spines.values():
- spine.set_linewidth(1.5)
- for method, (r_SC, r_FC) in SF_nodal.items():
- mk, col, sz = MARKER_STYLE[method]
- ax.scatter(r_SC, r_FC, label=method, marker=mk, s=sz,
- c=col, edgecolor="black", linewidth=1)
- ax.axvline(0, color="black", lw=1, ls=":", alpha=0.1)
- ax.axhline(0, color="black", lw=1, ls=":", alpha=0.1)
- ax.set_xlabel("Structural connectivity", fontsize=20, labelpad=10)
- ax.set_ylabel("Functional connectivity", fontsize=20, labelpad=5)
- ax.tick_params(width=1.5, length=6, labelsize=16)
- ax.set_xlim(-1.15, 1.15)
- ax.set_ylim(-1.15, 1.15)
- ax.legend(loc="upper left", bbox_to_anchor=(-0.005, 1.005), ncol=2,
- columnspacing=1., handletextpad=0.0, labelspacing=1,
- fontsize=12.5, markerscale=1.1, frameon=True, fancybox=True, shadow=True)
- plt.tight_layout()
- plt.savefig(f"{FIG_PATH}Fig2_structure_function_nodal.pdf",
- dpi=300, bbox_inches="tight", transparent=True)
- print("Nodal structure-function scatter saved.")
- # %%
- # Nodal similarity matrix + complete-linkage dendrogram
- nodal_nodal_all = np.array([
- np.mean(np.abs(data_nodal[key]), axis=0) if key == "Syn"
- else np.mean(data_nodal[key], axis=0)
- for key, _ in MEASURES
- ])
- corr_nodal = np.zeros((n_meas, n_meas))
- for i in range(n_meas):
- for j in range(n_meas):
- corr_nodal[i, j], _ = spearmanr(nodal_nodal_all[i], nodal_nodal_all[j])
- corr_nodal = (corr_nodal + corr_nodal.T) / 2
- dist_nodal = np.sqrt(2 * np.clip(1 - corr_nodal, 0, None))
- Z_nod_comp = linkage(squareform(dist_nodal, checks=False), method="complete")
- fig = plt.figure(dpi=150, figsize=(16, 7))
- gs = plt.GridSpec(1, 8)
- ax1 = fig.add_subplot(gs[0, :5])
- mask_upper = np.triu(np.ones_like(corr_nodal, dtype=bool), k=0)
- sns.heatmap(np.round(corr_nodal, 2),
- annot=True, fmt=".2f", cmap="RdYlBu_r", mask=mask_upper,
- ax=ax1, cbar=False, linewidths=0., square=True, annot_kws={"size": 12})
- ax1.set_yticks(np.arange(n_meas) + 0.5)
- ax1.set_yticklabels(LABELS, rotation=0)
- ax1.set_xticks(np.arange(n_meas - 1) + 0.5)
- ax1.set_xticklabels(LABELS[:-1], rotation=45)
- plt.setp(ax1.get_yticklabels(), rotation=45, ha="right", rotation_mode="anchor", fontsize=13)
- plt.setp(ax1.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor", fontsize=13)
- ax1.tick_params(length=7, width=1.5)
- for i in range(1, n_meas):
- ax1.plot([i-1, i], [i, i], "k-", lw=1.5, zorder=100, clip_on=False)
- ax1.plot([i, i], [i, i+1], "k-", lw=1.5, zorder=100, clip_on=False)
- ax1.plot([0, 0], [1, n_meas], "k-", lw=2, zorder=100, clip_on=False)
- ax1.plot([0, n_meas-1], [n_meas, n_meas], "k-", lw=2, zorder=100, clip_on=False)
- for x in range(1, n_meas):
- ax1.axvline(x, ymin=0, ymax=1-0.1*x, color="white", lw=1.5)
- ax1.axhline(x, xmin=0, xmax=0.09*x, color="white", lw=1.5)
- ax1.set_ylim(n_meas, 1)
- ax2 = fig.add_subplot(gs[0, 5:])
- dendro = dendrogram(
- Z_nod_comp, labels=LABELS, orientation="top",
- color_threshold=0,
- #link_color_func=lambda k: _leaf_group_color(k, Z_nod_comp, n_leaves),
- ax=ax2, leaf_rotation=45,
- )
- ax2.spines[["top", "left", "right"]].set_visible(False)
- ax2.spines["bottom"].set_linewidth(1.5)
- ax2.set_yticks([])
- for tick in ax2.get_xticklabels():
- tick.set_color(_group_color(tick.get_text()))
- ax2.tick_params(length=10, width=1)
- plt.xticks(rotation=45, ha="right", fontsize=13)
- plt.subplots_adjust(wspace=0)
- plt.savefig(f"{FIG_PATH}Fig2_nodal_similarity_dendrogram.pdf",
- dpi=300, bbox_inches="tight", transparent=True)
- print("Nodal similarity + dendrogram saved.")
- # %%
Fig2_analyses_clean.ipynb at commit ce1a32c, no license · at the source
Overview
- ISI Foundation,Torino, Italy
- Institut de Neurosciences de la Timone UMR 7289, Aix Marseille Université, CNRS,Marseille, France
- Nicolaus Copernicus University,Toruń, Poland
- Intesa Sanpaolo A.I. Research, Torino, Italy
- Department of Psychology and Neuroscience Institute of Turin, University of Torino,Torino, Italy
- Centre for Apprenticeships, Northeastern University London,London, UK
- NPLab, Network Science Institute, Northeastern University London,London, UK
- Department of Physics, Northeastern University,Boston, MA, USA
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repositories
Its files are read in the Code ↔ Paper reader above, with 23 matches between paragraphs and lines of code.
andresantoro/RHOSTS
f42f531c4434ddc5a7b1144ceadc7b246a31a3f8, 3 October 2024Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
21 files
- Example/
launch_High_order_TS.sh , Shell, 7 lines - Example/
launch_High_order_TS_wit , Shell, 11 linesh_edgesaving.sh - Example/
launch_High_order_TS_wit , Shell, 20 linesh_scaffold.sh - Example_notebook/
Example_usage.ipynb , Jupyter, 89 lines - High_order_TS/
simplicial_multivariate. , Python, 156 lines, 1 matchpy - High_order_TS/
utils.py , Python, 380 lines - High_order_TS_with_scaff
old/ , Python, 37 linesHoles.py - High_order_TS_with_scaff
old/ , Python, 156 lines, 1 matchpersistent_homology_calc ulation.py - High_order_TS_with_scaff
old/ , Python, 168 lines, 2 matchessimplicial_multivariate. py - High_order_TS_with_scaff
old/ , Python, 455 linesutils.py - Julia_MTS_optimized/
SimplicialTS/ , Julia, 522 linessrc/ SimplicialTS.jl - Julia_MTS_optimized/
SimplicialTS/ , Julia, 18 linessrc/ precompile_simplicial.jl - Julia_MTS_optimized/
compile_package.sh , Shell, 29 lines - Julia_MTS_optimized/
example_launch_julia_HOi , Shell, 15 linesndicators_only.sh - Julia_MTS_optimized/
example_launch_julia_cod , Shell, 16 linese_iterative.sh - Julia_MTS_optimized/
example_launch_julia_cod , Shell, 18 linese_parallel.sh - Julia_MTS_optimized/
simplicial_multivariate. , Julia, 114 linesjl - Kaneko_CLM/
generate_couple_maps.py , Python, 96 lines - Kaneko_CLM/
generate_couple_maps_on_ , Python, 132 linesnetworks.py - LICENSE, License, 674 lines
- README.md, Text, 63 lines
Zenodo 20260959
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
1 file
- README.md, Text, 227 lines
nplresearch/HOI_lenses_analysis
ce1a32ccba63dcc20c495b77be7352ad2993575d, 18 May 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
74 files
- Code/
01_synergy_redundancy/ , Python, 129 lines01_brain_analyses.py - Code/
02_local_higher_order_TD , Julia, 522 linesA/ SimplicialTS/ src/ SimplicialTS.jl - Code/
02_local_higher_order_TD , Julia, 18 linesA/ SimplicialTS/ src/ precompile_simplicial.jl - Code/
02_local_higher_order_TD , Python, 38 linesA/ average_data_across_time .py - Code/
02_local_higher_order_TD , Shell, 29 linesA/ compile_package.sh - Code/
02_local_higher_order_TD , Shell, 15 linesA/ example_launch_julia_HOi ndicators_only.sh - Code/
02_local_higher_order_TD , Shell, 16 linesA/ example_launch_julia_cod e_iterative.sh - Code/
02_local_higher_order_TD , Shell, 18 linesA/ example_launch_julia_cod e_parallel.sh - Code/
02_local_higher_order_TD , Shell, 13 linesA/ launch_julia_HOlocalinfo _all.sh - Code/
02_local_higher_order_TD , Shell, 42 linesA/ launch_julia_HOlocalinfo _script.sh - Code/
02_local_higher_order_TD , Shell, 24 linesA/ launch_julia_HOlocalinfo _singlefile.sh - Code/
02_local_higher_order_TD , Julia, 122 linesA/ simplicial_multivariate. jl - Code/
03_scaffold/ , Julia, 94 linescompute_scaffold.jl - Code/
04_PED/ , Python, 82 linesnumba_functions.py - Code/
04_PED/ , Python, 111 linesped_analysis.py - Code/
04_PED/ , Python, 182 linesped_gaussian.py - Code/
04_PED/ , Python, 93 lines, 1 matchped_module.py - Code/
04_PED/ , Python, 625 linessxpid/ SxPID.py - Code/
04_PED/ , Python, 3 linessxpid/ __init__.py - Code/
04_PED/ , Python, 55 linessxpid/ generate_lattices.py - Code/
05_PhiID/ , Python, 108 linescompute_phiID.py - Code/
compile_packages.sh , Shell, 6 lines - Code/
launch_HOIscript.sh , Shell, 65 lines - Code/
launch_HOIscript_HCP.sh , Shell, 71 lines - Code/
launch_HOIscript_HCP_EMO , Shell, 69 linesTION.sh - Code/
launch_HOIscript_HCP_GAM , Shell, 69 linesBLING.sh - Code/
launch_HOIscript_HCP_LAN , Shell, 74 linesGUAGE.sh - Code/
launch_HOIscript_HCP_MOT , Shell, 69 linesOR.sh - Code/
launch_HOIscript_HCP_REL , Shell, 69 linesATIONAL.sh - Code/
launch_HOIscript_HCP_SOC , Shell, 69 linesIAL.sh - Code/
launch_HOIscript_HCP_WM. , Shell, 69 linessh - Code/
launch_HOIscript_HCPrest , Shell, 69 lines.sh - Code/
plot_hoi/ , MATLAB, 68 linescomputeCohen_d.m - Code/
plot_hoi/ , MATLAB, 20 linesdata2gaussian.m - Code/
plot_hoi/ , MATLAB, 229 linesfdr_bh.m - Code/
plot_hoi/ , MATLAB, 14 linesgaussian_ent_biascorr.m - Code/
plot_hoi/ , MATLAB, 40 lineshigh_order.m - Code/
plot_hoi/ , MATLAB, 166 linesload_nifti.m - Code/
plot_hoi/ , MATLAB, 216 linesload_nifti_hdr.m - Code/
plot_hoi/ , MATLAB, 88 linesmain_Oinfo_GitHub.m - Code/
plot_hoi/ , MATLAB, 14 linesmain_save_nifti.m - Code/
plot_hoi/ , Python, 33 linesplot_hoi.py - Code/
plot_hoi/ , MATLAB, 188 linessave_nifti.m - Code/
plot_hoi/ , MATLAB, 34 linessoinfo_from_covmat.m - Code/
plot_hoi/ , MATLAB, 35 linesstrlen.m - Code/
statistical_testing/ , Python, 14 linesspin_perm.py - Code/
utils/ , Python, 510 linesbrain_network_measures.p y - Code/
utils/ , Python, 352 linesbrain_network_processor. py - Code/
utils/ , Shell, 1 lineenigma_set.sh - Code/
utils/ , Python, 455 linessurf_mod.py - Code/
utils/ , Python, 561 linessurfplot_mod.py - Code/
utils/ , Python, 641 linesutils.py - Code/
utils/ , Python, 769 linesutils_identifiability.py - Code/
utils/ , Python, 722 linesutils_neuromaps_brain.py - Code/
utils/ , Python, 454 linesutils_neuromaps_brain_mu ltibrain.py - Code/
utils/ , Python, 110 linesutils_plotting.py - Paper/
Figure2/ , Jupyter, 932 lines, 6 matchesFig2_analyses_clean.ipyn b - Paper/
Figure3/ , Jupyter, 805 lines, 3 matchesFig3_clean.ipynb - Paper/
Figure4/ , Jupyter, 657 linesFig4_fingerprinting.ipyn b - Paper/
Figure4/ , Jupyter, 611 lines, 1 matchFig4_tasks.ipynb - Paper/
Figure5-6/ , Jupyter, 378 lines, 2 matchesFig5_FC_reconstruction.i pynb - Paper/
Figure5-6/ , Jupyter, 658 linesFig5_PLS_behavior.ipynb - Paper/
utils/ , Python, 510 linesbrain_network_measures.p y - Paper/
utils/ , Python, 352 linesbrain_network_processor. py - Paper/
utils/ , Python, 455 linessurf_mod.py - Paper/
utils/ , Python, 561 linessurfplot_mod.py - Paper/
utils/ , Python, 649 linesutils.py - Paper/
utils/ , Python, 407 linesutils_HOI.py - Paper/
utils/ , Python, 769 linesutils_identifiability.py - Paper/
utils/ , Python, 143 linesutils_measures.py - Paper/
utils/ , Python, 618 linesutils_neuromaps_brain.py - Paper/
utils/ , Python, 454 linesutils_neuromaps_brain_mu ltibrain.py - Paper/
utils/ , Python, 110 linesutils_plotting.py - README.md, Text, 84 lines
brainets/hoi
4db2fbd701d40d33fe2375f3df5a4a4dc94c6b83, 30 January 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
60 files
- docs/
conf.py , Python, 125 lines - examples/
it/ , Python, 187 linesplot_entropies.py - examples/
it/ , Python, 164 linesplot_entropies_mvar.py - examples/
it/ , Python, 157 linesplot_entropy_high_dimens ional.py - examples/
it/ , Python, 147 linesplot_mi.py - examples/
it/ , Python, 161 linesplot_mi_high_dimensional .py - examples/
it/ , Python, 78 linestuto_core.py - examples/
metrics/ , Python, 118 linesplot_infotopo.py - examples/
metrics/ , Python, 296 linesplot_oinfo.py - examples/
metrics/ , Python, 176 linesplot_rsi.py - examples/
metrics/ , Python, 168 linesplot_syn_phiID.py - examples/
metrics/ , Python, 216 linesplot_syn_red_mmi.py - examples/
miscellaneous/ , Python, 121 linesplot_inspect_results.py - examples/
miscellaneous/ , Python, 175 linestuto_jax.py - examples/
statistics/ , Python, 202 linesplot_bootstrapping.py - examples/
tutorials/ , Python, 199 linesplot_ml_vs_it.py - examples/
tutorials/ , Python, 345 linesplot_sim_red_syn.py - hoi/
__init__.py , Python, 3 lines - hoi/
core/ , Python, 12 lines__init__.py - hoi/
core/ , Python, 105 linescombinatory.py - hoi/
core/ , Python, 427 linesentropies.py - hoi/
core/ , Python, 382 linesmi.py - hoi/
core/ , Python, 1 lineredundancies.py - hoi/
core/ , Python, 93 linestests/ test_combinatory.py - hoi/
core/ , Python, 85 linestests/ test_entropies.py - hoi/
core/ , Python, 72 linestests/ test_mi.py - hoi/
metrics/ , Python, 15 lines__init__.py - hoi/
metrics/ , Python, 325 linesbase_hoi.py - hoi/
metrics/ , Python, 207 linesdo_tot.py - hoi/
metrics/ , Python, 163 linesdtc.py - hoi/
metrics/ , Python, 108 linesgradient_oinfo.py - hoi/
metrics/ , Python, 128 linesinfo_tot.py - hoi/
metrics/ , Python, 159 linesinfotopo.py - hoi/
metrics/ , Python, 168 linesoinfo.py - hoi/
metrics/ , Python, 169 linespairwise_mi.py - hoi/
metrics/ , Python, 341 lines, 2 matchesphiid_atoms.py - hoi/
metrics/ , Python, 179 lines, 2 matchesphiid_red.py - hoi/
metrics/ , Python, 341 linespid_atoms.py - hoi/
metrics/ , Python, 129 linesred_mmi.py - hoi/
metrics/ , Python, 158 linesrsi.py - hoi/
metrics/ , Python, 164 linessinfo.py - hoi/
metrics/ , Python, 143 linessyn_mmi.py - hoi/
metrics/ , Python, 162 linestc.py - hoi/
metrics/ , Python, 377 linestests/ test_metrics.py - hoi/
metrics/ , Python, 187 linestransfer_entropy.py - hoi/
plot/ , Python, 1 line__init__.py - hoi/
plot/ , Python, 106 lineslandscape.py - hoi/
simulation/ , Python, 1 line__init__.py - hoi/
simulation/ , Python, 217 linessimulate_hoi_gauss.py - hoi/
simulation/ , Python, 52 linestests/ test_simulate_hoi_gauss. py - hoi/
utils/ , Python, 3 lines__init__.py - hoi/
utils/ , Python, 153 lineslogging.py - hoi/
utils/ , Python, 1 linemulticores.py - hoi/
utils/ , Python, 16 linesprogressbar.py - hoi/
utils/ , Python, 305 linesstats.py - hoi/
utils/ , Python, 21 linestests/ test_progressbar.py - hoi/
utils/ , Python, 77 linestests/ test_stats.py - setup.py, Python, 82 lines
- LICENSE, License, 28 lines
- README.rst, Text, 106 lines
andresantoro/EasyBrainSurfacePlots
c709d995f97c8f8e02055f7d2862b6aa0606ea89, 22 June 2023Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
4 files
- 01_example_surface_plots
.ipynb , Jupyter, 107 lines, 1 match - utils_neuromaps_brain.py
, Python, 446 lines, 1 match - LICENSE, License, 674 lines
- README.md, Text, 36 lines
Code availability statement
The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: brainets/
hoi , nplresearch/HOI_lenses_analysis , Zenodo 20260959
Read it in the paper: doi.org/10.1038/s41467-026-75959-w.
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:
- 5 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 152 scripts, each with its path and the digest of its content;
- 23 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
The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- no repository, dataset or request procedure was recognized in it
Read it in the paper: doi.org/10.1038/s41467-026-75959-w.
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, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 2 keywords, 10 MeSH terms, 2 funders, 154 references.
Cite
This paper
Santoro, A., Neri, M., Poetto, S., Orsenigo, D., Diano, M., Gatica, M., & Petri, G. (2026). Charting higher-order models of brain function beyond pairwise interactions. Nature communications, 17(1), 9207. https://
BibTeX
@article{santoro2026char
author = {Santoro, Andrea and Neri, Matteo and Poetto, Simone and Orsenigo, Davide and Diano, Matteo and Gatica, Marilyn and Petri, Giovanni},
title = {{Charting higher-order models of brain function beyond pairwise interactions}},
journal = {Nature communications},
year = {2026},
month = jul,
volume = {17},
number = {1},
pages = {9207},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/
url = {https://
pmid = {42660887},
pmcid = {PMC13522477}
}
RIS
TY - JOUR
AU - Santoro, Andrea
AU - Neri, Matteo
AU - Poetto, Simone
AU - Orsenigo, Davide
AU - Diano, Matteo
AU - Gatica, Marilyn
AU - Petri, Giovanni
TI - Charting higher-order models of brain function beyond pairwise interactions
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/
VL - 17
IS - 1
SP - 9207
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Charting higher-order models of brain function beyond pairwise interactions",
"container-title": "Nature communications",
"author": [
{
"family": "Santoro",
"given": "Andrea"
},
{
"family": "Neri",
"given": "Matteo"
},
{
"family": "Poetto",
"given": "Simone"
},
{
"family": "Orsenigo",
"given": "Davide"
},
{
"family": "Diano",
"given": "Matteo"
},
{
"family": "Gatica",
"given": "Marilyn"
},
{
"family": "Petri",
"given": "Giovanni"
}
],
"container-title-short":
"volume": "17",
"issue": "1",
"page": "9207",
"DOI": "10.1038/
"PMID": "42660887",
"PMCID": "PMC13522477",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
29
]
]
}
}
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.1016/j.patter.2026.101619 [code]
- Sampling bias corrections for discrete and Gaussian partial information decompositions.Journal: Patterns (New York, N.Y.)In common: Nilearn, NiBabel, Statistics and Machine Learning Toolbox, 6 other tools, 17 references, author Davide Orsenigo
- [2] doi:10.1371/journal.pone.0348005 [code]
- THOI: An efficient and accessible library for computing higher-order interactions enhanced by batch-processing.Journal: PloS oneIn common: NetworkX, seaborn, scikit-learn, 4 other tools, 15 references
- [3] doi:10.1038/s41593-026-02205-3 [code]
- Competitive interactions shape mammalian brain network dynamics and computation.Journal: Nature neuroscienceIn common: NetworkX, NiBabel, Statistics and Machine Learning Toolbox, 6 other tools, 15 references
- [4] doi:10.1038/s41531-026-01354-3 [code]
- Neuromodulation-induced normalization of cortical metastable dynamics signatures in Parkinson's disease.Journal: NPJ Parkinson's diseaseIn common: neuromaps, BrainSpace, Nilearn, 9 other tools, 9 references
- [5] doi:10.1002/hbm.70485 [code]
- Exploring the Role of the Rich Club in Network Control of Neurocognitive States.Journal: Human brain mappingIn common: BrainSpace, Nilearn, NiBabel, 5 other tools, 12 references
- [6] doi:10.1038/s41467-026-74466-2 [code]
- Neuromorphic hierarchical modular reservoirs.Journal: Nature communicationsIn common: neuromaps, Numba, Nilearn, 9 other tools, 8 references
- [7] doi:10.1038/s41467-026-71270-w [code]
- Spatiotemporal dynamics of the human cortical functional hierarchy across the lifespan.Journal: Nature communicationsIn common: BrainSpace, Nilearn, NetworkX, 9 other tools, 9 references
- [8] doi:10.1038/s41398-026-04025-2 [code]
- Brain energetic landscapes shape state dysregulation in major depressive disorder: a morphological network controllability perspective.Journal: Translational psychiatryIn common: neuromaps, BrainSpace, Nilearn, 9 other tools, 8 references
- [9] doi:10.1186/s12916-026-04903-y [code]
- Structural connectome architecture and biological vulnerability shape cortical atrophy in cocaine use disorder.Journal: BMC medicineIn common: neuromaps, Nilearn, statsmodels, 7 other tools, 12 references
- [10] doi:10.21203/rs.3.rs-9326213/v1 [code]
- Multi-task fMRI outperforms resting-state fMRI for revealing task-invariant organization of the human brainJournal: Research Square (preprint)In common: neuromaps, Numba, Nilearn, 8 other tools, 9 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: 5 repositories of the authors' code, each at its verified commit and with its license, 152 scripts, and 23 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:2ef72ba65d36e706…
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.
