Naturalistic behavior and self-generated neural activity predictive of self-correction
The 1 match
- [1] § Hippocampal representations of alternatives predict correct choices. ↔ src/gucompaper/changeOfMind_remote_interval.py, lines 421–467 · score 0.60 · remote arm representations, home arm, interval, segments, location, decoded
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 · 675 lines · 31 KB · no license · 1 match
- import numpy as np
- import pandas as pd
- import pickle
- from spyglass.utils.nwb_helper_fn import get_nwb_copy_filename
- from ripple_detection.core import segment_boolean_series
- from gucompaper.decodeQuality import return_low_hpd_time
- from gucompaper.decodeHelpers import runSessionNames
- from gucompaper.changeOfMind_triggered import region
- from gucompaper.ripple_add_replay import (find_start_end,
- position_posterior2arm_posterior,
- select_subset_helper,select_subset_helper_pd)
- from gucompaper.load import load_decode
- from gucompaper.changeOfMind_triggered import linear_map
- from gucompaper.changeOfMind_triggered_position import load_triggered_position_decode_day
- from gucompaper.Analysis_SGU import TrialChoice,DecodeIngredients,ChangeofMind,get_linearization_map,ChangeofMindTriggeredDecode,ChangeofMindRemoteTheta
- from gucompaper.changeOfMind_remote import is_rat_interior
- from gucompaper.changeOfMind import nodes, vectors
- from scipy import stats
- def parse_remote_master(animal,list_of_days,params,minimum_duration = 0.02, min_sum_posterior = 0.2, fill_spyglass = False):
- """This function calls find_remote_theta_animal() and saves the data"""
- all_info_animal, info_animal, time_intervals_animal, arm_identities_animal = find_remote_theta_animal(
- animal,list_of_days,fill_spyglass = fill_spyglass,
- minimum_duration = minimum_duration,
- min_sum_posterior = min_sum_posterior,
- **params)
- success = 1
- #all_info_animal_control, info_animal_control, time_intervals_animal_control, arm_identities_animal_control = find_remote_theta_animal(
- # animal,list_of_days,classifier_param_name,encoding_set,control=True,fill_spyglass = False,**params)
- #success = save_remote_animal(animal, list_of_days, encoding_set, classifier_param_name,params,
- # all_info_animal, info_animal, time_intervals_animal, arm_identities_animal,
- # all_info_animal_control, info_animal_control, time_intervals_animal_control, arm_identities_animal_control,
- # )
- return success
- output_folder = '/stelmo/shijie/change_of_mind_analysis/figure4/'
- def return_save_name_remote_parser(animal, encoding_set, classifier_param_name, d1, d2, proportion = 0.1, use_1d = 1):
- save_name = f'{animal.lower()}_{encoding_set}_{classifier_param_name}_{d1}_{d2}_p{proportion}_use1d{use_1d}'
- return save_name
- def save_remote_animal(animal, list_of_days, encoding_set, classifier_param_name, params,
- all_info_animal, info_animal, time_intervals_animal, arm_identities_animal,
- all_info_animal_control, info_animal_control, time_intervals_animal_control, arm_identities_animal_control
- ):
- d1= list_of_days[0]
- d2= list_of_days[-1]
- proportion = params["proportion"]
- use_1d = int(params["use_1d"])
- save_name = return_save_name_remote_parser(animal, encoding_set, classifier_param_name, d1, d2, proportion, use_1d)
- file_path = output_folder + save_name + '.pkl'
- data = {}
- (data["all_info_animal"],data["all_info_animal_control"],
- data["info_animal"], data["info_animal_control"],
- data["time_intervals_animal"], data["time_intervals_animal_control"],
- data["arm_identities_animal"], data["arm_identities_animal_control"]) = (
- all_info_animal,all_info_animal_control,
- info_animal, info_animal_control,
- time_intervals_animal,time_intervals_animal_control,
- arm_identities_animal, arm_identities_animal_control)
- # Open the file in binary write mode and dump the data
- with open(file_path, 'wb') as file:
- pickle.dump(data, file, protocol=pickle.HIGHEST_PROTOCOL)
- print(f"Data successfully pickled and saved to {file_path}")
- return 1
- def load_remote_animal(animal, list_of_days, encoding_set, classifier_param_name,
- proportion = 0.1, use_1d = 1, minimum_duration = 0.02, min_posterior = 0.2, spyglass = False):
- if spyglass:
- print("Loading from spyglass database instead of pickle file.")
- loaded_data = load_remote_animal_spyglass(animal, list_of_days,
- encoding_set,
- minimum_duration = minimum_duration,
- min_posterior = min_posterior,
- proportion = proportion, use_1d = use_1d)
- return loaded_data
- d1, d2 = list_of_days[0], list_of_days[-1]
- save_name = return_save_name_remote_parser(animal, encoding_set, classifier_param_name, d1, d2, proportion, use_1d)
- file_path = output_folder + save_name + '.pkl'
- with open(file_path, 'rb') as file:
- loaded_data = pickle.load(file)
- print(f"Successfully loaded data from '{file_path}':")
- return loaded_data
- def load_remote_animal_spyglass(animal, list_of_days, parameter_name, minimum_duration = 0.02,min_posterior=0.2,
- proportion = 0.1, use_1d = 1):
- """load from spyglass database instead of pickle file."""
- day_session_animal = []
- time_intervals_animal = []
- arm_identities_animal = []
- change_of_mind_num_animal = []
- for day in list_of_days:
- nwb_file_name = animal.lower() + day + '.nwb'
- nwb_copy_file_name = get_nwb_copy_filename(nwb_file_name)
- print(nwb_copy_file_name)
- session_interval, position_interval = runSessionNames(nwb_copy_file_name)
- remote_parameter = f"dur_{minimum_duration}_sum_{min_posterior}"
- for ind in range(len(session_interval)):
- session_name = session_interval[ind]
- position_name = position_interval[ind]
- epoch_num = int(session_name[:2])
- key_pre = {"nwb_file_name": nwb_copy_file_name, "epoch":epoch_num,
- "minimum_duration":minimum_duration,"remote_parameter":remote_parameter,
- "proportion":proportion, "parameter": parameter_name}
- query = ChangeofMindRemoteTheta & key_pre
- if len(query) == 0:
- print("No triggered decode found for ", key_pre)
- continue
- df = ChangeofMindRemoteTheta().fetch1_dataframe(key_pre)
- trials = df[df.has_remote_interval].index
- for trial in trials:
- remote_interval = df.loc[trial,'remote_interval']
- remote_content = df.loc[trial,'remote_content']
- change_of_mind_num = df.loc[trial,'change_of_mind_num']
- # if use post stopping content only
- # initial_stopping = df.loc[trial,'initial_time']
- # post_ind = [ind for ind in range(len(remote_interval)) if remote_interval[ind][0] >= initial_stopping]
- # remote_interval = [remote_interval[ind] for ind in post_ind]
- # remote_content = [remote_content[ind] for ind in post_ind]
- # if len(remote_content) == 0:
- # continue
- change_of_mind_num_animal.append(change_of_mind_num)
- day_session_animal.append([nwb_copy_file_name, session_name, [trial for i in range(len(remote_interval))]])
- time_intervals_animal.append(remote_interval)
- arm_identities_animal.append(remote_content)
- return {
- "info_animal": day_session_animal,
- "change_of_mind_num_animal": change_of_mind_num_animal,
- "time_intervals_animal": time_intervals_animal,
- "arm_identities_animal": arm_identities_animal
- }
- def find_remote_theta_animal(animal,list_of_days,
- parameter_name = None,
- use_1d = True,
- use_center = False, use_outer = False, use_home = True,
- proportion = 0.05,
- speed_threshold = 4,
- minimum_duration = 0.02,
- min_sum_posterior = 0.2,
- fill_spyglass = False):
- """
- default parameters should be:
- multiple_CoM = True, single_CoM = True, first_CoM = False,
- max_flag = True,
- delta_t_minus = 5,delta_t_plus = 5,
- "segment_only": False,
- Similar to find_remote_theta_animal_new(), but instead of a lumpsum of posterior in arms, it classfies intervals.
- use_1d: if True, use 1D decoding. if False, use 1D decoding collapsed from 2D decoding
- use_center: if True, consider moments when the rat in the center platform, and find decodes that in are outer arms
- use_home: if True, consider moments when the rat is in home arm, and find decodes that are in outer arms
- use_outer: if True, consider moments when the rat is in outer arms, and find decodes that are in all other outer arms including the home arm
- """
- if "2_state" in parameter_name:
- classifier_param_name = "default_decoding_gpu_4armMaze"
- elif "3_state" in parameter_name:
- classifier_param_name = "default_decoding_gpu_4armMaze_3states"
- else:
- classifier_param_name = "default_decoding_gpu_4armMaze"
- if "all_maze" in parameter_name:
- encoding_set = "all_maze"
- elif "run" in parameter_name:
- encoding_set = '2Dheadspeed_above_4'
- else:
- encoding_set = '2Dheadspeed_above_4'
- (day_session_animal, time_intervals_animal, arm_identities_animal) = (
- [],[],[])
- all_day_session_animal = [] # all the trials considered
- for day in list_of_days:
- nwb_file_name = animal.lower() + day + '.nwb'
- nwb_copy_file_name = get_nwb_copy_filename(nwb_file_name)
- print(nwb_copy_file_name)
- session_interval, position_interval = runSessionNames(nwb_copy_file_name)
- for ind in range(len(session_interval)):
- session_name = session_interval[ind]
- position_name = position_interval[ind]
- epoch_num = int(session_name[:2])
- # load triggered position and decode
- key_pre = {"nwb_file_name": nwb_copy_file_name, "epoch":epoch_num,
- "proportion":proportion, "parameter": parameter_name}
- query = ChangeofMindTriggeredDecode & key_pre
- if len(query) == 0:
- print("No triggered decode found for ", key_pre)
- continue
- parameters = (ChangeofMindTriggeredDecode & key_pre).fetch1("parameter_value")
- loaded_data = ChangeofMindTriggeredDecode().fetch1_dataframe(key_pre)
- (triggered_positions, triggered_positions_abs,
- triggered_times_triggered, triggered_times_abs,
- triggered_trial_infos) = (
- loaded_data["triggered_positions_baseoff"], loaded_data["triggered_positions"],
- loaded_data["time_triggered"], loaded_data["time_abs"],
- loaded_data["triggered_trial_info"],
- )
- # make triggered_positions a dataframe, with index of triggered_times_abs
- for tp_ind in range(len(triggered_positions)):
- triggered_positions[tp_ind] = pd.DataFrame({
- 'linear_position': triggered_positions[tp_ind],
- }, index = triggered_times_abs[tp_ind])
- triggered_positions_abs[tp_ind] = pd.DataFrame({
- 'linear_position': triggered_positions_abs[tp_ind],
- }, index = triggered_times_triggered[tp_ind])
- entry = DecodeIngredients & {'nwb_file_name':nwb_copy_file_name,
- 'interval_list_name':session_name}
- # position_1d,position_2d,
- position_1d = pd.read_csv(entry.fetch1('position_1d')) #still need 1D position
- position_2d = pd.read_csv(entry.fetch1('position_2d')) # need 2D position
- # load ChangeofMind info
- key={'nwb_file_name':nwb_copy_file_name,'epoch':epoch_num,'proportion': proportion}
- print(ChangeofMind & key)
- log = ChangeofMind().fetch1_dataframe(key)
- log2 = log.copy()
- # initialization, for spyglass insertion
- log2.insert(6,'has_remote_interval',[False for i in range(len(log2))])
- log2.insert(7,'remote_interval',[[] for i in range(len(log2))])
- log2.insert(8,'remote_content',[[] for i in range(len(log2))])
- log2.insert(9,'change_of_mind_num',[[] for i in range(len(log2))])
- # load decode
- results1d = load_decode(nwb_copy_file_name,
- session_name,
- classifier_param_name = classifier_param_name,
- encoding_set = encoding_set,
- use_1d = use_1d)
- #posterior1d = results1d.sum("state")
- event_indices_session = np.arange(len(triggered_positions))#[ind for ind in range(len(triggered_trial_infos)) if triggered_trial_infos[ind][1] == session_name]
- for event_index in event_indices_session:
- triggered_position = triggered_positions[event_index]
- triggered_position_abs = triggered_positions_abs[event_index]
- triggered_trial_info = triggered_trial_infos[event_index]
- (trial,
- time_interval,
- replayed_arm_identity) = find_remote_theta_interval(
- triggered_position, triggered_position_abs, triggered_trial_info,
- results1d, log, position_1d, position_2d,
- parameters["max_flag"],use_home,use_outer,use_center,
- minimum_duration = minimum_duration,
- min_sum_posterior = min_sum_posterior)
- if len(trial) > 0:
- print("Found remote theta in trial ", trial)
- day_session_animal.append([nwb_copy_file_name,session_name,trial])
- time_intervals_animal.append(time_interval)
- arm_identities_animal.append(replayed_arm_identity)
- trialID = trial[0]
- log2.loc[trialID,'has_remote_interval'] = True
- log2.at[trialID,'remote_interval'] += time_interval
- log2.at[trialID,'remote_content'] += replayed_arm_identity
- if len(log2.at[trialID,'change_of_mind_num']) == 0:
- log2.at[trialID,'change_of_mind_num'] += [0 for _ in range(len(replayed_arm_identity))]
- else:
- change_of_mind_num = int(np.max(log2.loc[trialID,'change_of_mind_num'])) + 1
- log2.at[trialID,'change_of_mind_num'] += [change_of_mind_num for _ in range(len(replayed_arm_identity))]
- all_day_session_animal.append([nwb_copy_file_name,session_name,trial])
- # save back to spyglass
- if fill_spyglass:
- q = {}
- q["parameter"] = parameter_name
- q["pandas"] = log2.to_dict()
- q["nwb_file_name"] = nwb_copy_file_name
- q["epoch"] = epoch_num
- q["proportion"] = proportion
- q["remote_parameter"] = f"dur_{minimum_duration}_sum_{min_sum_posterior}"
- ChangeofMindRemoteTheta().insert1(q, replace = True)
- return all_day_session_animal, day_session_animal,time_intervals_animal,arm_identities_animal
- def find_remote_interval(decode_subset, position2d, threshold = 20, minimum_duration = 0.02):
- position_axis = np.array(decode_subset.coords['position'])
- posterior_position_subset = decode_subset.causal_posterior.sum(dim='state')
- max_posterior_position1d = np.array(position_axis[posterior_position_subset.argmax(dim = 'position')])
- max_posterior_position2d = loc1d_to_2d_vector(max_posterior_position1d)
- # find remote time
- is_remote = np.sqrt(np.sum((max_posterior_position2d - position2d) ** 2, axis = 1)) > threshold
- is_remote_pd = pd.Series(is_remote, index = decode_subset.time)
- is_remote_segments = np.array(segment_boolean_series(
- is_remote_pd, minimum_duration=minimum_duration))
- if len(is_remote_segments) == 0:
- return [],[]
- time_intervals = []
- arm_identity = []
- for i in range(is_remote_segments.shape[0]):
- (t0,t1) = is_remote_segments[i]
- # restrict to continuous state:
- # length of the continuous state should be greater than 20ms
- decode_subset_ = select_subset_helper(decode_subset,(t0,t1))
- state_subset = np.array(decode_subset_.causal_posterior.sum(dim='position'))
- time=np.array(decode_subset_.causal_posterior.time)
- snippets_conti = find_start_end(state_subset[:,0] > 0.5) #continuous
- snippets = [time[s] for s in snippets_conti if np.diff(time[s])[0]>minimum_duration]
- for s in range(len(snippets)):
- (t0_peak,t1_peak) = snippets[s]
- # overall sum of decode posterior in the max posterior arm should be greater than 0.2
- posterior_by_arm = position_posterior2arm_posterior(
- select_subset_helper(posterior_position_subset,snippets[s]),
- linear_map)
- # classify the max/mean posterior arm, exclude the arm the animal is physically at
- subset_ind = (decode_subset.time >= t0_peak) & (decode_subset.time <= t1_peak)
- subset_arm_snippet = linear2arm_including_home(max_posterior_position1d[subset_ind])
- if len(subset_arm_snippet) == 0:
- continue
- subset_arm_snippet = subset_arm_snippet[~np.isnan(subset_arm_snippet)]
- if len(subset_arm_snippet) == 0:
- continue
- modes = np.unique(subset_arm_snippet)
- final_arms = []
- for mode in modes:
- max_arm_ind = int(mode - 5)
- if np.mean(posterior_by_arm[max_arm_ind,:]) < 0.2:
- continue
- final_arms.append(max_arm_ind)
- time_intervals.append(snippets[s])
- arm_identity.append(final_arms)
- return time_intervals, arm_identity
- def find_remote_theta_interval(triggered_position,triggered_position_abs,triggered_trial_info,
- decode,log_df,position_1d,position_2d,
- max_flag = 1,use_home = False,use_outer = True, use_center = False,
- minimum_duration = 0.02, min_sum_posterior = 0.2): # in seconds
- """
- if home = 1: find remote representation at home arm during running instead of at outer well.
- # 1. find time points out side of arm position
- # 2. for each time interval, find arm
- # decode should pass certain criteria:
- # (a) be continuous in decoder state
- # (b) posterior >= threshold%
- # 3. return for each trial a list of time range and arm identity for the decode
- INPUT: decode should be the absolute
- """
- position_axis = np.array(decode.coords['position'])
- # find the arm the animal is at
- subset_arm = triggered_trial_info[-1] + 5
- # find the trial
- # find t0, t1 to consider
- trialID = triggered_trial_info[-2]
- (t0, t1) = (triggered_position.index[0],triggered_position.index[-1])
- if use_home:
- timestamp_H = log_df.loc[trialID,'timestamp_H']
- if not np.isnan(timestamp_H):
- t0 = timestamp_H
- # set by time
- position2d_subset = position_2d[np.logical_and(position_2d.time>=t0, position_2d.time<=t1)]
- position1d_subset = position_1d[np.logical_and(position_1d.time>=t0, position_1d.time<=t1)]
- decode_subset = select_subset_helper(decode,(t0,t1))
- if abs(len(position1d_subset) - len(decode_subset.time)) > 3:
- print("skipped due to decode and camera time frame do not fully match.")
- return [],[],[]
- # set by location
- if use_home:
- subset_arm = 5
- # set by location
- #animal is physically at the home segment and not in the well area
- #stricter: remove well area
- subset_ind = np.logical_and(np.array(position1d_subset.linear_position) >= 10,
- np.array(position1d_subset.linear_position) <= linear_map[1][1])
- elif use_outer:
- # set by location
- subset_ind = position1d_subset.track_segment_id == subset_arm
- else: # use center
- subset_arm = 5
- p_rat = np.hstack((np.array(position2d_subset.head_position_x).reshape((-1,1)),
- np.array(position2d_subset.head_position_y).reshape((-1,1))))
- subset_ind = is_rat_interior(p_rat)
- position2d_subset = position2d_subset[subset_ind]
- position1d_subset = position1d_subset[subset_ind]
- decode_subset = decode_subset.isel(time = np.argwhere(subset_ind).ravel())
- # all previous operations restrict time to consider
- posterior_position_subset = decode_subset.causal_posterior.sum(dim='state')
- # chew down decode to either mean or max position
- # get max posterior
- if max_flag:
- max_posterior_position = np.array(position_axis[posterior_position_subset.argmax(dim = 'position')])
- # get mean posterior
- else:
- posterior_position_subset_array = np.array(posterior_position_subset).T
- posterior_position_subset_array = posterior_position_subset_array/np.sum(posterior_position_subset_array, axis = 0)
- max_posterior_position = np.matmul(position_axis,posterior_position_subset_array)
- # find remote time
- is_remote = np.zeros_like(max_posterior_position) #just to initialize
- if use_home: # find remote arm representations when the animal is in the home arm
- for k in region.keys():
- (arm_base, arm_top) = region[k]
- is_remote = is_remote + np.logical_and(max_posterior_position <= arm_top, max_posterior_position >= arm_base)
- elif use_outer: # find remote representations when the animal is in outer arms
- # find representation in other arms
- for k in region.keys():
- if k == int(subset_arm):
- continue
- (arm_base, arm_top) = region[k]
- is_remote = is_remote + np.logical_and(max_posterior_position <= arm_top, max_posterior_position >= arm_base)
- # find remote representation at home
- is_remote = is_remote + np.logical_and(max_posterior_position >= 0, max_posterior_position <= linear_map[0][1])
- else: # use center
- for k in region.keys():
- (arm_base, arm_top) = region[k]
- is_remote = is_remote + np.logical_and(max_posterior_position <= arm_top, max_posterior_position >= arm_base)
- # restrict to moving time
- is_moving = np.array(position2d_subset.head_speed) > 4
- min_len = np.min([len(is_moving),len(is_remote)])
- # choose min because one variable is a subset of decode and the other is a subset of position.
- # there could be 1 or 2 time point difference.
- is_moving = is_moving[:min_len]
- is_remote = is_remote[:min_len]
- is_remote = np.logical_and(is_remote, is_moving)
- if min_sum_posterior == 0:
- # if no posterior threshold, there will be no continuity and state requirement,
- trials = [trialID]
- arm_identity = [0,1,2,3,4] # all arms including home arm
- time_intervals = []
- # for each region, count the number of time bins that the max posterior position falls into that region,
- for k in [5,6,7,8,9]:
- (arm_base, arm_top) = region[k]
- time_in_arm = np.logical_and(max_posterior_position <= arm_top, max_posterior_position >= arm_base)
- time_in_arm = time_in_arm[:min_len]
- time_in_arm = np.logical_and(time_in_arm, is_remote)
- delta_t = np.sum(time_in_arm) * np.median(np.diff(posterior_position_subset.time))
- t0 = float(posterior_position_subset.time[0])
- time_intervals.append((t0, t0 + delta_t))
- return trials, time_intervals, arm_identity
- is_remote_pd = pd.Series(is_remote, index = posterior_position_subset.time)
- is_remote_segments = np.array(segment_boolean_series(
- is_remote_pd, minimum_duration=minimum_duration))
- if len(is_remote_segments) == 0:
- return [],[],[]
- time_intervals = []
- arm_identity = []
- trials = []
- for i in range(is_remote_segments.shape[0]):
- (t0,t1) = is_remote_segments[i]
- # restrict to continuous state:
- # length of the continuous state should be greater than 20ms
- decode_subset_ = select_subset_helper(decode_subset,(t0,t1))
- state_subset = np.array(decode_subset_.causal_posterior.sum(dim='position'))
- time=np.array(decode_subset_.causal_posterior.time)
- snippets_conti = find_start_end(state_subset[:,0] > 0.5) #continuous
- snippets = [time[s] for s in snippets_conti if np.diff(time[s])[0]>minimum_duration]
- for s in range(len(snippets)):
- (t0_peak,t1_peak) = snippets[s]
- # overall sum of decode posterior in the max posterior arm should be greater than 0.2
- posterior_by_arm = position_posterior2arm_posterior(
- select_subset_helper(posterior_position_subset,snippets[s]),
- linear_map)
- # classify the max/mean posterior arm, exclude the arm the animal is physically at
- subset_ind = (posterior_position_subset.time >= t0_peak) & (posterior_position_subset.time <= t1_peak)
- subset_arm_snippet = linear2arm_including_home(max_posterior_position[subset_ind])
- if len(subset_arm_snippet) == 0:
- continue
- subset_arm_snippet = subset_arm_snippet[~np.isnan(subset_arm_snippet)]
- if len(subset_arm_snippet) == 0:
- continue
- mode, count = stats.mode(subset_arm_snippet)
- if mode == subset_arm or count <= (len(subset_arm_snippet) * 0.8):
- #ambiguous situation, we will not consider those
- continue
- max_arm_ind = int(mode - 5)
- if np.mean(posterior_by_arm[max_arm_ind,:]) < min_sum_posterior:
- continue
- time_intervals.append(snippets[s])
- arm_identity.append(max_arm_ind)
- trials.append(trialID)
- return trials, time_intervals, arm_identity
- def linear2arm(position):
- arm = np.zeros_like(position) + np.nan
- for p_ind in range(len(position)):
- p = position[p_ind]
- for k in region.keys():
- if p>=region[k][0] and p<region[k][1]:
- arm[p_ind] = k
- continue
- return arm
- def linear2arm_including_home(position):
- arm = np.zeros_like(position) + np.nan
- for p_ind in range(len(position)):
- p = position[p_ind]
- for k in region.keys():
- if p>=region[k][0] and p<region[k][1]:
- arm[p_ind] = k
- continue
- if p >= 0 and p <= linear_map[0][1]:
- arm[p_ind] = 5
- return arm
- def add_trial(t0,log_df):
- trial_ind=np.array(log_df.index)
- trial_number = trial_ind[np.argwhere((np.array(log_df.timestamp_O[:-1])-t0) > 0).ravel()[0]]
- return trial_number
- def dotproduct(head_direction, arm):
- # arms are 0,1,2,3,4.
- # get arm direction
- arm_vector = vectors[arm + 5]
- return np.dot(head_direction, arm_vector)
- #### return angle between remote content and the rat head direction
- ### code in figure4d calls the following functions
- def find_angle(max_posterior_2d,head_orientation,animal_location):
- # in radian
- # make unit vector
- head_orientation_unit = np.hstack((np.cos(head_orientation).reshape((-1,1)),np.sin(head_orientation).reshape((-1,1)))) #unit vector
- displacement_unit = max_posterior_2d - animal_location
- displacement_unit = displacement_unit / np.linalg.norm(displacement_unit, axis = 1).reshape((-1,1))
- # shape of both displacement_unit and head_orientation_unit are (number of time bin, 2)
- # finally: return radian between head orientation and remote content
- dot_product = [np.dot(head_orientation_unit[i],displacement_unit[i].T) for i in range(displacement_unit.shape[0])]
- angle = np.arccos(np.clip(dot_product, -1.0, 1.0))
- return angle, head_orientation_unit, displacement_unit
- linear_map,welllocations = get_linearization_map()
- linear_map_arms = linear_map[[0,3,5,7,9]]
- def loc1d_to_2d_vector(loc1d_vector, arm = None):
- loc2d_vector = np.array([loc1d_to_2d(loc1d, arm) for loc1d in loc1d_vector])
- return loc2d_vector
- def loc1d_to_2d(loc1d, arm_avoid = None):
- # linear_map is like this:
- # array([[ 57.63896252, 0. ], arm 0 base - outer
- # [165.66041604, 252.64353221], arm 1 base - outer
- # [331.10211383, 418.29227956], arm 2 base - outer
- # [496.49241045, 583.18763812], arm 3 base - outer
- # [657.72023142, 743.03215907]]). arm 4 base - outer
- # the arm the 1d location belongs, 1-indexed
- row_ind = np.argwhere(np.logical_and(linear_map_arms[:,0] <= loc1d, linear_map_arms[:,1] > loc1d)).ravel()
- if len(row_ind) == 0:
- return np.array([np.nan,np.nan])
- arm_id = int(row_ind)
- if arm_id == arm_avoid:
- return np.array([np.nan,np.nan])
- # the base - outer 1d
- arm = linear_map_arms[arm_id].ravel()
- if arm_id == 0:
- arm = arm[::-1]
- # convert to proportion
- proportion = (loc1d - arm[0])/(arm[1]-arm[0])
- # get 2D node location
- node = nodes[int(arm_id + 5)]
- loc2d = (node[1] - node[0]) * proportion + node[0]
- return loc2d
- def loc1d_to_baseoff_vector(loc1d_vector, arm_avoid = None):
- loc2d_vector = np.array([loc1d_to_baseoff(loc1d) for loc1d in loc1d_vector])
- return loc2d_vector
- def loc1d_to_baseoff(loc1d, arm_avoid = None):
- # linear_map is like this:
- # array([[ 0, 57.63896252], arm 0 base - outer
- # [165.66041604, 252.64353221], arm 1 base - outer
- # [331.10211383, 418.29227956], arm 2 base - outer
- # [496.49241045, 583.18763812], arm 3 base - outer
- # [657.72023142, 743.03215907]]). arm 4 base - outer
- # the arm the 1d location belongs, 1-indexed
- row_ind = np.argwhere(np.logical_and(linear_map_arms[:,0] <= loc1d, linear_map_arms[:,1] > loc1d)).ravel()
- if len(row_ind) == 0:
- return np.array([np.nan,np.nan])
- arm_id = int(row_ind)
- if arm_id == arm_avoid:
- return np.array([np.nan,np.nan])
- # the base - outer 1d
- arm = linear_map_arms[arm_id].ravel()
- d = loc1d - arm[0]
- if arm_id == 0:
- d = arm[1] - loc1d
- return arm_id, d
changeOfMind_remote_interval.py at commit 0f0c9a7, no license · at the source
Overview
- UC Berkeley – UCSF Joint Graduate Program in Bioengineering, University of California, San Francisco, 94143, USA
- Department of Physiology, University of California, San Francisco, 94143, USA
- Graduate Program in Computational Neuroscience, University of Chicago, Chicago, 60637, USA
- Department of Neurobiology & Biophysics, University of Washington, Seattle, 98195, USA
- Neuroscience Graduate Program, University of California San Francisco, San Francisco, 94143, USA
- Howard Hughes Medical Institute, University of California, San Francisco, 94143, USA
- Kavli Institute for Fundamental Neuroscience, University of California, San Francisco, 94143, USA
Abstract
Changing one’s mind — revising a past decision independently of external cues — can lead to better outcomes, but its neural basis remains poorly understood. We therefore developed a challenging spatial task for rats where a conflict between innate foraging biases and task rules leads to abundant, spontaneous, and characteristically corrective changes-of-mind (COMs). Neural recordings in the hippocampus, a brain region implicated in counterfactual thinking, revealed two distinct stages wherein more local representations gave way to representations of distant alternatives after animals had begun to reverse course. These representations predicted their eventual choice, and often serially encoded trial start and end locations. Our novel task paradigm reveals distinct representational phases engaged during self-correction and uncovers a rich repertoire of hippocampal spatial representations tied to behavior.
Reproduced under the paper's license (CC BY-NC), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 1 match between paragraphs and lines of code.
Zenodo 20371883
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
- 28 September 2026: the link answers (HTTP 200)
86 files
- src/
gucompaper/ , Python, 982 linesAnalysis_SGU.py - src/
gucompaper/ , Python, 73 linesAnalysis_nwb_helper.py - src/
gucompaper/ , Jupyter, 17 linesChangeOfMind_export.ipyn b - src/
gucompaper/ , Python, 37 linesGu2026_export.py - src/
gucompaper/ , Python, 157 linesPastFuture_Replay.py - src/
gucompaper/ , Python, 138 linesRemoteTimes.py - src/
gucompaper/ , Python, 91 linesSessionData.py - src/
gucompaper/ , Python, 294 linesVideo_player.py - src/
gucompaper/ , Python, 1 line__init__.py - src/
gucompaper/ , Python, 310 linesassembly.py - src/
gucompaper/ , Python, 461 linesbehavior.py - src/
gucompaper/ , Python, 659 lineschangeOfMind.py - src/
gucompaper/ , Python, 382 lineschangeOfMindRipple.py - src/
gucompaper/ , Python, 280 lineschangeOfMind_DeltaT.py - src/
gucompaper/ , Python, 112 lineschangeOfMind_byTransitio n.py - src/
gucompaper/ , Python, 607 lineschangeOfMind_deltat.py - src/
gucompaper/ , Python, 1 linechangeOfMind_figures/ __init__.py - src/
gucompaper/ , Python, 73 lineschangeOfMind_figures/ content_sidedness.py - src/
gucompaper/ , Python, 968 lineschangeOfMind_figures/ dynamic_home_arm.py - src/
gucompaper/ , Python, 828 lineschangeOfMind_figures/ example_snippet.py - src/
gucompaper/ , Python, 225 lineschangeOfMind_figures/ extra_correctness.py - src/
gucompaper/ , Python, 362 lineschangeOfMind_figures/ figure2_ripple.py - src/
gucompaper/ , Python, 263 lineschangeOfMind_figures/ figure2_theta.py - src/
gucompaper/ , Python, 6 lineschangeOfMind_figures/ figure2c.py - src/
gucompaper/ , Python, 247 lineschangeOfMind_figures/ figure3_thetaGLM.py - src/
gucompaper/ , Python, 248 lineschangeOfMind_figures/ figure3d.py - src/
gucompaper/ , Python, 258 lineschangeOfMind_figures/ figure4.py - src/
gucompaper/ , Python, 90 lineschangeOfMind_figures/ figure4_counting.py - src/
gucompaper/ , Python, 733 lineschangeOfMind_figures/ figure4c.py - src/
gucompaper/ , Python, 1,162 lineschangeOfMind_figures/ figure4d.py - src/
gucompaper/ , Python, 106 lineschangeOfMind_figures/ figure_prepost_supp.py - src/
gucompaper/ , Python, 53 lineschangeOfMind_figures/ notebook7b.py - src/
gucompaper/ , Python, 53 lineschangeOfMind_figures/ notebook7c.py - src/
gucompaper/ , Python, 57 lineschangeOfMind_figures/ supp3_correctness.py - src/
gucompaper/ , Python, 312 lineschangeOfMind_figures/ supp_behavior_speed.py - src/
gucompaper/ , Python, 110 lineschangeOfMind_figures/ supp_decode.py - src/
gucompaper/ , Python, 182 lineschangeOfMind_figures/ supp_decode_concentratio n.py - src/
gucompaper/ , Python, 126 lineschangeOfMind_figures/ supp_decode_t0t1.py - src/
gucompaper/ , Python, 109 lineschangeOfMind_figures/ supp_remote_length.py - src/
gucompaper/ , Python, 225 lineschangeOfMind_figures/ supp_thetacycle_concentr ation.py - src/
gucompaper/ , Python, 322 lineschangeOfMind_figures/ traveling_direction.py - src/
gucompaper/ , Python, 88 lineschangeOfMind_helper.py - src/
gucompaper/ , Python, 75 lineschangeOfMind_proportion. py - src/
gucompaper/ , Python, 569 lineschangeOfMind_remote.py - src/
gucompaper/ , Python, 675 lineschangeOfMind_remote_inte rval.py - src/
gucompaper/ , Python, 226 lineschangeOfMind_remote_loca tion.py - src/
gucompaper/ , Python, 396 lineschangeOfMind_statespace. py - src/
gucompaper/ , Python, 1,385 lineschangeOfMind_triggered.p y - src/
gucompaper/ , Python, 550 lineschangeOfMind_triggered_p osition.py - src/
gucompaper/ , Python, 204 linescircularLinearFit.py - src/
gucompaper/ , Python, 359 linescuration_burst.py - src/
gucompaper/ , Python, 594 linescuration_manual.py - src/
gucompaper/ , Python, 1 linedata_sharing.py - src/
gucompaper/ , Python, 378 linesdecodeHelpers.py - src/
gucompaper/ , Python, 50 linesdecodeQuality.py - src/
gucompaper/ , Python, 90 linesephysProcessingHelpers.p y - src/
gucompaper/ , Python, 299 linesfragmented.py - src/
gucompaper/ , Python, 119 linesfragmented_content.py - src/
gucompaper/ , Python, 233 linesfragmented_general.py - src/
gucompaper/ , Python, 361 linesfragmented_graph.py - src/
gucompaper/ , Python, 35 linesfragmented_place_sum.py - src/
gucompaper/ , Python, 694 linesgyroscope.py - src/
gucompaper/ , Python, 191 lineshelpers.py - src/
gucompaper/ , Python, 148 lineslikelihoodDecode_helper. py - src/
gucompaper/ , Python, 384 linesload.py - src/
gucompaper/ , Python, 114 linesmua_detection.py - src/
gucompaper/ , Python, 665 linespairwiseDecode.py - src/
gucompaper/ , Python, 419 linesparallel_decode_video.py - src/
gucompaper/ , Python, 580 linesparallel_video_writer.py - src/
gucompaper/ , Python, 332 linesparallel_video_writer_ex amples.py - src/
gucompaper/ , Python, 199 linesplacefield.py - src/
gucompaper/ , Python, 72 linesplacefield_simple.py - src/
gucompaper/ , Python, 110 linespredecessorRepresentatio n.py - src/
gucompaper/ , Python, 944 linesripple_add_replay.py - src/
gucompaper/ , Python, 1,214 linesripple_detection.py - src/
gucompaper/ , Python, 480 linessingleUnit.py - src/
gucompaper/ , Python, 297 linessingleUnit_classificatio n.py - src/
gucompaper/ , Python, 186 linessingleUnit_sortedDecode. py - src/
gucompaper/ , Python, 245 linessingleUnit_thetaPhase.py - src/
gucompaper/ , Python, 389 linessingletonDecode.py - src/
gucompaper/ , Python, 244 linesspectrum.py - src/
gucompaper/ , Python, 598 linestheta.py - src/
gucompaper/ , Python, 57 linestheta_mua.py - src/
gucompaper/ , Python, 287 linestheta_singleUnit.py - src/
gucompaper/ , Python, 95 linesvideo.py - README.md, Text, 37 lines
shijiegu/gu2026
0f0c9a7dadba3b5c9cbf2e8f3ac3372cff9726ee, 24 May 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
86 files
- src/
gucompaper/ , Python, 982 linesAnalysis_SGU.py - src/
gucompaper/ , Python, 73 linesAnalysis_nwb_helper.py - src/
gucompaper/ , Jupyter, 17 linesChangeOfMind_export.ipyn b - src/
gucompaper/ , Python, 37 linesGu2026_export.py - src/
gucompaper/ , Python, 157 linesPastFuture_Replay.py - src/
gucompaper/ , Python, 138 linesRemoteTimes.py - src/
gucompaper/ , Python, 91 linesSessionData.py - src/
gucompaper/ , Python, 294 linesVideo_player.py - src/
gucompaper/ , Python, 1 line__init__.py - src/
gucompaper/ , Python, 310 linesassembly.py - src/
gucompaper/ , Python, 461 linesbehavior.py - src/
gucompaper/ , Python, 659 lineschangeOfMind.py - src/
gucompaper/ , Python, 382 lineschangeOfMindRipple.py - src/
gucompaper/ , Python, 607 lineschangeOfMind_DeltaT.py - src/
gucompaper/ , Python, 112 lineschangeOfMind_byTransitio n.py - src/
gucompaper/ , Python, 607 lineschangeOfMind_deltat.py - src/
gucompaper/ , Python, 1 linechangeOfMind_figures/ __init__.py - src/
gucompaper/ , Python, 73 lineschangeOfMind_figures/ content_sidedness.py - src/
gucompaper/ , Python, 968 lineschangeOfMind_figures/ dynamic_home_arm.py - src/
gucompaper/ , Python, 828 lineschangeOfMind_figures/ example_snippet.py - src/
gucompaper/ , Python, 225 lineschangeOfMind_figures/ extra_correctness.py - src/
gucompaper/ , Python, 362 lineschangeOfMind_figures/ figure2_ripple.py - src/
gucompaper/ , Python, 263 lineschangeOfMind_figures/ figure2_theta.py - src/
gucompaper/ , Python, 6 lineschangeOfMind_figures/ figure2c.py - src/
gucompaper/ , Python, 247 lineschangeOfMind_figures/ figure3_thetaGLM.py - src/
gucompaper/ , Python, 248 lineschangeOfMind_figures/ figure3d.py - src/
gucompaper/ , Python, 258 lineschangeOfMind_figures/ figure4.py - src/
gucompaper/ , Python, 90 lineschangeOfMind_figures/ figure4_counting.py - src/
gucompaper/ , Python, 733 lineschangeOfMind_figures/ figure4c.py - src/
gucompaper/ , Python, 1,162 lineschangeOfMind_figures/ figure4d.py - src/
gucompaper/ , Python, 106 lineschangeOfMind_figures/ figure_prepost_supp.py - src/
gucompaper/ , Python, 53 lineschangeOfMind_figures/ notebook7b.py - src/
gucompaper/ , Python, 53 lineschangeOfMind_figures/ notebook7c.py - src/
gucompaper/ , Python, 57 lineschangeOfMind_figures/ supp3_correctness.py - src/
gucompaper/ , Python, 312 lineschangeOfMind_figures/ supp_behavior_speed.py - src/
gucompaper/ , Python, 110 lineschangeOfMind_figures/ supp_decode.py - src/
gucompaper/ , Python, 182 lineschangeOfMind_figures/ supp_decode_concentratio n.py - src/
gucompaper/ , Python, 126 lineschangeOfMind_figures/ supp_decode_t0t1.py - src/
gucompaper/ , Python, 109 lineschangeOfMind_figures/ supp_remote_length.py - src/
gucompaper/ , Python, 225 lineschangeOfMind_figures/ supp_thetacycle_concentr ation.py - src/
gucompaper/ , Python, 322 lineschangeOfMind_figures/ traveling_direction.py - src/
gucompaper/ , Python, 88 lineschangeOfMind_helper.py - src/
gucompaper/ , Python, 75 lineschangeOfMind_proportion. py - src/
gucompaper/ , Python, 569 lineschangeOfMind_remote.py - src/
gucompaper/ , Python, 675 lines, 1 matchchangeOfMind_remote_inte rval.py - src/
gucompaper/ , Python, 226 lineschangeOfMind_remote_loca tion.py - src/
gucompaper/ , Python, 396 lineschangeOfMind_statespace. py - src/
gucompaper/ , Python, 1,385 lineschangeOfMind_triggered.p y - src/
gucompaper/ , Python, 550 lineschangeOfMind_triggered_p osition.py - src/
gucompaper/ , Python, 204 linescircularLinearFit.py - src/
gucompaper/ , Python, 359 linescuration_burst.py - src/
gucompaper/ , Python, 594 linescuration_manual.py - src/
gucompaper/ , Python, 1 linedata_sharing.py - src/
gucompaper/ , Python, 378 linesdecodeHelpers.py - src/
gucompaper/ , Python, 50 linesdecodeQuality.py - src/
gucompaper/ , Python, 90 linesephysProcessingHelpers.p y - src/
gucompaper/ , Python, 299 linesfragmented.py - src/
gucompaper/ , Python, 119 linesfragmented_content.py - src/
gucompaper/ , Python, 233 linesfragmented_general.py - src/
gucompaper/ , Python, 361 linesfragmented_graph.py - src/
gucompaper/ , Python, 35 linesfragmented_place_sum.py - src/
gucompaper/ , Python, 694 linesgyroscope.py - src/
gucompaper/ , Python, 191 lineshelpers.py - src/
gucompaper/ , Python, 148 lineslikelihoodDecode_helper. py - src/
gucompaper/ , Python, 384 linesload.py - src/
gucompaper/ , Python, 114 linesmua_detection.py - src/
gucompaper/ , Python, 665 linespairwiseDecode.py - src/
gucompaper/ , Python, 419 linesparallel_decode_video.py - src/
gucompaper/ , Python, 580 linesparallel_video_writer.py - src/
gucompaper/ , Python, 332 linesparallel_video_writer_ex amples.py - src/
gucompaper/ , Python, 199 linesplacefield.py - src/
gucompaper/ , Python, 72 linesplacefield_simple.py - src/
gucompaper/ , Python, 110 linespredecessorRepresentatio n.py - src/
gucompaper/ , Python, 944 linesripple_add_replay.py - src/
gucompaper/ , Python, 1,214 linesripple_detection.py - src/
gucompaper/ , Python, 480 linessingleUnit.py - src/
gucompaper/ , Python, 297 linessingleUnit_classificatio n.py - src/
gucompaper/ , Python, 186 linessingleUnit_sortedDecode. py - src/
gucompaper/ , Python, 245 linessingleUnit_thetaPhase.py - src/
gucompaper/ , Python, 389 linessingletonDecode.py - src/
gucompaper/ , Python, 244 linesspectrum.py - src/
gucompaper/ , Python, 598 linestheta.py - src/
gucompaper/ , Python, 57 linestheta_mua.py - src/
gucompaper/ , Python, 287 linestheta_singleUnit.py - src/
gucompaper/ , Python, 95 linesvideo.py - README.md, Text, 39 lines
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;
- 170 scripts, each with its path and the digest of its content;
- 1 match 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
- dandi:001836, at DANDI; found in “Supplementary Material”
- github.com/
shijiegu/ , at github.com; found in the end of the papergu2026_docker
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, 28 September 2026: the first record
Recorded: type, language, journal, pages, dates, 8 authors, 4 funders, 30 references.
Cite
This paper
Gu, S., Liu, C., Gillespie, A. K., Nevers, R., Denovellis, E. L., Coulter, M. E., Kay, K., & Frank, L. M. (2026). Naturalistic behavior and self-generated neural activity predictive of self-correction. bioRxiv : the preprint server for biology, 2026.05.26.727951.
BibTeX
@article{gu2026naturalis
author = {Gu, Shijie and Liu, Chenyan and Gillespie, Anna K. and Nevers, Rhino and Denovellis, Eric L. and Coulter, Michael E. and Kay, Kenneth and Frank, Loren M.},
title = {{Naturalistic behavior and self-generated neural activity predictive of self-correction}},
journal = {bioRxiv : the preprint server for biology},
year = {2026},
month = may,
pages = {2026.05.26.727951},
publisher = {bioRxiv},
issn = {2692-8205},
pmcid = {PMC13232212}
}
RIS
TY - JOUR
AU - Gu, Shijie
AU - Liu, Chenyan
AU - Gillespie, Anna K.
AU - Nevers, Rhino
AU - Denovellis, Eric L.
AU - Coulter, Michael E.
AU - Kay, Kenneth
AU - Frank, Loren M.
TI - Naturalistic behavior and self-generated neural activity predictive of self-correction
T2 - bioRxiv : the preprint server for biology
J2 - bioRxiv
PY - 2026
DA - 2026/
SP - 2026.05.26.727951
SN - 2692-8205
PB - bioRxiv
LA - en
ER -
CSL-JSON
{
"id": "pmcid:PMC13232212",
"type": "article-journal",
"title": "Naturalistic behavior and self-generated neural activity predictive of self-correction",
"container-title": "bioRxiv : the preprint server for biology",
"author": [
{
"family": "Gu",
"given": "Shijie"
},
{
"family": "Liu",
"given": "Chenyan"
},
{
"family": "Gillespie",
"given": "Anna K."
},
{
"family": "Nevers",
"given": "Rhino"
},
{
"family": "Denovellis",
"given": "Eric L."
},
{
"family": "Coulter",
"given": "Michael E."
},
{
"family": "Kay",
"given": "Kenneth"
},
{
"family": "Frank",
"given": "Loren M."
}
],
"container-title-short":
"page": "2026.05.26.727951",
"PMCID": "PMC13232212",
"ISSN": "2692-8205",
"publisher": "bioRxiv",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
27
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41593-026-02232-0 [code]
- Entorhinal cortex represents task-relevant remote locations independently of CA1.Journal: Nature neuroscienceIn common: SpikeInterface, Neurodata Without Borders (PyNWB, MatNWB), xarray, 11 other tools, 2 references
- [2] doi:10.1002/hipo.70131 [code]
- Decoding Medial Entorhinal Cortical Dynamics Produces Planning-Like Alternations in Hippocampal theta Sequences.Journal: HippocampusIn common: JAX, xarray, OpenCV, 5 other tools, 6 references
- [3] doi:10.1016/j.isci.2026.115488 [code]
- An integrated &
lt;i& gt;i& lt;/ i& gt; & lt;i& gt;n vitro& lt;/ i& gt; platform and biophysical modeling approach for studying synaptic transmission in isolated neuronal pairs. Journal: iScienceIn common: Elephant, Neo, SpikeInterface, 10 other tools - [4] doi:10.7554/elife.110588 [code]
- Opening the black box toward a modular approach to spike sorting.Journal: eLifeIn common: Neo, SpikeInterface, Neurodata Without Borders (PyNWB, MatNWB), 9 other tools
- [5] doi:10.1016/j.celrep.2026.117420 [code]
- Neural population dynamics of direct electrical stimulation of neocortex.Journal: Cell reportsIn common: Neurodata Without Borders (PyNWB, MatNWB), JAX, NetworkX, 10 other tools
- [6] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: CuPy, JAX, NetworkX, 10 other tools
- [7] doi:10.1126/sciadv.aeg6797 [code]
- Dorsoventral gradient of theta sweeps in the medial entorhinal cortex.Journal: Science advancesIn common: JAX, NetworkX, statsmodels, 6 other tools, 3 references
- [8] doi:10.1016/j.isci.2026.116825 [code]
- Social hierarchy shapes behavioral and transcriptional responses to chronic stress and ketamine in male mice.Journal: iScienceIn common: CuPy, NetworkX, OpenCV, 9 other tools
- [9] doi:10.1371/journal.pcbi.1014752 [code]
- Hierarchical feature binding in a spiking neural network model of the primate ventral visual pathway.Journal: PLoS computational biologyIn common: Elephant, Neo, xarray, 6 other tools
- [10] doi:10.1038/s41593-026-02365-2 [code]
- Hippocampal theta sweeps indicate goal direction during navigation.Journal: Nature neuroscienceIn common: JAX, SciPy, Matplotlib, 1 other tool, 6 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, 170 scripts, and 1 match 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:4c434f17d68e65ce…
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.
