A vector-based strategy for olfactory navigation in Drosophila.
The 3 matches
- [1] § A behavioural model of edge tracking ↔ state_space_model/simulation_agent.py, lines 6–68 · score 0.60 · state transitions, exit direction, exit memory, cross, state space model, fit
- [2] § A behavioural model of edge tracking ↔ state_space_model/sssm.py, lines 62–85 · score 0.56 · continuous latent variables, state space model, switching
- [3] § A behavioural model of edge tracking ↔ state_space_model/simulation_agent.py, lines 6–68 · score 0.55 · memory updates, exit memory, transition, crosses, state space model, fits
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 · 309 lines · 15 KB · MIT · 2 matches
- import os
- import numpy as np
- class Agent(object):
- def __init__(self, dt=None,
- dt_fit=None, r_011=None, p_011=None, r_100=None, p_100=None,
- _radius_bkw=1, _radius_fwd=1, _flter='average',
- _tau=None, _radius=None, sub_wind=False,
- a_m=None, b_m=None, sigma_m=None, init_m=None, downwind_thres=0,
- resample_exit_m=False,
- goal_speeds=None, a_v=None, sigma_v=None,
- tau_a1=9.8, tau_r1=0.72, beta=0.01, stim_thres=0.25, **kwargs):
- self.dt = dt
- ####### parameters for odor filtering and binarizing. (alvarez-salvado et al 2018)
- self.exp_tau_a1 = np.exp(- dt / tau_a1) # for odor adaptation factor
- self.exp_tau_r1 = np.exp(- dt / tau_r1) # for odor response
- self.beta = beta # for odor compression
- self.stim_thres = stim_thres # threshold to binarize odor
- ####### paramters for delay in state transition. negative binomial distribution
- ############ dt_fit: parameters are learned from data with time step dt_fit
- ############ r_011, p_011: duration of leaving state after exit
- ############ r_100, p_100: duration of returning state after entry
- self.r_arr = [r_011, r_100]
- self.p_arr = [p_011, p_100]
- self.delay_coef = int(dt_fit / dt)
- ####### whether to subtract wind direction from exit direction for memory update
- self.sub_wind = sub_wind
- ####### parameters for computing travel direction for memory update
- self._radius_bkw = _radius_bkw * int(dt_fit / dt)
- self._radius_fwd = _radius_fwd * int(dt_fit / dt)
- self._flter = _flter
- self._tau = _tau * int(dt_fit / dt) if _tau is not None else None
- self._radius = _radius * int(dt_fit / dt) if _radius is not None else None
- ####### parameters for memory update: m(t+1) = a_m * m(t) + b_m * v(t) + sqrt(sigma_m) * randn(2)
- self.a_m = a_m
- self.b_m = [(1 - a_mk) for a_mk in a_m] if b_m is None else b_m
- self.sigma_m = sigma_m
- ####### parameters for memory initialization
- self.init_m = init_m
- self.downwind_thres = downwind_thres
- ####### resample exit memory from initialization distribution
- self.resample_exit_m = resample_exit_m
- ####### goal speeds [returning, leaving]
- self.goal_speeds = goal_speeds
- ####### displacement update: step(t+1) = a_v * step(t) + (1 - a_v) * goal(t+1) + sqrt(sigma) * randn(2)
- ####### convert a_v, sigma_v from time step dt_fit to time step dt_sim
- a_v, sigma_v = a_v.copy(), sigma_v.copy()
- for io in range(2):
- a_v[io], _, sigma_v[io] = param_convert(a_v[io], 1 - a_v[io], sigma_v[io], dt_fit, dt)
- self.a_v = a_v
- self.sigma_v = sigma_v
- #######
- self.rs = None # random state
- self.modes = None # phase of the trial
- self.winds = None # wind direction
- self.odors = None # odor concentration
- self.oadpt = None # odor adaptation factor (equation 8 in alvarez-salvado et al 2018)
- self.ocmpr = None # odor compression (equation 9 in ...)
- self.orspn = None # odor response (equation 10 in ...)
- self.stims = None # stimuli (binarized odor)
- self.ichng = None # the time step when stimuli changes
- self.delay = None # delay of state transition
- self.stats = None # states (leaving/returning)
- self.xmems = None # crossing (entry and exit) memories.
- self.goals = None # goal direction
- self.steps = None # displacement
- self.xylocs = None # xy location
- def reset(self, nT, rs):
- self.rs = rs
- self.modes = np.zeros((nT,)).astype(int)
- self.winds = np.zeros((nT, 2))
- self.odors = np.zeros((nT,))
- self.oadpt = np.zeros((nT,))
- self.ocmpr = np.zeros((nT,))
- self.orspn = np.zeros((nT,))
- self.stims = np.zeros((nT,)).astype(int)
- self.ichng = -1
- self.delay = None
- self.stats = np.zeros((nT,), dtype=int)
- self.xmems = np.zeros((2, nT, 2))
- self.goals = np.zeros((nT, 2))
- self.steps = np.zeros((nT, 2))
- self.xylocs = np.zeros((nT + 1, 2))
- return
- def simulate(self, env, rs_, T, odor_filter=False):
- env.reset()
- nT = int(T / self.dt)
- self.reset(nT, np.random.RandomState(rs_))
- self.xylocs[0] = env.init_loc(self.rs)
- for it in range(nT):
- self.odors[it], self.winds[it], self.modes[it] = env.sense(xyloc=self.xylocs[it], it=it, odors=self.odors,
- steps=self.steps, ichng=self.ichng,
- xylocs=self.xylocs) # kwargs
- self.odor_response(it, odor_filter=odor_filter)
- self.state(it)
- self.memory(it)
- self.goal(it)
- self.step(it)
- return
- def odor_response(self, it, odor_filter=False):
- if odor_filter:
- self.oadpt[it] = self.exp_tau_a1 * self.oadpt[it - 1] + (1 - self.exp_tau_a1) * self.odors[it]
- self.ocmpr[it] = self.odors[it] / (self.odors[it] + self.beta + self.oadpt[it])
- self.orspn[it] = self.exp_tau_r1 * self.orspn[it - 1] + (1 - self.exp_tau_r1) * self.ocmpr[it]
- self.stims[it] = int(self.orspn[it] > self.stim_thres)
- else:
- self.stims[it] = self.odors[it]
- if self.stims[it] != self.stims[it - 1]:
- self.ichng = it - 1
- delay = self.rs.negative_binomial(self.r_arr[self.stims[it]], 1 - self.p_arr[self.stims[it]]) + 1
- self.delay = delay * self.delay_coef
- return
- def state(self, it):
- if it == 0:
- self.stats[it] = self.stims[it]
- elif (self.stats[it - 1] != self.stims[it]) and (it == self.ichng + self.delay):
- self.stats[it] = 1 - self.stats[it - 1]
- else:
- self.stats[it] = self.stats[it - 1]
- return
- def travel_direction(self, it):
- _radius = (self._radius_bkw + self._radius_fwd - 1) if self._radius is None else self._radius
- if self._flter in ['exponential']:
- arr = self.steps[max(0, it - _radius + 1): (it + 1)]
- arr = np.pad(arr, ((-min(0, it - _radius + 1), 0), (0, 0)), 'edge')
- weights = np.arange(it - _radius + 1, it + 1)
- weights = np.exp(-np.abs(weights - it) / self._tau)
- weights = weights / weights.sum()
- val = weights @ arr
- elif self._flter in ['average']:
- val = self.steps[max(0, it - _radius + 1): (it + 1)].mean(0)
- elif self._flter == 'none':
- val = self.steps[it]
- else:
- raise ValueError(f'{self._flter} not implemented.')
- val = val / np.linalg.norm(val) # travel direction
- return val
- def init_memory(self, it, k):
- ####### xmems[0]: memory of entry, initialized as the null vector
- ####### xmems[1]: memory of exit, initialized to be upwind with a random cross wind component
- wind_ortho = np.array([self.winds[it, 1], - self.winds[it, 0]]) # cross wind direction
- vec = (self.rs.uniform(*self.init_m[k][0]) * wind_ortho +
- self.rs.uniform(*self.init_m[k][1]) * self.winds[it])
- if k == 1 and self.sub_wind: # subtract wind direction from exit memory
- vec -= self.winds[it]
- return vec
- def memory(self, it):
- if it == 0:
- for k in range(2):
- self.xmems[k, it] = self.init_memory(it, k)
- return
- for k in range(2): # k=0: entry; k=1: exit
- cond_stim = np.concatenate([np.zeros(self._radius_bkw), np.ones(self._radius_fwd)])
- cond_stim = (1 - cond_stim) if k == 1 else cond_stim
- cond_learn = np.array_equal(cond_stim, self.stims[max(0, it - len(cond_stim) + 1): (it + 1)])
- if cond_learn: # update memory
- direction = self.travel_direction(it - 1)
- if k == 1 and (direction @ self.winds[it] < self.downwind_thres): # ignore downwind exit
- self.xmems[k][it] = self.xmems[k][it - 1]
- continue
- if k == 1 and self.resample_exit_m:
- self.xmems[k][it] = self.init_memory(it, k)
- continue
- if k == 1 and self.sub_wind: # subtract wind direction from exit direction
- direction = direction - self.winds[it]
- self.xmems[k][it] = self.a_m[k] * self.xmems[k][it - 1] + self.b_m[k] * direction
- self.xmems[k][it] += np.sqrt(self.sigma_m[k]) * self.rs.randn(2)
- else:
- self.xmems[k][it] = self.xmems[k][it - 1]
- return
- def goal(self, it):
- self.goals[it] = self.xmems[self.stats[it]][it] # returning: memory of entry; leaving: memory of exit;
- if self.stats[it] == 1 and self.sub_wind:
- self.goals[it] += self.winds[it]
- return
- def step(self, it):
- a = self.a_v[self.stats[it]]
- self.steps[it] = (a * self.steps[it - 1]
- + (1 - a) * self.goals[it] * self.goal_speeds[self.stats[it]] * self.dt
- + np.sqrt(self.sigma_v[self.stats[it]]) * self.rs.randn(2))
- self.xylocs[it + 1] = self.xylocs[it] + self.steps[it]
- return
- def param_convert(a, b, sigma, dt_fit, dt_sim):
- ####### for displacement update equation: step(t+1) = a * step(t) + b * m(t+1) + sqrt(sigma) * randn(2)
- ####### convert parameters under time step dt_fit to time step dt_sim
- if dt_fit == dt_sim:
- return a, b, sigma
- else:
- a_ = np.power(a, dt_sim / dt_fit)
- b_ = b / (1 - a) * (1 - a_)
- sigma = sigma / np.square(dt_fit) # velocity = step_fit / dt_fit
- sigma_ = sigma / (1 - np.square(a)) * (1 - np.square(a_))
- sigma_ = sigma_ * np.square(dt_sim) # step_sim = velocity * dt_sim
- return a_, b_, sigma_
- def param_from_sssm(model, single_trial=False, downwind_thres=0.5):
- param_dict = {'dt_fit': model._dt,
- 'r_011': model.r_011, 'p_011': model.p_011,
- 'r_100': model.r_100, 'p_100': model.p_100,
- 'a_m': model.a_m, 'sigma_m': np.zeros(2),
- 'goal_speeds': model.b_m / (1 - model.a_m),
- 'a_v': model.a_v, 'sigma_v': model.sigma_v,
- '_flter': model._flter, '_tau': model._tau,
- '_radius_bkw': model._radius_bkw, '_radius_fwd': model._radius_fwd,
- 'downwind_thres': downwind_thres}
- if single_trial:
- init_m = model.m0[0] / (model._dt * model.b_m / (1 - model.a_m))[:, None]
- param_dict['init_m'] = np.repeat(init_m[..., None], 2, axis=-1)
- else:
- init_m = np.zeros((2, 2, 2))
- for k in [1]:
- arr = model.m0[:, k, :] / (model.b_m[k] / (1 - model.a_m[k])) / model._dt
- xwind_abs_median = np.median(np.abs(arr[:, 0]))
- init_m[k, 0, :] = [-2 * xwind_abs_median, 2 * xwind_abs_median]
- init_m[k, 1, :] = np.median(arr[:, 1])
- param_dict['init_m'] = init_m
- return param_dict
- def param_from_fixedbias(model):
- param_dict = {'dt_fit': model._dt,
- 'r_011': model.r_011, 'p_011': model.p_011,
- 'r_100': model.r_100, 'p_100': model.p_100,
- 'a_m': np.ones(2), 'sigma_m': np.zeros(2), 'goal_speeds': np.ones(2),
- 'a_v': model.a_v, 'sigma_v': model.sigma_v}
- init_m = model.b_v / (1 - model.a_v[:, None]) / model._dt
- param_dict['init_m'] = np.repeat(init_m[..., None], 2, axis=-1)
- return param_dict
- if __name__ == '__main__':
- from simulation_envs import *
- import matplotlib.pyplot as plt
- import pickle
- from sssm import plot_traj_base, plot_edge
- plt.rcParams.update({'font.size': 6,
- 'font.family': 'arial',
- 'pdf.fonttype': 42,
- 'ps.fonttype': 42,
- 'savefig.dpi': 480})
- ################## param_from_sssm ##################
- name1, fld_str, fld_select = 'All', '0123', '0123'
- name2, init_str = 'N', '_initm01'
- save_file = (f'./files/models_ssm/fly_c_dt0pt2_fld{fld_str}_'
- f'sssm{init_str}_rb3rf3_drctAvgNorm_h0linear_trN200N1_sd0.pkl')
- with open(save_file, 'rb') as f:
- ifldlist_to_sssm = pickle.load(f)
- model = ifldlist_to_sssm[fld_select]
- param_str = f'Fit{name1}{name2}0'
- param_dict = param_from_sssm(model, downwind_thres=0.5)
- print(param_str)
- print(param_dict)
- ######################## setting time step and environment ##############
- dt = 0.2
- odor_filter = False
- # env, T = EnvEdge(deg=45, half_width=25*np.sqrt(2), ymin=-np.inf), 1000
- env, T = EnvEdge(deg=90, half_width=25, ymin=-np.inf), 1000
- # env, T = EnvEdge(deg=0, half_width=25, ymin=-np.inf), 1000
- # env, T = EnvJump(), 600
- # env, T = EnvReplay(deg=0, T1=600, T2=610, dt=dt), 1210
- # env, T = EnvZigzag(deg1=45, deg2=135, deg3=135, y1=200, nx=[0, 3, 11, None][0],
- # dt=dt, dur_thres=2.0, dist_thres=4.0), 2000
- # env, T = EnvZigzag(deg1=45, deg2=45, deg3=135, y1=200, nx=[0, 3, 11, None][2],
- # dt=dt, dur_thres=2.0, dist_thres=4.0), 2000
- ######################## agent ########################
- agent = Agent(dt=dt, **param_dict)
- ######################## run simulation ########################
- rerun = True
- save_file = f'./files/simulations/{param_str}_{env.env_name}.pkl'
- if os.path.isfile(save_file) and (not rerun):
- with open(save_file, 'rb') as f:
- res_list = pickle.load(f)
- else:
- res_list = {}
- for rs_ in range(5): # random seed
- agent.simulate(env, rs_, T, odor_filter=odor_filter)
- res_list[rs_] = {'steps': agent.steps, 'stims': agent.stims, 'modes': agent.modes,
- 'stats': agent.stats, 'xmems': agent.xmems, 'goals': agent.goals,
- 'xyloc0': agent.xylocs[0]}
- # with open(save_file, 'wb') as f:
- # pickle.dump(res_list, f)
- ####################### plot simulated trajectories #######################
- for rs_, res in res_list.items():
- figsize = (5, 5)
- fig, ax = plt.subplots(1, 1, figsize=figsize)
- stims = res['stims']
- nT = len(res['steps'])
- cumsum = np.cumsum(np.array([res['xyloc0']] + list(res['steps'][:nT])), axis=0)
- plot_traj_base(cumsum, res['stims'][:nT], ax,
- nT=None, init_xy=[0, 0], colors=['midnightblue', 'r'], linewidth=0.5)
- ax.axis('equal')
- ax.set_title(rs_)
- fig.show()
- # fig_file = f'./files/figures_ssm/leave_return/sim_{param_str}_{env.env_name}_example{rs_}.pdf'
- # fig.savefig(fig_file, bbox_inches='tight', transparent=True)
simulation_agent.py at commit 225dc7d, under MIT · at the source
Overview
- Laboratory of Neurophysiology and Behavior and Howard Hughes Medical Institute, The Rockefeller University, New York, NY USA
- Mortimer B. Zuckerman Mind Brain Behavior Institute, Kavli Institute for Brain Science, Department of Neuroscience, Columbia University, New York, NY USA
Abstract
For many species, odours serve as key navigational cues1,2. Although tracking an odour plume has been modelled as a reflexive process3–5, it remains unclear whether animals can use memories of their past odour encounters to infer the spatial structure of their chemical environment or their location within it. Here we developed a virtual-reality olfactory paradigm that allows head-fixed Drosophila to explore structured chemical landscapes, offering insight into how memory mechanisms shape their navigational strategies. We found that flies track an appetitive odour corridor by following its boundary, alternating between rapid counter-turns to exit the plume and directed returns to its edge. Using a combination of behavioural modelling, functional calcium imaging and neural perturbations, we show that this ‘edge tracking’ strategy relies on vector-based computations within the Drosophila central complex, in which flies store and dynamically update memories of the direction to return to the plume’s boundary. Consistent with this, we find that FC2 neurons within the fan-shaped body, which encode a fly’s navigational goal6, signal the direction back to the odour boundary when flies are outside the plume. Plume tracking thus engages components of a conserved navigational toolkit, in which flies can use directional memories to navigate through complex and shifting chemical landscapes.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 3 matches between paragraphs and lines of code.
rutalaboratory/Edge-Tracking-Model
225dc7ddbebb30d5f092f7144db02216fd1271b6, 31 March 2025Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
6 files
- state_space_model/
data_preprocess.py , Python, 225 lines - state_space_model/
simulation_agent.py , Python, 309 lines, 2 matches - state_space_model/
simulation_envs.py , Python, 210 lines - state_space_model/
sssm.py , Python, 835 lines, 1 match - LICENSE, License, 21 lines
- README.md, Text, 22 lines
Zenodo 2075181
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
Code availability
Code for the switching state-space model is available at 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:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 4 scripts, each with its path and the digest of its content;
- 3 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:20751812, at Zenodo; found in “Data availability”
Data availability
Data supporting the findings of this study are available via Zenodo at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Publisher: n/a → Nature Portfolio
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 3 keywords, 12 MeSH terms, 2 funders, 47 references.
Cite
This paper
Siliciano, A. F., Minni, S., Morton, C., Dowell, C. K., Eghbali, N. B., Busch, S. E., Rhee, J. Y., Abbott, L. F., & Ruta, V. (2026). A vector-based strategy for olfactory navigation in Drosophila. Nature, 657(8131), 443-454. https://
BibTeX
@article{siliciano2026ve
author = {Siliciano, Andrew F and Minni, Sun and Morton, Chad and Dowell, Charles K and Eghbali, Noelle B and Busch, Silas E and Rhee, Juliana Y and Abbott, L F and Ruta, Vanessa},
title = {{A vector-based strategy for olfactory navigation in Drosophila}},
journal = {Nature},
year = {2026},
month = jul,
volume = {657},
number = {8131},
pages = {443--454},
publisher = {Nature Portfolio},
issn = {0028-0836},
doi = {10.1038/
url = {https://
pmid = {42486983},
pmcid = {PMC13558081}
}
RIS
TY - JOUR
AU - Siliciano, Andrew F
AU - Minni, Sun
AU - Morton, Chad
AU - Dowell, Charles K
AU - Eghbali, Noelle B
AU - Busch, Silas E
AU - Rhee, Juliana Y
AU - Abbott, L F
AU - Ruta, Vanessa
TI - A vector-based strategy for olfactory navigation in Drosophila
T2 - Nature
J2 - Nature
PY - 2026
DA - 2026/
VL - 657
IS - 8131
SP - 443
EP - 454
SN - 0028-0836
PB - Nature Portfolio
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "A vector-based strategy for olfactory navigation in Drosophila",
"container-title": "Nature",
"author": [
{
"family": "Siliciano",
"given": "Andrew F"
},
{
"family": "Minni",
"given": "Sun"
},
{
"family": "Morton",
"given": "Chad"
},
{
"family": "Dowell",
"given": "Charles K"
},
{
"family": "Eghbali",
"given": "Noelle B"
},
{
"family": "Busch",
"given": "Silas E"
},
{
"family": "Rhee",
"given": "Juliana Y"
},
{
"family": "Abbott",
"given": "L F"
},
{
"family": "Ruta",
"given": "Vanessa"
}
],
"container-title-short":
"volume": "657",
"issue": "8131",
"page": "443-454",
"DOI": "10.1038/
"PMID": "42486983",
"PMCID": "PMC13558081",
"ISSN": "0028-0836",
"publisher": "Nature Portfolio",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
22
]
]
}
}
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-75945-2 [code]
- Neural dynamics for working memory and evidence integration during olfactory navigation in Drosophila.Journal: Nature communicationsIn common: drosophila, cognitive, 20 references
- [2] doi:10.1126/sciadv.aeh7220 [code]
- Central complex representations of self-movement are sufficient to compute wind direction in flight.Journal: Science advancesIn common: pandas, SciPy, Matplotlib, 1 other tool, 16 references
- [3] doi:10.7554/elife.107589 [code]
- Distinct evolutionary trajectories of two integration centres, the central complex and mushroom bodies, across Heliconiini butterflies.Journal: eLifeIn common: 11 references
- [4] doi:10.1038/s41467-025-67545-3 [code]
- Updating an allocentric goal from lateralised egocentric visual memories.Journal: Nature communicationsIn common: cognitive, 10 references
- [5] doi:10.1073/pnas.2609141123
- Odor tracking in flying &
lt;i& gt;Drosophila& lt;/ i& gt; requires visual reafference and compass neurons. Journal: Proceedings of the National Academy of Sciences of the United States of AmericaIn common: drosophila, cognitive, 9 references - [6] doi:10.3389/fnsys.2026.1822122 [code]
- Convergence-divergence circuits for multimodal integration of innate and learned opponent valences.Journal: Frontiers in systems neuroscienceIn common: pandas, SciPy, Matplotlib, 1 other tool, 6 references
- [7] doi:10.1038/s41586-026-10735-w [code]
- Distributed control circuits across a brain-and-cord connectome.Journal: NatureIn common: pandas, SciPy, Matplotlib, 1 other tool, drosophila, 5 references
- [8] doi:10.1126/sciadv.aeg3535 [code]
- Undoing of firing rate adaptation enables invariant population codes.Journal: Science advancesIn common: SciPy, Matplotlib, NumPy, 4 references
- [9] doi:10.1371/journal.pcbi.1014577 [code]
- Combining sampling and attractor dynamics in spiking models of head direction systems.Journal: PLoS computational biologyIn common: SciPy, Matplotlib, NumPy, 4 references
- [10] doi:10.1038/s41593-026-02257-5 [code]
- Neural sequences underlying directed turning in Caenorhabditis elegans.Journal: Nature neuroscienceIn common: pandas, SciPy, Matplotlib, 1 other tool, 3 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: 2 repositories of the authors' code, each at its verified commit and with its license, 4 scripts, and 3 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:67e94f87daadf447…
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.
