Phase-tuned modulation during reward expectancy in human anterior insular cortex.
The 2 matches
- [1] § Methods › Analysis of phase shifts in PAC temporal patterns ↔ Precession_utils.py, lines 119–192 · score 0.65 · circular linear correlation, circular variable, correlation coefficient, phases
- [2] § Methods › Identification of RBPs and their pre-activation ↔ extractRSAvalues.m, lines 47–99 · score 0.57 · brain patterns, Fisher, overlap, transformed, Spearman, vector
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 388 lines · 12 KB · CC-BY-4.0 · 1 match
- import numpy as np
- import os
- import math
- import scipy as sp
- import pandas as pd
- import pycircstat as pcs
- import pyfftw
- import multiprocessing
- import numba
- from scipy.signal import find_peaks
- # These are the core functions used to identify both spatial and non-spatial phase precession
- def corrcc(alpha1, alpha2, axis=None):
- """
- Circular correlation coefficient for two circular random variables.
- Parameters
- ----------
- alpha1: 1d array
- sample of angles in radians
- alpha2: 1d array
- sample of angles in radians
- axis: int
- correlation coefficient is computed along this dimension
- (default axis=None, across all dimensions)
- Returns
- ----------
- rho: float
- Circular-circular correlation coefficient
- pval: float
- Circular-circular correlation p-value
- References: [Jammalamadaka2001]_
- Original: https://github.com/circstat/pycircstat
- modified by: Salman Qasim, 11/12/2018
- """
- assert alpha1.shape == alpha2.shape, 'Input dimensions do not match.'
- n = len(alpha1)
- # center data on circular mean
- alpha1_centered, alpha2_centered = pcs.descriptive.center(alpha1, alpha2, axis=axis)
- num = np.sum(np.sin(alpha1_centered) * np.sin(alpha2_centered), axis=axis)
- den = np.sqrt(np.sum(np.sin(alpha1_centered) ** 2, axis=axis) *
- np.sum(np.sin(alpha2_centered) ** 2, axis=axis))
- # compute correlation coefficient from p. 176
- rho = num / den
- # Modification:
- # significance of this correlation coefficient can be tested using the fact that Z is approx. normal
- l20 = np.mean(np.sin(alpha1_centered) ** 2)
- l02 = np.mean(np.sin(alpha2_centered) ** 2)
- l22 = np.mean((np.sin(alpha1_centered) ** 2) * (np.sin(alpha2_centered) ** 2))
- z = np.sqrt((n * l20 * l02) / l22) * rho
- pval = 2 * (1 - sp.stats.norm.cdf(np.abs(z))) # two-sided test
- return rho, pval
- def corrcc_uniform(alpha1, alpha2, axis=None):
- """
- Circular correlation coefficient for two circular random variables.
- Use if at least one of our variables may be a uniform distribution
- Parameters
- ----------
- alpha1: 1d array
- sample of angles in radians
- alpha2: 1d array
- sample of angles in radians
- axis: int
- correlation coefficient is computed along this dimension
- (default axis=None, across all dimensions)
- Returns
- ----------
- rho: float
- Circular-circular correlation coefficient
- pval: float
- Circular-circular correlation p-value
- References: [Jammalamadaka2001]_
- Original: https://github.com/circstat/pycircstat
- https://github.com/HoniSanders/measure_phaseprec/blob/master/cl_corr.m
- modified by: Salman Qasim, 11/12/2018
- """
- assert alpha1.shape == alpha2.shape, 'Input dimensions do not match.'
- n = len(alpha1)
- # center data on circular mean
- alpha1_centered, alpha2_centered = pcs.descriptive.center(alpha1, alpha2, axis=axis)
- # One of the sample means is not well defined due to uniform distribution of data
- # so take the difference of the resultant vector length for the sum and difference of the alphas
- num = pcs.descriptive.resultant_vector_length(alpha1 - alpha2) - pcs.descriptive.resultant_vector_length(alpha1 + alpha2)
- den = 2 * np.sqrt(np.sum(np.sin(alpha1_centered) ** 2, axis=axis) *
- np.sum(np.sin(alpha2_centered) ** 2, axis=axis))
- rho = n * num / den
- # significance of this correlation coefficient can be tested using the fact that Z is approx. normal
- l20 = np.mean(np.sin(alpha1_centered) ** 2)
- l02 = np.mean(np.sin(alpha2_centered) ** 2)
- l22 = np.mean((np.sin(alpha1_centered) ** 2) * (np.sin(alpha2_centered) ** 2))
- z = np.sqrt((n * l20 * l02) / l22) * rho
- pval = 2 * (1 - sp.stats.norm.cdf(np.abs(z))) # two-sided test
- return rho, pval
- def spatial_phase_precession(spike_phases, spike_position, slope_bounds=[-3*np.pi, 3*np.pi]):
- """
- Compute the circular-linear correlation as in: https://pubmed.ncbi.nlm.nih.gov/22487609/
- Parameters
- ----------
- circ : 1d array
- Circular data in radians (i.e. spike phases)
- lin : 1d array
- Linear data (i.e. spike positions)
- slope_bounds: 1d array, or tuple
- Slope range has to be restricted for optimization
- Returns
- ----------
- rho: float
- Circular-linear correlation coefficient
- pval: float
- Circular-linear correlation p-value
- sl: float
- Circular-linear correlation slope
- offs: float
- Circular-linear correlation offset
- Notes
- -----
- This is different from the linear-circular correlation used in: https://science.sciencemag.org/content/340/6138/1342
- I've modified the pcs.descriptive.corrcc function above to compute a p-value in two different scenarios
- """
- # Get rid of all the nans in this data
- nan_index = np.logical_or(np.isnan(circ), np.isnan(lin))
- circ = circ[~nan_index]
- lin = lin[~nan_index]
- # Make sure there are still valid data
- if np.size(lin) == 0:
- return np.nan, np.nan, np.nan, np.nan
- def myfun1(p):
- return -np.sqrt(
- (np.sum(np.cos(circ - (p * lin))) / len(circ)) ** 2 + (np.sum(np.sin(circ - (p * lin))) / len(circ)) ** 2)
- # finding the optimal slope, note that we have to restrict the range of slopes
- sl = sp.optimize.fminbound(myfun1, slope_bounds[0] / (np.max(lin) - np.min(lin)), slope_bounds[1] / (
- np.max(lin) - np.min(lin)))
- # calculate offset
- offs = np.arctan2(np.sum(np.sin(circ - (sl * lin))), np.sum(np.cos(circ - (sl * lin))))
- # circular variable derived from the linearization
- linear_circ = np.mod(abs(sl) * lin, 2 * np.pi)
- # # marginal distributions:
- # p1, z1 = pcs.tests.rayleigh(circ)
- # p2, z2 = pcs.tests.rayleigh(linear_circ)
- # circular-linear correlation:
- if (p1 > 0.5) | (p2 > 0.5):
- # This means at least one of our variables may be a uniform distribution
- rho, pval = corrcc_uniform(circ, linear_circ)
- else:
- rho, pval = corrcc(circ, linear_circ)
- # Assign the correct sign to rho
- if sl < 0:
- rho = -np.abs(rho)
- else:
- rho = np.abs(rho)
- return rho, pval, sl, offs
- @numba.jit(nopython=True)
- def pcorrelate(t, u, bins):
- """
- From : https://github.com/OpenSMFS/pycorrelate
- Compute correlation of two arrays of discrete events (Point-process).
- The input arrays need to be values of a point process, such as
- photon arrival times or positions. The correlation is efficiently
- computed on an arbitrary array of lag-bins. As an example, bins can be
- uniformly spaced in log-space and span several orders of magnitudes.
- (you can use :func:`make_loglags` to creat log-spaced bins).
- This function implements the algorithm described in
- `(Laurence 2006) <https://doi.org/10.1364/OL.31.000829>`__.
- Arguments:
- t (array): first array of "points" to correlate. The array needs
- to be monothonically increasing.
- u (array): second array of "points" to correlate. The array needs
- to be monothonically increasing.
- bins (array): bin edges for lags where correlation is computed.
- normalize (bool): if True, normalize the correlation function
- as typically done in FCS using :func:`pnormalize`. If False,
- return the unnormalized correlation function.
- Returns:
- Array containing the correlation of `t` and `u`.
- The size is `len(bins) - 1`.
- """
- nbins = len(bins) - 1
- # Array of counts (histogram)
- counts = np.zeros(nbins, dtype=np.int64)
- # For each bins, imin is the index of first `u` >= of each left bin edge
- imin = np.zeros(nbins, dtype=np.int64)
- # For each bins, imax is the index of first `u` >= of each right bin edge
- imax = np.zeros(nbins, dtype=np.int64)
- # For each ti, perform binning of (u - ti) and accumulate counts in Y
- for ti in t:
- for k, (tau_min, tau_max) in enumerate(zip(bins[:-1], bins[1:])):
- if k == 0:
- j = imin[k]
- # We start by finding the index of the first `u` element
- # which is >= of the first bin edge `tau_min`
- while j < len(u):
- if u[j] - ti >= tau_min:
- break
- j += 1
- imin[k] = j
- if imax[k] > j:
- j = imax[k]
- while j < len(u):
- if u[j] - ti >= tau_max:
- break
- j += 1
- imax[k] = j
- # Now j is the index of the first `u` element >= of
- # the next bin left edge
- counts += imax - imin
- G = counts / np.diff(bins)
- return G
- def fast_acf(counts, width, bin_width, cut_peak=True):
- """
- Super fast ACF function relying on numba (above).
- Parameters
- ----------
- cut_peak : bool
- Whether or not the largest central peak should be replaced for subsequent fitting
- counts : 1d array
- Variable of interest (i.e. spike times or spike phases)
- width: float
- Time window for ACF
- bin_width: float
- Width of bins
- Returns
- ----------
- acf: 1d array
- Counts for ACF
- bins: 1d array
- Lag bins for ACF
- Notes
- -----
- """
- n_b = int(np.ceil(width / bin_width)) # Num. edges per side
- # Define the edges of the bins (including rightmost bin)
- bins = np.linspace(-width, width, 2 * n_b, endpoint=True)
- temp = pcorrelate(counts, counts, np.split(bins, 2)[1])
- acf = np.ones(bins.shape[0] - 1)
- acf[0:temp.shape[0]] = np.flip(temp)
- acf[temp.shape[0]] = temp[0]
- acf[temp.shape[0] + 1:] = temp
- if cut_peak:
- acf[np.nanargmax(acf)] = np.sort(acf)[-2]
- return acf, bins
- def acf_power(acf, norm=True):
- """
- Compute the power spectrum of the signal by computing the FFT of the autocorrelation.
- Parameters
- ----------
- acf: 1d array
- Counts for ACF
- norm: bool
- To normalize or not
- Returns
- ----------
- psd: 1d array
- Power spectrum
- Notes
- -----
- """
- # Take the FFT
- fft = pyfftw.interfaces.numpy_fft.fft(acf, threads=multiprocessing.cpu_count())
- # Compute the power from the real component squared
- pow = (np.abs(fft) ** 2)
- # Account for nyquist
- psd = pow[0:round(pow.shape[0] / 2)]
- # normalize
- if norm:
- psd = psd / np.trapz(psd)
- return psd
- def nonspatial_phase_precession(unwrapped_spike_phases, width=4 * 2 * np.pi, bin_width=np.pi/3, cut_peak=True, norm=True, psd_lims = [0.65, 1.55]):
- """
- Compute the nonspatial spike-LFP relationship modulation index.
- Parameters
- ----------
- unwrapped_spike_phases : 1d array
- Spike phases that have been linearly unwrapped
- width: float
- Time window for ACF in cycles (default = 4 cycles)
- bin_width: float
- Width of bins in radians (default = 60 degrees)
- cut_peak : bool
- Whether or not the largest central peak should be replaced for subsequent fitting
- norm: bool
- To normalize the ACF or not
- Returns
- ----------
- max_freq: float
- Relative spike-LFP frequency of PSD peak
- MI: float
- Modulation index of non-spatial phase relationship
- Notes
- -----
- """
- frequencies = (np.arange(2 * (width // bin_width) - 1)) * (2 * np.pi) / (
- 2 * width - bin_width)
- freqs_of_interest = np.intersect1d(np.where(frequencies < psd_lims[0]),
- np.where(frequencies> psd_lims[1]))
- acf, _ = fast_acf(unwrapped_spike_phases, width, bin_width, cut_peak=cut_peak)
- psd = acf_power(acf, norm=norm)
- all_peaks = find_peaks(PSD_norm[freqs_of_interest], None)[0] # FIND ALL LOCAL MAXIMA IN WINDOW
- # make sure there is a peak.... .
- if ~np.any(all_peaks):
- return np.nan, np.nan
- max_peak = np.max(PSD_norm[freqs_of_interest][all_peaks])
- max_idx = [all_peaks[np.argmax(PSD_norm[freqs_of_interest][all_peaks])]]
- max_freq = frequencies[freqs_of_interest][max_idx]
- MI = max_peak / np.trapz(PSD_norm[freqs_of_interest])
- return max_freq, MI
Precession_utils.py, under CC-BY-4.0 · at the source
Overview
- Department of Psychiatry, Second Affiliated Hospital, School of Medicine, Zhejiang University,Hangzhou, China
- Department of Neurology, Epilepsy Center, Second Affiliated Hospital, School of Medicine, Zhejiang University,Hangzhou, China
- CENIR - Centre de Neuro-Imagerie de Recherche, Paris Brain Institute, ICM, Hôpital de la Pitié-Salpêtrière,Paris, France
- Department of Radiology, Second Affiliated Hospital, School of Medicine, Zhejiang University,Hangzhou, China
- Sorbonne Université, Inserm, CNRS, Paris Brain Institute, ICM, Hôpital de la Pitié-Salpêtrière,Paris, France
- Epilepsy Unit, AP-HP, PitiéSalpêtrière Hospital,Paris, France
- Clinical Neurophysiology Department, AP-HP, Pitié-Salpêtrière Hospital,Paris, France
- Institute for Neural Computation, Faculty of Computer Science, Ruhr University Bochum,Bochum, Germany
- Department of Neuropsychology, Institute of Cognitive Neuroscience, Faculty of Psychology, Ruhr University Bochum,Bochum, Germany
- State Key Laboratory of Cognitive Neuroscience and Learning and IDG/McGovern Institute for Brain Research, Beijing Normal University,Beijing, PR China
Abstract
Reward expectancy engages the anterior insular cortex (AIC) to coordinate cognitive allocation. Using intracranial electroencephalographic data from epilepsy patients navigating a virtual T-maze, we identified reward-specific brain patterns (RBPs) that were preactivated in the AIC prior to reward onset. This pre-activation was followed by phase-amplitude coupling (PAC) between theta oscillations and gamma activity, with coupling strength positively correlated with the pre-activation level across contacts. Furthermore, this PAC exhibited a phase-precession-like effect (PPLE), characterized by a progressive shift of peak gamma activity to earlier theta phases across successive navigation rounds. Participants exhibiting stronger PPLE in the AIC showed greater trial-by-trial improvements in reward-collection performance. Taken together, these findings reveal a precise phase-tuned timing mechanism in the AIC that supports reward-directed behavior. Specifically, oscillatory coordination initiated by representational pre-activation, is dynamically refined through PPLE across successive exposures to the same reward. This mechanism accelerates responses to impending rewards, thereby optimizing adaptive behavior.
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 2 matches between paragraphs and lines of code.
figshare 30413173
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
9 files
- PAClme.m, MATLAB, 35 lines
- PhaseShift.py, Python, 51 lines
- PhaseShift_surr.py, Python, 52 lines
- Precession_utils.py, Python, 388 lines, 1 match
- RSAlme.m, MATLAB, 38 lines
- extractPACvalues.m, MATLAB, 64 lines
- extractRSAvalues.m, MATLAB, 99 lines, 1 match
- get_klmi_jia.m, MATLAB, 115 lines
- README.md, Text, 9 lines
Code availability
The custom-written Matlab and Python code supporting the findings of this study will be made available at the Figshare repository84 https://
Reproduced under the paper's license (CC BY), from the paper cited above.
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;
- 8 scripts, each with its path and the digest of its content;
- 2 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
The raw iEEG data are confidential medical records and cannot be publicly deposited due to ethical and privacy restrictions. All numerical data used to generate the data shown are available at the Figshare repository84 https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 2 keywords, 9 MeSH terms, 2 funders, 83 references.
Cite
This paper
Yang, L., Lehongre, K., Yu, X., Ye, H., Navarro, V., Cheng, S., Axmacher, N., Wang, S., & Zhang, H. (2026). Phase-tuned modulation during reward expectancy in human anterior insular cortex. Communications biology, 9(1), 1148. https://
BibTeX
@article{yang2026phase,
author = {Yang, Linglin and Lehongre, Katia and Yu, Xinfeng and Ye, Hongyi and Navarro, Vincent and Cheng, Sen and Axmacher, Nikolai and Wang, Shuang and Zhang, Hui},
title = {{Phase-tuned modulation during reward expectancy in human anterior insular cortex}},
journal = {Communications biology},
year = {2026},
month = jun,
volume = {9},
number = {1},
pages = {1148},
publisher = {Nature Publishing Group},
issn = {2399-3642},
doi = {10.1038/
url = {https://
pmid = {42304129},
pmcid = {PMC13521940}
}
RIS
TY - JOUR
AU - Yang, Linglin
AU - Lehongre, Katia
AU - Yu, Xinfeng
AU - Ye, Hongyi
AU - Navarro, Vincent
AU - Cheng, Sen
AU - Axmacher, Nikolai
AU - Wang, Shuang
AU - Zhang, Hui
TI - Phase-tuned modulation during reward expectancy in human anterior insular cortex
T2 - Communications biology
J2 - Commun Biol
PY - 2026
DA - 2026/
VL - 9
IS - 1
SP - 1148
SN - 2399-3642
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Phase-tuned modulation during reward expectancy in human anterior insular cortex",
"container-title": "Communications biology",
"author": [
{
"family": "Yang",
"given": "Linglin"
},
{
"family": "Lehongre",
"given": "Katia"
},
{
"family": "Yu",
"given": "Xinfeng"
},
{
"family": "Ye",
"given": "Hongyi"
},
{
"family": "Navarro",
"given": "Vincent"
},
{
"family": "Cheng",
"given": "Sen"
},
{
"family": "Axmacher",
"given": "Nikolai"
},
{
"family": "Wang",
"given": "Shuang"
},
{
"family": "Zhang",
"given": "Hui"
}
],
"container-title-short":
"volume": "9",
"issue": "1",
"page": "1148",
"DOI": "10.1038/
"PMID": "42304129",
"PMCID": "PMC13521940",
"ISSN": "2399-3642",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
16
]
]
}
}
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.1371/journal.pbio.3003818 [code]
- Human neuronal firing varies with the frequency of local field potential oscillations.Journal: PLoS biologyIn common: CircStat, Statistics and Machine Learning Toolbox, 7 references
- [2] doi:10.7554/elife.108023 [code]
- Challenges in replay detection by TDLM in post-encoding resting state.Journal: eLifeIn common: Numba, Statistics and Machine Learning Toolbox, pandas, 2 other tools, 3 references
- [3] doi:10.1002/hipo.70131 [code]
- Decoding Medial Entorhinal Cortical Dynamics Produces Planning-Like Alternations in Hippocampal theta Sequences.Journal: HippocampusIn common: Numba, pandas, SciPy, 1 other tool, 4 references
- [4] doi:10.1016/j.celrep.2026.117845 [code]
- Hippocampal skill memory expansion drives online performance dynamics during skill learning.Journal: Cell reportsIn common: SciPy, NumPy, 6 references
- [5] doi:10.1093/brain/awaf431 [code]
- Behavioural and clinical biomarkers of the human bed nucleus of stria terminalis from direct neural recordings.Journal: Brain : a journal of neurologyIn common: Statistics and Machine Learning Toolbox, 6 references
- [6] doi:10.1093/braincomms/fcag130 [code]
- Sleep increases firing rate modulation during interictal epileptiform discharges in mesial temporal structures.Journal: Brain communicationsIn common: Statistics and Machine Learning Toolbox, EEG, 1 reference, author Katia Lehongre
- [7] doi:10.1126/sciadv.aea1037 [code]
- Distinct cortical spatial representations learned along disparate visual pathways.Journal: Science advancesIn common: CircStat, Numba, Statistics and Machine Learning Toolbox, 3 other tools, 1 reference
- [8] doi:10.1523/jneurosci.2001-25.2026 [code]
- Dynamics of Dentate Gyrus Place Cells and Dentate Spikes during Spatial and Nonspatial Changes in Environments.Journal: The Journal of neuroscience : the official journal of the Society for NeuroscienceIn common: CircStat, Numba, Statistics and Machine Learning Toolbox, 3 other tools, 1 reference
- [9] doi:10.64898/2026.03.12.710517 [code]
- Cortical excitability inversely modulates fMRI connectivity via low-frequency neuronal couplingJournal: bioRxiv (preprint)In common: CircStat, Statistics and Machine Learning Toolbox, pandas, 2 other tools, 2 references
- [10] doi:10.1162/imag.a.105 [code]
- Right posterior theta reflects human parahippocampal phase resetting by salient cues during goal-directed navigationJournal: n/aIn common: CircStat, Statistics and Machine Learning Toolbox, pandas, 2 other tools, EEG, 2 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 8 scripts, and 2 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:ffdc9f7b77954220…
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
[.
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.
