Centralized brain networks controlling antennal grooming coordination.
The 40 matches · 4 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
- [1] § Methods › Connectome analysis › Assigning neurons to groups ↔ src/prepare_data/Figure4_graph_tools.py, lines 253–315 · score 0.90 · MNfl, MNnm, T1 leg motor, neck premotor neurons, leg premotor neurons, leg motor neuron
- [2] § Results › A computational perturbation screen identifies key neurons for grooming ↔ src/Figure6.ipynb, lines 394–515 · score 0.83 · Global activity, bilateral neural silencing, unilateral neural activation, Neural perturbations, asymmetric JO, aMN4
- [3] § Methods › Data analysis › Analysis of perturbation experiments ↔ src/prepare_data/Figure3_prepare_data.py, lines 498–583 · score 0.80 · freely moving body, kinematic variable, head rotation, head fixed, body parts, head roll
- [4] § Methods › Connectome analysis › Constructing the antennal grooming network ↔ src/prepare_data/Figure4_generate_grooming_network.py, lines 340–402 · score 0.79 · super_class, FAFB connectome, foundational network, sensory neurons, brain, threshold
- [5] § Methods › Data analysis › Analysis of perturbation experiments ↔ src/prepare_data/Figure3_prepare_data.py, lines 352–436 · score 0.75 · freely moving body, pitched antenna, head fixed, amputee, body part, head roll
- [6] § Methods › Data processing › 2D & 3D pose estimation ↔ charuco_board/design/checkboard_config.py, the whole file · a weak match · score 0.72 · ChArUco board, OpenCV, bit, squares, dictionary
- [7] § Methods › Data processing › 2D & 3D pose estimation ↔ charuco_board/check_charuco.py, the whole file · a weak match · score 0.69 · ChArUco board, OpenCV, reconstruction, Anipose, calibrated
- [8] § Results › A computational perturbation screen identifies key neurons for grooming ↔ src/Figure6.ipynb, lines 394–515 · score 0.69 · neural silencing, neural activation, asymmetric JO, aMN4, clusters, activity
- [9] § Results › Proprioception does not play a major role in body-part coordination ↔ src/prepare_data/Figure3_prepare_data.py, lines 846–954 · score 0.69 · freely moving body, kinematic variable, head rotations, body part, head fixed, head roll
- [10] § Methods › Connectome analysis › Constructing the antennal grooming network ↔ src/common.py, lines 710–730 · score 0.67 · degree_centrality, eigenvector_centrality, NetworkX, scores
- [11] § Methods › Connectome analysis › Assigning neurons to groups ↔ src/prepare_data/Figure4_graph_tools.py, lines 253–315 · score 0.66 · neck premotor neurons, leg motor neurons, shared premotor neurons, neck motor neurons, VNC, foreleg
- [12] § Results › Body-part coordination enhances sustained foreleg-antennal contact ↔ src/EDFigure4.ipynb, lines 129–186 · score 0.66 · reduced collisions, left tarsus, right tibia, kinematic replay, head pitch, simulation
- [13] § Methods › Connectome analysis › Assigning neurons to groups ↔ src/Figure4.ipynb, lines 564–597 · score 0.65 · postsynaptic neurons, presynaptic neurons, leg premotor, modules, sensory, JO
- [14] § Methods › Kinematic replay and antennal contact detection ↔ src/EDFigure4.ipynb, lines 266–318 · score 0.65 · zero forces, contact force, collision pair, segments, tarsus, antennae
- [15] § Results › Simulating a connectome-derived antennal grooming network ↔ src/EDFigure13.ipynb, lines 50–85 · score 0.65 · unilateral selectivity, right neuron, left neuron, Neural responses, aDNs, aBNs
- [16] § Results › A centralized brain network links multiple motor modules ↔ src/EDFigure7.ipynb, lines 45–119 · score 0.64 · parameter sweep, monosynaptically connected, neck motor neurons, grooming neurons, descending, interneurons
- [17] § Results › Antennal grooming arises from tripartite coordination ↔ src/Figure1.ipynb, lines 424–503 · score 0.63 · uniR, grooming subtype, bilateral, Unilateral, positioned, behaviors
- [18] § Methods › Kinematic replay and antennal contact detection ↔ src/Figure2.ipynb, lines 57–177 · score 0.63 · collision diagrams, collision pair, leg segment, contact, replay, tarsus
- [19] § Methods › Connectome analysis › Graph visualizations ↔ src/prepare_data/Figure4_graph_tools.py, lines 38–71 · score 0.63 · source node, target node, NetworkX, graph, edge
- [20] § Results › Antennal grooming arises from tripartite coordination ↔ src/Figure1.ipynb, lines 424–503 · score 0.63 · uniR, subtypes, bilateral, unilateral, behavioral, grooming
- [21] § Results › A centralized brain network links multiple motor modules ↔ src/prepare_data/Figure4_graph_tools.py, lines 341–393 · score 0.62 · shared premotor neurons, antennal motor neurons, motor modules, synapses, neck, network
- [22] § Methods › Data processing › 3D pose alignment & inverse kinematics ↔ kinematics3d/constants.py, the whole file · a weak match · score 0.61 · Thorax Coxa, Tibia Tarsus, Claw, wing, tip
- [23] § Results › A centralized brain network links multiple motor modules ↔ src/prepare_data/Figure4_generate_grooming_network.py, lines 340–402 · score 0.61 · parameter sweep, brain connectome, sensory neurons, motor neurons, threshold, network
- [24] § Methods › Statistical analysis ↔ src/Figure7.ipynb, lines 73–128 · score 0.60 · Mann Whitney, stimulus transition, windows, median, fly
- [25] § Methods › Connectome-constrained neural network modeling › Adjacency matrix preparation ↔ src/prepare_data/Figure5_prepare_data.py, lines 34–47 · score 0.60 · distance matrix, cluster neurons, DBSCAN, algorithm
- [26] § Methods › Connectome-constrained neural network modeling › Model parameters and training ↔ src/prepare_data/connectome_utils.py, lines 389–410 · score 0.59 · pre synaptic, synaptic connection, post synaptic, neurotransmitter, neurons
- [27] § Methods › Data analysis › Dimensionality reduction using PCA ↔ src/EDFigure2.ipynb, lines 105–175 · score 0.59 · coxa trochanter, Tibia Tarsus joints, overlap, optogenetically, positions, foreleg
- [28] § Results › Simulating a connectome-derived antennal grooming network ↔ src/Figure5.ipynb, lines 185–219 · score 0.58 · unilateral selectivity, right neuron, left neuron, aDNs, aBNs, USI
- [29] § Results › Coupled circuit motifs enable robust unilateral coordination ↔ src/Figure6.ipynb, lines 779–908 · score 0.58 · neck premotor, leg premotor, shared premotor, DN33, clusters, motifs
- [30] § Methods › Data processing › 3D pose alignment & inverse kinematics ↔ src/EDFigure2.ipynb, lines 105–175 · score 0.57 · coxa trochanter, femur tibia, joint, positioning, leg, pose
- [31] § Results › Body-part coordination enhances sustained foreleg-antennal contact ↔ src/Figure2.ipynb, lines 225–365 · score 0.56 · Simes Hochberg, Contact duration, head pitch, boxes, segments, tarsus
- [32] § Methods › Data analysis › Transitions between behaviors ↔ src/prepare_data/Figure4_graph_tools.py, lines 495–608 · score 0.55 · directed graph, NetworkX, transition, edges, row, node
- [33] § Methods › Connectome analysis › Assigning neurons to groups ↔ src/prepare_data/Figure4_graph_tools.py, lines 396–442 · score 0.54 · identify central neurons, NetworkX, motor neurons, layers, synapses, premotor
- [34] § Methods › Connectome analysis › Graph visualizations ↔ src/Figure4.ipynb, lines 98–179 · score 0.54 · pre synaptic neuron, post synaptic neuron, node, exported, widths, connectivity
- [35] § Methods › Data analysis › Transitions between behaviors ↔ src/EDFigure9.ipynb, lines 52–167 · score 0.54 · directed graph, NetworkX, transition, edges, row, node
- [36] § Results › Coupled circuit motifs enable robust unilateral coordination ↔ src/Figure7.ipynb, lines 73–128 · score 0.53 · Mann Whitney, stimulus transition, windows, intervals, medians, Figure 7
- [37] § Methods › Kinematic replay and antennal contact detection ↔ src/Figure2.ipynb, lines 57–177 · score 0.53 · kinematic replay, collision pair, simulations, contact, antennal
- [38] § Methods › Data processing › 2D & 3D pose estimation ↔ dlc_fxns/06_extract_outlier_refine.py, the whole file · a weak match · score 0.53 · outlier frames, DeepLabCut, amputation, pose
- [39] § Methods › Kinematic replay and antennal contact detection ↔ src/common.py, lines 343–407 · score 0.52 · kinematic replay, collision pair, 0–1, simulations, contact, antennal
- [40] § Results › Simulating a connectome-derived antennal grooming network ↔ src/prepare_data/EDFigure9_random_graphs.py, lines 1–46 · score 0.52 · random seeds, adjacency matrix, edges, pre, post, neck
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 · 737 lines · 26 KB · Apache-2.0 · 6 matches
- """ Graph tools. """
- import copy
- import itertools
- import numpy as np
- import pandas as pd
- import networkx as nx
- import matplotlib.pyplot as plt
- import neuprint
- from neuprint import Client
- import Figure4_neurons as neurons
- MY_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InBnaXplbW96ZGlsQGdtYWlsLmNvbSIsImxldmVsIjoibm9hdXRoIiwiaW1hZ2UtdXJsIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUNnOG9jTENyNEoyQWozazFqTjFGTzQtcmpIVnhZU2xGV3Y5NHptSUtndDVicVRuPXM5Ni1jP3N6PTUwP3N6PTUwIiwiZXhwIjoxODkyMTQ5OTA0fQ.1jPbQ350OHMCitI6zQy5SQIBtc6A2hdY5ErwYwqpn-A'
- def signal_flow(A):
- """
- Implementation of the signal flow metric from Varshney et al 2011
- Source: A Connectome of an insect brain, Winding, Pedigo et al 2023
- """
- A = A.copy()
- # A = remove_loops(A)
- W = (A + A.T) / 2
- D = np.diag(np.sum(W, axis=1))
- L = D - W
- b = np.sum(W * np.sign(A - A.T), axis=1)
- L_pinv = np.linalg.pinv(L)
- z = L_pinv @ b
- return z
- def get_all_shortest_paths(
- graph, source_nodes, target_nodes, edge_property="syn_count_inv"
- ):
- """Get all simple paths between source and target nodes"""
- all_paths = []
- for source_n, target_n in itertools.product(source_nodes, target_nodes):
- if not source_n in graph.nodes or not target_n in graph.nodes:
- continue
- if nx.has_path(graph, source_n, target_n) and source_n != target_n:
- # If there is a direct edge, remove it and find the shortest path
- edge_list = []
- while graph.has_edge(source_n, target_n):
- edge_data = graph.get_edge_data(
- source_n, target_n
- ) # Store the edge data if needed
- edge_list.append((source_n, target_n, edge_data))
- graph.remove_edge(source_n, target_n)
- try:
- path = nx.shortest_path(
- graph, source=source_n, target=target_n, weight=edge_property
- )
- except nx.NetworkXNoPath:
- path = []
- # Add the edge back to the graph
- for edge in edge_list:
- source_n, target_n, edge_data = edge
- graph.add_edge(source_n, target_n, **edge_data)
- all_paths.append(path)
- return all_paths
- def get_all_simple_paths(graph, source_nodes, target_nodes, cutoff=4):
- """Get all simple paths between source and target nodes"""
- all_paths = []
- for source_n, target_n in itertools.product(source_nodes, target_nodes):
- if not source_n in graph.nodes or not target_n in graph.nodes:
- continue
- if nx.has_path(graph, source_n, target_n):
- all_paths.extend(
- [
- p
- for p in nx.all_simple_paths(
- graph, source_n, target_n, cutoff=cutoff
- )
- ]
- )
- return all_paths
- def threshold_prune_paths(
- graph,
- paths,
- threshold=0.05,
- edge_property="syn_count_perc",
- exclude_nodes=None,
- ):
- """Thresholds the paths based on the threshold value"""
- thresholded_paths = [
- p
- for p in paths
- if (len(p) > 1)
- and (
- nx.path_weight(graph, path=list(p), weight=edge_property) / (len(p) - 1)
- >= threshold
- )
- ]
- # we prune the paths that include specific nodes
- if exclude_nodes is None:
- return thresholded_paths
- return [p for p in thresholded_paths if not set(p).intersection(set(exclude_nodes))]
- def get_adj_matrix_from_conn(
- connectivity_df,
- neuron_groups,
- ):
- """Get the adjacency matrix from the connectivity dataframe between neuronal groups."""
- adjacency_matrix_perc = np.zeros((len(neuron_groups), len(neuron_groups)))
- adjacency_matrix_syn = np.zeros((len(neuron_groups), len(neuron_groups)))
- for i, (name_pre, nodes_pre) in enumerate(neuron_groups.items()):
- for j, (name_post, nodes_post) in enumerate(neuron_groups.items()):
- number_of_synapses_total = (
- connectivity_df[connectivity_df.pre_root_id.isin(nodes_pre)]
- .syn_count.abs()
- .sum()
- )
- number_of_synapses = (
- connectivity_df[
- (connectivity_df.pre_root_id.isin(nodes_pre))
- & (connectivity_df.post_root_id.isin(nodes_post))
- ]
- .syn_count.abs()
- .sum()
- )
- w_perc = (number_of_synapses / (number_of_synapses_total + 1e-5)) * 100
- adjacency_matrix_perc[i, j] = w_perc
- adjacency_matrix_syn[i, j] = number_of_synapses / (
- len(nodes_pre) * len(nodes_post)
- )
- return {
- "perc": adjacency_matrix_perc,
- "syn": adjacency_matrix_syn,
- }
- def get_upstream(connectivity_df, neuron_ids):
- """Gets the upstream partners of a list of neurons"""
- neuron_ids = list(neuron_ids) if not isinstance(neuron_ids, list) else neuron_ids
- return connectivity_df[
- connectivity_df.post_root_id.isin(neuron_ids)
- ].pre_root_id.unique()
- def threshold_connection(
- connectivity_df,
- pre_root_ids,
- post_root_ids,
- threshold_col_name="syn_count_perc",
- threshold=0.05,
- # verbose=False,
- ):
- """Thresholds the connections based on the threshold value"""
- pre_root_ids = (
- list(pre_root_ids) if not isinstance(pre_root_ids, list) else pre_root_ids
- )
- post_root_ids = (
- list(post_root_ids) if not isinstance(post_root_ids, list) else post_root_ids
- )
- thresholded_neurons = {}
- # for each pre root id, look at the synapse percentage
- for pre_id in pre_root_ids:
- sum_perc = connectivity_df[
- (connectivity_df.pre_root_id == pre_id)
- & (connectivity_df.post_root_id.isin(post_root_ids))
- ][threshold_col_name].sum()
- # if sum percentage is more than the threshold of the total synapses onto motor neurons
- if sum_perc >= threshold:
- thresholded_neurons[pre_id] = sum_perc
- # if verbose:
- # print(pre_id, neurons.ALL_NEURONS_REV_JO[pre_id]["name"], sum_perc)
- return thresholded_neurons
- def shuffle_postsyn_conn(adj_matrix, random_seed=0):
- """Shuffle the postsynaptic connection.
- This will ensure that a neuron will have
- the same number of synapses.
- """
- np.random.seed(random_seed)
- shuffled_adj = np.zeros_like(adj_matrix)
- for row in range(adj_matrix.shape[0]):
- shuffled_adj[row, :] = np.random.choice(
- adj_matrix[row, :], size=adj_matrix.shape[1], replace=False
- )
- return shuffled_adj
- def make_a_random_graph(
- original_connectivity,
- motor_neuron_ids,
- seed=1,
- ):
- """Randomize the connections in a graph."""
- np.random.seed(seed)
- all_segment_ids = set(original_connectivity.pre_root_id.tolist()).union(
- set(original_connectivity.post_root_id.tolist())
- )
- all_segment_ids_wo_mns = all_segment_ids.difference(set(motor_neuron_ids))
- random_conn = copy.deepcopy(original_connectivity)
- random_conn["pre_root_id"] = np.random.choice(
- list(all_segment_ids_wo_mns), len(random_conn)
- )
- random_conn["post_root_id"] = np.random.choice(
- list(all_segment_ids), len(random_conn)
- )
- random_conn["syn_count"] = np.random.permutation(random_conn["syn_count"].values)
- random_conn["total_synapses"] = random_conn.groupby("pre_root_id")[
- "syn_count"
- ].transform("sum")
- # Normalize syn_count by dividing it with total_synapses
- random_conn["syn_count_perc"] = (
- random_conn["syn_count"] / random_conn["total_synapses"]
- )
- random_conn["syn_count_inv"] = 1 / random_conn["syn_count"].values
- return random_conn
- def get_premotor_neurons(connectivity_df, motor_neuron_ids, threshold=0.05):
- """Get the premotor neurons in the brain dataset, defined by a connectivity threshold."""
- mn_upstream = get_upstream(connectivity_df, motor_neuron_ids)
- mn_ups_percentage = threshold_connection(
- connectivity_df,
- mn_upstream,
- motor_neuron_ids,
- threshold=0.05,
- )
- return mn_ups_percentage
- def get_prem_neurons_vnc():
- """Get the premotor neurons in the VNC, returns three dataframes: connectivity of neck, foreleg, and shared premotor neurons with their respective motor neurons."""
- c = Client("neuprint.janelia.org", dataset="manc:v1.2.1", token=MY_TOKEN)
- c.fetch_version()
- # Get the leg motor neurons
- neuron_df_npt1_left, _ = neuprint.fetch_neurons(
- neuprint.NeuronCriteria(outputRois=["LegNp(T1)(L)"])
- )
- neuron_df_npt1_right, _ = neuprint.fetch_neurons(
- neuprint.NeuronCriteria(outputRois=["LegNp(T1)(R)"])
- )
- # Concat the two dfs
- neuron_df_npt1 = pd.concat(
- [neuron_df_npt1_left, neuron_df_npt1_right], axis=0
- ).dropna(subset=["instance", "type"])
- # Search for the motor neurons
- t1_leg_mn_df = neuron_df_npt1[neuron_df_npt1.instance.str.contains("MNfl")]
- # Find the leg premotor neurons
- # Example: Fetch all upstream connections TO a set of neurons
- leg_mns = t1_leg_mn_df.bodyId.values
- leg_prem_df, leg_prem_conn_df = neuprint.fetch_adjacencies(
- sources=None, targets=leg_mns, min_total_weight=10
- )
- # drop if the bodyId_pre is in the leg motor neurons
- leg_prem_conn_df = leg_prem_conn_df[~leg_prem_conn_df.bodyId_pre.isin(leg_mns)]
- leg_prem_conn_clean_df = (
- leg_prem_conn_df.groupby(["bodyId_pre", "bodyId_post"]).sum().reset_index()
- )
- # Get the neck motor neurons
- neuron_df, _ = neuprint.fetch_neurons(neuprint.NeuronCriteria())
- neuron_df = neuron_df.dropna(subset=["instance", "type"])
- # search for the neck motor neurons
- neck_mn_df = neuron_df[neuron_df.instance.str.contains("MNnm")]
- # Get the neck premotor neurons
- neck_mns = neck_mn_df.bodyId.values
- neck_prem_df, neck_prem_conn_df = neuprint.fetch_adjacencies(
- sources=None, targets=neck_mns, min_total_weight=10
- )
- neck_prem_conn_df = neck_prem_conn_df[~neck_prem_conn_df.bodyId_pre.isin(neck_mns)]
- neck_prem_conn_clean_df = (
- neck_prem_conn_df.groupby(["bodyId_pre", "bodyId_post"]).sum().reset_index()
- )
- neck_prem_neurons = neck_prem_conn_clean_df.bodyId_pre.unique()
- neck_prem_df = neuron_df[neuron_df.bodyId.isin(neck_prem_neurons)]
- leg_prem_neurons = leg_prem_conn_clean_df.bodyId_pre.unique()
- leg_prem_df = neuron_df[neuron_df.bodyId.isin(leg_prem_neurons)]
- both_prem_neurons = np.intersect1d(leg_prem_neurons, neck_prem_neurons)
- common_prem_df = neuron_df[neuron_df.bodyId.isin(both_prem_neurons)]
- print(
- f"Neurons ({len(both_prem_neurons)}) projecting onto leg and neck motor neurons in the VNC are: {both_prem_neurons}"
- )
- return neck_prem_df, leg_prem_df, common_prem_df
- def update_motor_modules(
- motor_module_neurons, anten_prem_set, neck_prem_set, leg_prem_set
- ):
- # Shared prem neurons: those at the intersection of at least two premotor neuron types
- neck_anten_leg_prem = neck_prem_set & anten_prem_set & leg_prem_set
- neck_anten_prem = neck_prem_set & anten_prem_set - neck_anten_leg_prem
- neck_leg_prem = neck_prem_set & leg_prem_set - neck_anten_leg_prem
- anten_leg_prem = anten_prem_set & leg_prem_set - neck_anten_leg_prem
- shared_prem = neck_anten_leg_prem.union(
- neck_anten_prem, neck_leg_prem, anten_leg_prem
- )
- all_prem_neurons = neck_prem_set.union(anten_prem_set, leg_prem_set)
- motor_module_neurons["leg_prem"] = list(leg_prem_set - shared_prem)
- motor_module_neurons["neck_prem"] = list(neck_prem_set - shared_prem)
- motor_module_neurons["anten_prem"] = list(anten_prem_set - shared_prem)
- motor_module_neurons["shared_prem"] = list(shared_prem)
- motor_module_neurons["all_prem"] = list(all_prem_neurons)
- return motor_module_neurons
- def get_panel_m(
- grooming_network, motor_module_neurons, shared_prem, anten_prem_set, neck_prem_set
- ):
- # Look at how much of information to MNs come from shared vs. other prem neurons
- # total number of synapses onto neck mns
- neck_mns_upstream_synapses = grooming_network[
- grooming_network.post_root_id.isin(motor_module_neurons["neck_mn"])
- ].syn_count.sum()
- # number of synapses from shared prem onto neck mns
- neck_mns_shared_prem_input = grooming_network[
- (grooming_network.post_root_id.isin(motor_module_neurons["neck_mn"]))
- & (grooming_network.pre_root_id.isin(shared_prem))
- ].syn_count.sum()
- # number of synapses from ind. prem onto neck mns
- neck_mns_ind_input = grooming_network[
- (grooming_network.post_root_id.isin(motor_module_neurons["neck_mn"]))
- & (grooming_network.pre_root_id.isin(neck_prem_set - shared_prem))
- ].syn_count.sum()
- neck_input_percen = {
- "shared": 100 * neck_mns_shared_prem_input / neck_mns_upstream_synapses,
- "ind": 100 * neck_mns_ind_input / neck_mns_upstream_synapses,
- }
- print(
- f"""Neck motor neurons receive {neck_input_percen["shared"]:.2f}% of their input from shared premotor neurons"""
- )
- # Same for the antennal motor neurons
- # total number of synapses onto anten mns
- anten_mns_upstream_synapses = grooming_network[
- grooming_network.post_root_id.isin(motor_module_neurons["anten_mn"])
- ].syn_count.sum()
- # number of synapses from shared prem onto anten mns
- anten_mns_shared_prem_input = grooming_network[
- (grooming_network.post_root_id.isin(motor_module_neurons["anten_mn"]))
- & (grooming_network.pre_root_id.isin(shared_prem))
- ].syn_count.sum()
- # number of synapses from ind prem onto anten mns
- anten_mns_ind_input = grooming_network[
- (grooming_network.post_root_id.isin(motor_module_neurons["anten_mn"]))
- & (grooming_network.pre_root_id.isin(anten_prem_set - shared_prem))
- ].syn_count.sum()
- anten_input_percen = {
- "shared": 100 * anten_mns_shared_prem_input / anten_mns_upstream_synapses,
- "ind": 100 * anten_mns_ind_input / anten_mns_upstream_synapses,
- }
- print(
- f"""Antennal motor neurons receive {anten_input_percen["shared"]:.2f}% of their input from shared premotor neurons"""
- )
- return neck_input_percen, anten_input_percen
- def identify_central_neurons(grooming_network, motor_module_neurons):
- """To identify central neurons, we look at all simple paths from the JOF to the premotor/motor neurons and take those with a connection strength more than a threshold."""
- graph_table = nx.from_pandas_edgelist(
- grooming_network,
- source="pre_root_id",
- target="post_root_id",
- edge_attr=["syn_count", "syn_count_perc"],
- create_using=nx.DiGraph(),
- )
- cutoff = 4 # based on the layer algorithm max depth
- threshold = 0.05 # average synapse count percentage
- jof2prem_simple_paths = get_all_simple_paths(
- graph_table,
- # From
- motor_module_neurons["jo_f"],
- # To
- motor_module_neurons["all_prem"]
- + motor_module_neurons["neck_mn"]
- + motor_module_neurons["anten_mn"],
- cutoff=cutoff,
- )
- # Prune those with low connection strength
- jof2prem_simple_paths_pruned = threshold_prune_paths(
- graph_table,
- jof2prem_simple_paths,
- threshold=threshold,
- edge_property="syn_count_perc",
- exclude_nodes=motor_module_neurons["jo_e"]
- + motor_module_neurons["jo_c"]
- + motor_module_neurons["bm_ant"],
- )
- # Exclude sensory and motor module neurons
- central_neurons = set(
- itertools.chain.from_iterable(jof2prem_simple_paths_pruned)
- ).difference(
- set(
- motor_module_neurons["jo_f"]
- + motor_module_neurons["all_prem"]
- + motor_module_neurons["neck_mn"]
- + motor_module_neurons["anten_mn"]
- )
- )
- return list(central_neurons)
- def get_conn_between_groups(grooming_network, motor_module_neurons):
- """Calculate the connectivity percentage between neuron groups."""
- input_dictionary = {
- "sensory": motor_module_neurons["jo_f"],
- "central": motor_module_neurons["central"],
- "anten prem": motor_module_neurons["anten_prem"],
- "neck prem": motor_module_neurons["neck_prem"],
- "leg prem": motor_module_neurons["leg_prem"],
- "shared prem": motor_module_neurons["shared_prem"],
- }
- prem_mn_dictionary = {
- "central": motor_module_neurons["central"],
- "anten prem": motor_module_neurons["anten_prem"],
- "neck prem": motor_module_neurons["neck_prem"],
- "leg prem": motor_module_neurons["leg_prem"],
- "shared prem": motor_module_neurons["shared_prem"],
- "anten mn": motor_module_neurons["anten_mn"],
- "neck mn": motor_module_neurons["neck_mn"],
- }
- input_central_to_prem_array = np.zeros(
- (len(input_dictionary) + 1, len(prem_mn_dictionary))
- )
- # For each premotor neuron type, get the percentage of synapses going to each premotor neuron type
- input_central_to_prem_perc = {}
- for j, to_prem_type in enumerate(prem_mn_dictionary):
- total_synapses = grooming_network[
- grooming_network.post_root_id.isin(prem_mn_dictionary[to_prem_type])
- ].syn_count.sum()
- for i, from_prem_type in enumerate(input_dictionary):
- btw_synapses = grooming_network[
- (grooming_network.pre_root_id.isin(input_dictionary[from_prem_type]))
- & (grooming_network.post_root_id.isin(prem_mn_dictionary[to_prem_type]))
- ].syn_count.sum()
- # percentage
- if total_synapses == 0:
- perc = 0
- else:
- perc = 100 * btw_synapses / total_synapses
- # prem_to_prem_perc[(from_prem_type, to_prem_type)] = perc
- input_central_to_prem_array[i, j] = perc
- # Other
- input_central_to_prem_array[-1, :] = 100 - input_central_to_prem_array.sum(axis=0)
- return input_central_to_prem_array
- def draw_graph(
- adjacency_matrix,
- neuron_group_names_pre,
- neuron_group_names_post,
- pos_custom,
- node_colors,
- title="",
- fig_name=None,
- edge_label=False,
- normalize_edge_weight=False,
- threshold=0,
- connectionstyle="arc3,rad=0.1",
- export_path=None,
- ):
- # Plot a graph from the adjacency matrix
- neuron_names_pre = [name.replace("_", " ") for name in neuron_group_names_pre]
- neuron_names_post = [name.replace("_", " ") for name in neuron_group_names_post]
- neuron_names = np.unique(neuron_names_pre + neuron_names_post)
- fig, ax = plt.subplots(figsize=(2.4, 2.8), dpi=300)
- edge_color = []
- edge_weight = []
- edges = []
- # create directed graph from transition dataframe
- G = nx.DiGraph()
- for neuron in neuron_names:
- G.add_node(neuron)
- for row in range(adjacency_matrix.shape[0]):
- for column in range(adjacency_matrix.shape[1]):
- if np.abs(adjacency_matrix[row, column]) > threshold:
- # print(
- # f"{neuron_names_pre[row]} -> {neuron_names_post[column]}: {adjacency_matrix[row, column]}"
- # )
- G.add_edge(
- neuron_names_pre[row],
- neuron_names_post[column],
- weight=np.abs(adjacency_matrix[row, column]),
- )
- edge_color.append(
- "darkblue" if adjacency_matrix[row, column] < 0 else "darkred"
- )
- edges.append((neuron_names_pre[row], neuron_names_post[column]))
- edge_weight.append(adjacency_matrix[row, column])
- edge_weight = np.array(edge_weight)
- # print(edge_weight.min(), edge_weight.max())
- if normalize_edge_weight:
- edge_weight -= edge_weight.min() - 0.2
- edge_weight /= edge_weight.max() - edge_weight.min() - 0.2
- edge_weight *= 4.5
- # create node and edge labels
- node_labels = {
- node: node.replace(" ", "\n").replace("OTHER", "").replace("NEURONS", "")
- for node in G.nodes()
- }
- edge_labels = {(u, v): round(d["weight"], 1) for u, v, d in G.edges(data=True)}
- # create graph layout and draw nodes, edges, and labels
- pos = pos_custom
- node_size = 300
- nx.draw_networkx_nodes(
- G,
- pos,
- nodelist=neuron_names,
- node_size=node_size,
- node_shape="s",
- node_color=[node_colors[name] for name in G.nodes()],
- alpha=1,
- edgecolors="black",
- )
- # print(G.edges())
- nx.draw_networkx_edges(
- G,
- pos,
- # node_size=node_size,
- edgelist=edges,
- width=edge_weight,
- arrows=True,
- edge_color="black", # edge_color,
- connectionstyle=connectionstyle,
- alpha=1,
- )
- nx.draw_networkx_labels(G, pos, labels=node_labels, font_size=5)
- if edge_label:
- nx.draw_networkx_edge_labels(
- G,
- pos,
- edge_labels=edge_labels,
- font_size=3,
- rotate=False,
- label_pos=0.35,
- )
- # display graph
- plt.axis("off")
- ax.margins(0.1)
- ax.set_title(title)
- if fig_name is not None and export_path is not None:
- fig.savefig(
- export_path / f"{fig_name}.png", bbox_inches="tight", facecolor="white"
- )
- # plt.show()
- return G, edge_weight
- def order_signal_flow(grooming_network):
- """Takes the connectivity table of a network, and orders nodes based on their signal flow score (i.e., input to output)."""
- graph_table = nx.from_pandas_edgelist(
- grooming_network,
- source="pre_root_id",
- target="post_root_id",
- edge_attr=["syn_count", "syn_count_perc"],
- create_using=nx.DiGraph(),
- )
- # make the adj matrix
- adj_matrix_unsigned = nx.to_numpy_array(graph_table, weight=None)
- # apply the signal flow algorithm
- z = signal_flow(adj_matrix_unsigned)
- sort_inds = np.argsort(z)[::-1]
- adj_sorted_unsigned = adj_matrix_unsigned[np.ix_(sort_inds, sort_inds)]
- # get list of node names
- nodes = np.array(list(graph_table.nodes()))[sort_inds]
- # sort z too
- z_sorted = z[sort_inds]
- return adj_sorted_unsigned, nodes, z_sorted
- def layer_neurons(nodes, signal_flow_score, no_layers=10):
- """Divide the neurons into layers based on their signal flow score."""
- layer_bounds = np.linspace(
- signal_flow_score.max(), signal_flow_score.min(), no_layers
- )
- layer_neurons = {}
- for layer_no in range(len(layer_bounds) - 1):
- layer_neurons[layer_no + 1] = nodes[
- np.logical_and(
- layer_bounds[layer_no] >= signal_flow_score,
- signal_flow_score >= layer_bounds[layer_no + 1],
- )
- ]
- return layer_neurons, layer_bounds
- def get_connectivity_between_layers(layer_neurons, grooming_network):
- """ Computes the number of synapses between layers. """
- layers = list(layer_neurons.keys())
- # connectivity between the layers
- layer_by_layer = np.zeros((len(layers), len(layers)))
- layer_by_layer_inh = np.zeros((len(layers), len(layers)))
- layer_by_layer_exc = np.zeros((len(layers), len(layers)))
- for layer1 in sorted(layers):
- layer1_neurons = layer_neurons[layer1]
- for layer2 in sorted(layers):
- layer2_neurons = layer_neurons[layer2]
- synapses = grooming_network[
- grooming_network.pre_root_id.isin(layer1_neurons)
- & grooming_network.post_root_id.isin(layer2_neurons)
- ]
- synapses_inh = synapses[synapses.nt_type.isin(["GABA", "GLUT"])].syn_count.sum()
- synapses_exc = synapses[
- synapses.nt_type.isin(["ACH", "SER", "DA", "OCT"])
- ].syn_count.sum()
- synapses_total = synapses.syn_count.sum()
- assert synapses_total == synapses_inh + synapses_exc
- layer_by_layer[layer1 - 1, layer2 - 1] = synapses_total
- layer_by_layer_inh[layer1 - 1, layer2 - 1] = synapses_inh
- layer_by_layer_exc[layer1 - 1, layer2 - 1] = synapses_exc
- return layer_by_layer, layer_by_layer_inh, layer_by_layer_exc
- def classify_central_neurons(grooming_network, neuron_groups):
- """ Classify central neurons based on their projections onto premotor neurons."""
- central_neurons = neuron_groups["central"]
- shared_prem = neuron_groups["shared_prem"]
- neck_prem = neuron_groups["neck_prem"]
- anten_prem = neuron_groups["anten_prem"]
- leg_prem = neuron_groups["leg_prem"]
- # neck upstream and central
- shared_prem_upstream = set(grooming_network[
- grooming_network.pre_root_id.isin(central_neurons) &
- grooming_network.post_root_id.isin(shared_prem)
- ].pre_root_id.unique())
- neck_prem_upstream = set(grooming_network[
- grooming_network.pre_root_id.isin(central_neurons) &
- grooming_network.post_root_id.isin(neck_prem)
- ].pre_root_id.unique()) - shared_prem_upstream
- anten_prem_upstream = set(grooming_network[
- grooming_network.pre_root_id.isin(central_neurons) &
- grooming_network.post_root_id.isin(anten_prem)
- ].pre_root_id.unique()) - shared_prem_upstream
- leg_prem_upstream = set(grooming_network[
- grooming_network.pre_root_id.isin(central_neurons) &
- grooming_network.post_root_id.isin(leg_prem)
- ].pre_root_id.unique()) - shared_prem_upstream
- central_array_projection = np.zeros((len(central_neurons), 5))
- for central_id, central_neuron in enumerate(central_neurons):
- if central_neuron in anten_prem_upstream:
- central_array_projection[central_id, 0] = 1
- if central_neuron in neck_prem_upstream:
- central_array_projection[central_id, 1] = 1
- if central_neuron in leg_prem_upstream:
- central_array_projection[central_id, 2] = 1
- if central_neuron in shared_prem_upstream:
- central_array_projection[central_id, 3] = 1
- # if not in any premotor neuron
- if (
- central_neuron not in shared_prem_upstream
- and central_neuron not in neck_prem_upstream
- and central_neuron not in anten_prem_upstream
- and central_neuron not in leg_prem_upstream
- ):
- central_array_projection[central_id, 4] = 1
- return central_array_projection
Figure4_graph_tools.py at commit 65787ac, under Apache-2.0 · at the source
Overview
- Neuroengineering Laboratory, Brain Mind Institute & Interfaculty Institute of Bioengineering, EPFL, Lausanne, Switzerland
- Biorobotics Laboratory, Institute of Bioengineering, EPFL, Lausanne, Switzerland
- Kempner Institute, Harvard University, Allston, MA USA
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repositories
Its files are read in the Code ↔ Paper reader above, with 40 matches between paragraphs and lines of code.
gizemozd/anipose
eb23f2ddde8d50b030c2195f475ab8aef370bfd5, 16 July 2022Availability: 1 check, the latest on 29 September 2026: the link answers
- 29 September 2026: the link answers
28 files
- anipose/
__init__.py , Python, 7 lines - anipose/
anipose.py , Python, 404 lines - anipose/
calibrate.py , Python, 230 lines - anipose/
calibration_errors.py , Python, 206 lines - anipose/
common.py , Python, 228 lines - anipose/
compute_angles.py , Python, 189 lines - anipose/
convert_videos.py , Python, 80 lines - anipose/
extract_frames.py , Python, 546 lines - anipose/
filter_3d.py , Python, 82 lines - anipose/
filter_pose.py , Python, 391 lines - anipose/
label_combined.py , Python, 514 lines - anipose/
label_filter_compare.py , Python, 203 lines - anipose/
label_videos.py , Python, 165 lines - anipose/
label_videos_3d.py , Python, 201 lines - anipose/
label_videos_proj.py , Python, 122 lines - anipose/
pose_videos.py , Python, 72 lines - anipose/
project_2d.py , Python, 163 lines - anipose/
server.py , Python, 476 lines - anipose/
static/ , JavaScript, 2,030 linesscript.js - anipose/
summarize.py , Python, 136 lines - anipose/
tracking_errors.py , Python, 184 lines - anipose/
train_autoencoder.py , Python, 113 lines - anipose/
triangulate.py , Python, 380 lines - docs/
sphinx/ , Python, 59 linesconf.py - release.sh, Shell, 5 lines
- setup.py, Python, 43 lines
- LICENSE, License, 25 lines
- README.md, Text, 37 lines
NeLy-EPFL/kinematics3d
7b2621bf9c677266b68d755822356ffe1868524d, 16 July 2025Availability: 1 check, the latest on 29 September 2026: the link answers
- 29 September 2026: the link answers
28 files
- charuco_board/
check_charuco.py , Python, 46 lines, 1 match - charuco_board/
design/ , Python, 27 lines, 1 matchcheckboard_config.py - dlc_fxns/
01_extract_frames.py , Python, 38 lines - dlc_fxns/
02_create_training_datas , Python, 46 lineset.py - dlc_fxns/
03_train_network.py , Python, 48 lines - dlc_fxns/
04_evaluate_network.py , Python, 36 lines - dlc_fxns/
05_run_pose_estimation.p , Python, 57 linesy - dlc_fxns/
06_extract_outlier_refin , Python, 55 lines, 1 matche.py - dlc_fxns/
add_new_videos.py , Python, 27 lines - dlc_fxns/
change_kp_names.py , Python, 29 lines - dlc_fxns/
check_video_exists.py , Python, 56 lines - dlc_fxns/
femke_exps.py , Python, 48 lines - dlc_fxns/
get_videos_list.py , Python, 32 lines - dlc_fxns/
run_pose_5cams.py , Python, 63 lines - dlc_fxns/
transfer_synch.py , Python, 85 lines - kinematics3d/
__init__.py , Python, 1 line - kinematics3d/
anipose_pipeline.py , Python, 225 lines - kinematics3d/
camera_pose_viz.py , Python, 64 lines - kinematics3d/
constants.py , Python, 96 lines, 1 match - kinematics3d/
ffmpeg.py , Python, 123 lines - kinematics3d/
pose2d.py , Python, 188 lines - kinematics3d/
utils.py , Python, 90 lines - kinematics3d/
visualization.py , Python, 160 lines - scripts/
run_pipeline_sample.sh , Shell, 11 lines - scripts/
run_video_making.py , Python, 75 lines - setup.py, Python, 48 lines
- LICENSE, License, 201 lines
- README.md, Text, 63 lines
NeLy-EPFL/antennal-grooming
65787ac7fa35aa5520addb6d3e4ac27887bbaf60, 4 May 2026Availability: 1 check, the latest on 29 September 2026: the link answers
- 29 September 2026: the link answers
33 files
- download_data.sh, Shell, 26 lines
- generate_figures.sh, Shell, 83 lines
- src/
EDFigure1.ipynb , Jupyter, 465 lines - src/
EDFigure10.ipynb , Jupyter, 247 lines - src/
EDFigure11.ipynb , Jupyter, 691 lines - src/
EDFigure13.ipynb , Jupyter, 259 lines, 1 match - src/
EDFigure2.ipynb , Jupyter, 175 lines, 2 matches - src/
EDFigure3.ipynb , Jupyter, 102 lines - src/
EDFigure4.ipynb , Jupyter, 467 lines, 2 matches - src/
EDFigure6.ipynb , Jupyter, 108 lines - src/
EDFigure7.ipynb , Jupyter, 467 lines, 1 match - src/
EDFigure8.ipynb , Jupyter, 133 lines - src/
EDFigure9.ipynb , Jupyter, 419 lines, 1 match - src/
Figure1.ipynb , Jupyter, 850 lines, 2 matches - src/
Figure2.ipynb , Jupyter, 802 lines, 3 matches - src/
Figure3.ipynb , Jupyter, 1,529 lines - src/
Figure4.ipynb , Jupyter, 736 lines, 2 matches - src/
Figure5.ipynb , Jupyter, 317 lines, 1 match - src/
Figure6.ipynb , Jupyter, 908 lines, 3 matches - src/
Figure7.ipynb , Jupyter, 468 lines, 2 matches - src/
common.py , Python, 922 lines, 2 matches - src/
prepare_data/ , Python, 159 lines, 1 matchEDFigure9_random_graphs. py - src/
prepare_data/ , Python, 138 linesFigure1_prepare_data.py - src/
prepare_data/ , Python, 1,194 lines, 3 matchesFigure3_prepare_data.py - src/
prepare_data/ , Python, 402 lines, 2 matchesFigure4_generate_groomin g_network.py - src/
prepare_data/ , Python, 737 lines, 6 matchesFigure4_graph_tools.py - src/
prepare_data/ , Python, 95 linesFigure4_neurons.py - src/
prepare_data/ , Python, 137 lines, 1 matchFigure5_prepare_data.py - src/
prepare_data/ , Python, 195 linesFigure6_prepare_data.py - src/
prepare_data/ , Python, 1 line__init__.py - src/
prepare_data/ , Python, 813 lines, 1 matchconnectome_utils.py - LICENSE, License, 201 lines
- README.md, Text, 116 lines
Code availability statement
The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to the authors' code: NeLy-EPFL/
antennal-grooming - it says that the code is available on request
Read it in the paper: doi.org/10.1038/s41467-026-72152-x.
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:
- 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 83 scripts, each with its path and the digest of its content;
- 40 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
- dataverse.harvard.edu/
dataverse/ , at dataverse.harvard.edu; found in “Data availability”ozdil_2024_antennal_groo ming
Data availability statement
The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to a dataset: dataverse.harvard.edu/
dataverse/ ozdil_2024_antennal_groo ming
Read it in the paper: doi.org/10.1038/s41467-026-72152-x.
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, 29 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 6 authors, 3 keywords, 10 MeSH terms, 3 funders, 99 references.
Cite
This paper
Özdil, P. G., Arreguit, J., Scherrer, C., Hurtak, F., Ijspeert, A., & Ramdya, P. (2026). Centralized brain networks controlling antennal grooming coordination. Nature communications, 17(1), 5617. https://
BibTeX
@article{ozdil2026centra
author = {Özdil, Pembe Gizem and Arreguit, Jonathan and Scherrer, Clara and Hurtak, Femke and Ijspeert, Auke and Ramdya, Pavan},
title = {{Centralized brain networks controlling antennal grooming coordination}},
journal = {Nature communications},
year = {2026},
month = apr,
volume = {17},
number = {1},
pages = {5617},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/
url = {https://
pmid = {42026054},
pmcid = {PMC13314972}
}
RIS
TY - JOUR
AU - Özdil, Pembe Gizem
AU - Arreguit, Jonathan
AU - Scherrer, Clara
AU - Hurtak, Femke
AU - Ijspeert, Auke
AU - Ramdya, Pavan
TI - Centralized brain networks controlling antennal grooming coordination
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/
VL - 17
IS - 1
SP - 5617
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "Centralized brain networks controlling antennal grooming coordination",
"container-title": "Nature communications",
"author": [
{
"family": "Özdil",
"given": "Pembe Gizem"
},
{
"family": "Arreguit",
"given": "Jonathan"
},
{
"family": "Scherrer",
"given": "Clara"
},
{
"family": "Hurtak",
"given": "Femke"
},
{
"family": "Ijspeert",
"given": "Auke"
},
{
"family": "Ramdya",
"given": "Pavan"
}
],
"container-title-short":
"volume": "17",
"issue": "1",
"page": "5617",
"DOI": "10.1038/
"PMID": "42026054",
"PMCID": "PMC13314972",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
23
]
]
}
}
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/s41586-026-10735-w [code]
- Distributed control circuits across a brain-and-cord connectome.Journal: NatureIn common: NetworkX, seaborn, scikit-learn, 4 other tools, drosophila, 26 references
- [2] doi:10.7554/elife.96084 [code]
- Organization of circuits linking descending input to motor output in the &
lt;i& gt;Drosophila& lt;/ i& gt; Male Adult Nerve Cord connectome. Journal: eLifeIn common: drosophila, systems, 19 references - [3] 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: TensorFlow, NetworkX, h5py, 6 other tools, systems, 10 references
- [4] doi:10.7554/elife.107867 [code]
- Peripheral anatomy and central connectivity of proprioceptive sensory neurons in the &
lt;i& gt;Drosophila& lt;/ i& gt; wing. Journal: eLifeIn common: seaborn, scikit-learn, pandas, 3 other tools, drosophila, 9 references - [5] doi:10.1371/journal.pbio.3003959 [code]
- Recurrent synapses between CO2-sensitive olfactory sensory neurons enable robust CO2 detection in Aedes aegypti mosquitoes.Journal: PLoS biologyIn common: statsmodels, seaborn, scikit-learn, 4 other tools, drosophila, 8 references
- [6] doi:10.1038/s41467-026-72057-9 [code]
- Sex-specific behavioral feedback modulates sensorimotor processing and drives flexible social behavior.Journal: Nature communicationsIn common: TensorFlow, OpenCV, h5py, 7 other tools, drosophila, systems, 4 references
- [7] doi:10.1016/j.isci.2026.117359 [code]
- Connectomic mapping of pharyngeal and gut sensory circuits in adult &
lt;i& gt;Drosophila& lt;/ i& gt;. Journal: iScienceIn common: statsmodels, seaborn, pandas, 3 other tools, drosophila, systems, 7 references - [8] doi:10.1038/s41593-026-02232-0 [code]
- Entorhinal cortex represents task-relevant remote locations independently of CA1.Journal: Nature neuroscienceIn common: DeepLabCut, NetworkX, OpenCV, 8 other tools, systems, 1 reference
- [9] doi:10.1038/s41593-026-02262-8 [code]
- Cheese3D enables sensitive detection and analysis of whole-face movement in mice.Journal: Nature neuroscienceIn common: DeepLabCut, OpenCV, h5py, 6 other tools, systems, 2 references
- [10] doi:10.1126/sciadv.aeh7220 [code]
- Central complex representations of self-movement are sufficient to compute wind direction in flight.Journal: Science advancesIn common: TensorFlow, statsmodels, seaborn, 5 other tools, 4 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: 3 repositories of the authors' code, each at its verified commit and with its license, 83 scripts, and 40 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:29e03a4c6de3a977…
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.
