Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish.
The 19 matches
- [1] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for vagal experiments ↔ Analysis/Figure 2/1_extract_neurons.ipynb, lines 125–188 · score 0.98 · gSig, merge_thr, SNR_lowest, cnn_lowest, min_SNR, min_cnn_thr
- [2] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for vagal experiments ↔ Analysis/Figure 3/1_extract_neurons.ipynb, lines 124–195 · score 0.98 · gSig, merge_thr, SNR_lowest, cnn_lowest, min_SNR, min_cnn_thr
- [3] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for hindbrain experiments ↔ Analysis/Figure 2/1_extract_neurons.ipynb, lines 125–188 · score 0.97 · gSig, merge_thr, SNR_lowest, cnn_lowest, min_SNR, min_cnn_thr
- [4] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for hindbrain experiments ↔ Analysis/Figure 3/1_extract_neurons.ipynb, lines 124–195 · score 0.97 · gSig, merge_thr, SNR_lowest, cnn_lowest, min_SNR, min_cnn_thr
- [5] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for vagal experiments ↔ Analysis/Figure 3/4_vagal_alignment.ipynb, lines 47–159 · score 0.90 · flipped horizontally, left vagal ganglion, right vagal ganglion, reverse alignment, scalePenalty, landmarks
- [6] § STAR★Methods › Quantification and statistical analysis ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 309–338 · score 0.86 · beta regression, generalized linear model, 0–100 %, upper bound, GLM, variables
- [7] § Results › Chemosensory encoding of AITC features slow-onset dynamics ↔ notebooks/hindbrain_alignment_to_mapzebrain.ipynb, lines 402–445 · score 0.86 · inferior dorsal medulla, intermediate dorsal medulla, vagus motor nucleus, vagal sensory lobe, area postrema, oblongata
- [8] § Results › Gut distension broadly activates dorsal hindbrain circuits ↔ notebooks/hindbrain_alignment_to_mapzebrain.ipynb, lines 402–445 · score 0.81 · inferior dorsal medulla, intermediate dorsal medulla, vagus motor nucleus, vagal sensory lobe, oblongata, hindbrain
- [9] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for vagal experiments ↔ notebooks/vagal_alignment.ipynb, lines 50–70 · score 0.76 · flipped horizontally, left vagal ganglion, right vagal ganglion, anatomy, summed, pixel
- [10] § STAR★Methods › Quantification and statistical analysis ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 452–480 · score 0.68 · fold change, Gamma, GLM, genotypes, EECDTA, WT
- [11] § STAR★Methods › Method details › Feeding behavior data processing and analysis ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 91–123 · score 0.67 · Kolmogorov Smirnov, feeding behavior, bootstrapping, unfiltered, median, raw
- [12] § STAR★Methods › Method details › Slice tensor component analysis (sliceTCA) › Cross-validated model selection ↔ slicetca/run/grid_search.py, lines 15–78 · score 0.66 · cross validated loss, seeds, training, masked, components, models
- [13] § STAR★Methods › Method details › Two-photon data processing and analysis ↔ Analysis/Figure 3/1_extract_neurons.ipynb, lines 70–122 · score 0.65 · motion correction, NoRMCorre, CaImAn, mesmerize, gavage, volumes
- [14] § STAR★Methods › Method details › Slice tensor component analysis (sliceTCA) › Cross-validated model selection ↔ slicetca/run/decompose.py, lines 11–72 · score 0.65 · SliceTCA, seeds, training, loss, optimize, models
- [15] § Results › EEC depletion alters food approach and nutrient-specific feeding ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 348–378 · score 0.64 · feeding behavior, NaCl, Ctrl, EECDTA, alanine, empty
- [16] § Results › Amino acids increase gut-mediated feeding ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 189–233 · score 0.60 · NaCl, batch control, Gut fluorescence, Gly, Ala, Glu
- [17] § Results › Amino acids increase gut-mediated feeding ↔ Analysis/Figure 1/1_feeding_behavior_analysis.ipynb, lines 348–378 · score 0.56 · NaCl, Gly, Glu, Ctrl, alanine, empty
- [18] § STAR★Methods › Method details › Two-photon calcium imaging ↔ Analysis/Figure 3/4_vagal_alignment.ipynb, lines 47–159 · score 0.54 · right vagal ganglion, landmarks, anatomy, pixels, elavl3, stack
- [19] § STAR★Methods › Method details › Two-photon data processing and analysis › Parameters for hindbrain experiments ↔ notebooks/hindbrain_alignment_to_mapzebrain.ipynb, lines 65–106 · score 0.50 · scalePenalty, mapZebrain, Alignment, iterations, hindbrain
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Jupyter notebook · 533 lines · 20 KB · no license · 6 matches
- # %%
- %load_ext autoreload
- %autoreload 2
- import matplotlib.pyplot as plt
- import numpy as np
- import os
- import pandas as pd
- from random import sample
- from scipy.stats import ks_2samp
- import statsmodels.api as sm
- import statsmodels.formula.api as smf
- from statsmodels.othermod.betareg import BetaModel
- import sys
- # Change this folder to where the cloned `caImageAnalysis` repository is
- sys.path.insert(0, '/Users/minelarinel/caImageAnalysis')
- # Set the base path to the arinel-et-al_2025 repository
- arinel_repo_path = r'/Users/minelarinel/arinel-et-al_2025'
- from caImageAnalysis.statistics import *
- # %%
- # Set the `data_folder` variable to the path of the folder containing the data files
- data_folder = fr'{arinel_repo_path}/Data/Fig1/Feeding behavior experiments'
- # %%
- # Process experimental data from multiple folders and compile it into a list of DataFrames.
- # 1. Initialize an empty list `exp_folders` to store paths of experiment folders.
- exp_folders = list()
- # 2. Iterate through the entries in the `data_folder` directory:
- # - If an entry is a directory and its name starts with '202', add its path to `exp_folders`.
- with os.scandir(data_folder) as entries:
- for entry in entries:
- if os.path.isdir(entry.path) and entry.name.startswith('202'):
- exp_folders.append(entry.path)
- # 3. Initialize an empty list `dfs` to store DataFrames.
- dfs = list()
- # 4. Iterate through the experiment folders in `exp_folders`
- for exp_folder in exp_folders:
- # Read the 'Results.csv' file into a DataFrame `df`.
- df = pd.read_csv(os.path.join(exp_folder, 'Results.csv'))
- # Add columns 'Experiment', 'filtered', and 'ablated' to `df`.
- df['Experiment'] = exp_folder[exp_folder.rfind('/')+1:]
- df['filtered'] = False
- df['ablated'] = False
- # For the '20231005_filtered(ala_emp_glu)' experiment, since only 3 of the stimuli were filtered,
- # mark rows with those specific stimuli as filtered.
- if '20231005_filtered(ala_emp_glu)' in exp_folder:
- filtered_stims = ['alanine', 'empty', 'glucose']
- for i, row in df.iterrows():
- if row['Stimulus'] in filtered_stims:
- df.loc[i, 'filtered'] = True
- # If the folder name contains 'filtered', mark all rows as filtered.
- elif 'filtered' in exp_folder:
- df['filtered'] = True
- # If the folder name contains 'ABLATED', mark all rows as ablated.
- if 'ABLATED' in exp_folder:
- df['ablated'] = True
- # Since an experiment can have multiple plates that got the same stimulus,
- # also keep track of the plate identity.
- df["plate"] = 0
- stims = list()
- for i, row in df.iterrows():
- if row["Stimulus"] != 'None' and row["Stimulus"] not in stims:
- pass
- elif row["Stimulus"] != 'None' and row["Stimulus"] in stims:
- df.loc[i, "plate"] = stims.count(row["Stimulus"])
- elif row["Stimulus"] == 'None':
- stims.append(df.loc[i-1, "Stimulus"])
- dfs.append(df)
- # Concatenate the DataFrames in `dfs` into a single DataFrame `df`.
- df = pd.concat(dfs, ignore_index=True)
- df = df[df.Stimulus != 'None']
- df
- # %% [markdown]
- # ### Check if the filtering has an effect
- # %%
- # Perform a bootstrapping analysis to determine if there is a statistically significant difference
- # between unfiltered and filtered datasets for 'empty' stimulus conditions using the Kolmogorov-Smirnov test.
- # Set the number of bootstrap iterations to perform.
- n_iterations = 1000
- empty_nofilter_vals = df[(df.filtered == False) & (df.Stimulus == 'empty') & (df.RawIntDen != 0)].RawIntDen.values
- empty_filter_vals = df[(df.filtered == True) & (df.Stimulus == 'empty') & (df.RawIntDen != 0)].RawIntDen.values
- # Check if the filtered dataset has more data points than the unfiltered dataset.
- # If true, perform bootstrapping.
- if len(empty_filter_vals) > len(empty_nofilter_vals):
- sample_pvals = list()
- for i in range(n_iterations):
- # Randomly sample data points from the filtered dataset to match the number of data points
- # in the unfiltered dataset.
- y = sample(list(empty_filter_vals), len(empty_nofilter_vals))
- # Perform the Kolmogorov-Smirnov test between the sampled filtered data and the unfiltered data.
- # Store the p-value from each iteration.
- _, p_value = kolmogorov_smirnov_test(y, empty_nofilter_vals, verbose=False)
- sample_pvals.append(p_value)
- # Calculate and print the median p-value from all iterations.
- # If the median p-value is larger than 0.05, the difference is statistically significant and
- # the two datasets need to be treated separately.
- print(np.median(sample_pvals))
- # %% [markdown]
- # Since the p-value is larger than 0.05, we can combine the filtered and unfiltered datasets.
- # %% [markdown]
- # ## Gut fluorescence - WT
- # %%
- # Combine the raw gut fluorescence for each experiment and store it in a dictionary.
- # Define the list of stimuli
- stims = ['empty', 'NaCl', 'glucose', 'glycine', 'alanine']
- aggregate = {stim: [] for stim in stims}
- normal_df = df[(df.ablated == False) & (df.RawIntDen != 0)]
- # Calculate gut fluorescence for each stimulus
- for stim in stims:
- stimdf = normal_df[normal_df.Stimulus == stim]
- aggregate[stim].extend(stimdf.RawIntDen.values)
- aggregate = dict([(k,pd.Series(v)) for k,v in aggregate.items()])
- # Rename the columns of the DataFrame
- df_WT = pd.DataFrame(aggregate)
- df_WT.columns = ["Ctrl", "NaCl", "Glu", "Gly", "Ala"]
- # Print and copy the combined DataFrame to clipboard
- print(df_WT)
- df_WT.to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `WT total gut fluorescence`, for plotting the graph.
- # %% [markdown]
- # ### Check if there are differences across batches
- # %%
- # Determine whether fish from different batches eat in different amounts.
- # Filter out ablated data
- normal_df = df[df.ablated == False]
- # Initialize a dictionary to store 'empty' stimulus data per experiment
- empty_per_exp = dict()
- # Iterate over unique experiments
- for i, exp in enumerate(normal_df.Experiment.unique()):
- # Filter data for the current experiment with 'empty' stimulus and non-zero RawIntDen
- exp_df = normal_df[(normal_df.Experiment == exp) & (normal_df.Stimulus == 'empty') & (normal_df.RawIntDen != 0)]
- # Store RawIntDen values in the dictionary
- empty_per_exp[f'batch {i+1}'] = exp_df.RawIntDen.values
- print(f'batch {i+1}: {exp}')
- # Convert dictionary values to pandas Series
- empty_per_exp = dict([(k, pd.Series(v)) for k, v in empty_per_exp.items()])
- # Print the DataFrame created from the dictionary
- print(pd.DataFrame(empty_per_exp))
- # Copy the DataFrame to clipboard
- pd.DataFrame(empty_per_exp).to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `WT batch differences`, for further analysis.
- # %% [markdown]
- # Due to significant differences in feeding across the controls of batches, all the raw intensity values are normalized to the batch control.
- # %% [markdown]
- # ### Fold change in gut fluorescence intensity
- # %%
- # Calculate the fold change in Raw Integrated Density (RawIntDen) for different stimuli
- # compared to the 'empty' condition. The results are stored in a dictionary and then
- # converted to a DataFrame for further analysis or copying to the clipboard.
- stims = ['empty', 'NaCl', 'glucose', 'glycine', 'alanine']
- aggregate_foldchange = {stim: [] for stim in stims}
- # Filter the DataFrame to include only relevant data.
- normal_df = df[(df.ablated == False) & (df.RawIntDen != 0)]
- for exp in normal_df.Experiment.unique():
- exp_df = normal_df[normal_df.Experiment == exp]
- # Median RawIntDen for the 'empty' condition.
- empty_fei = 0
- for stim in stims:
- stimdf = exp_df[exp_df.Stimulus == stim]
- if stim == 'empty':
- # For each experiment, calculate the median RawIntDen for the 'empty' condition.
- empty_fei = np.median(stimdf.RawIntDen.values)
- # Calculate the fold change for each stimulus compared to the 'empty' condition.
- aggregate_foldchange[stim].extend((stimdf.RawIntDen.values - empty_fei)/empty_fei)
- aggregate_foldchange = dict([(k,pd.Series(v)) for k,v in aggregate_foldchange.items()])
- # Rename the columns of the DataFrame
- df_foldchange = pd.DataFrame(aggregate_foldchange)
- df_foldchange.columns = ["Ctrl", "NaCl", "Glu", "Gly", "Ala"]
- # Print the DataFrame and copy it to the clipboard
- print(df_foldchange)
- df_foldchange.to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `WT fold change in fluorescence`, for further analysis.
- # %% [markdown]
- # ## Feeding incidence
- # %%
- # Calculate the feeding incidence for each experiment and store it in a dictionary.
- # Define the list of stimuli
- stims = ['empty', 'NaCl', 'glucose', 'glycine', 'alanine']
- feeding_incidence = {stim: [] for stim in stims}
- feeding_incidence_ablated = {stim: [] for stim in stims}
- normal_df = df[df.ablated == False]
- ablated_df = df[df.ablated == True]
- # Calculate feeding incidence for each stimulus
- for stim in stims:
- stimdf = normal_df[normal_df.Stimulus == stim]
- ablated_stimdf = ablated_df[ablated_df.Stimulus == stim]
- for exp in stimdf.Experiment.unique():
- for plate in stimdf[stimdf.Experiment == exp].plate.unique():
- expdf = stimdf[(stimdf.Experiment == exp) & (stimdf.plate == plate)]
- zeros = len(expdf[expdf.RawIntDen == 0])
- n_fish = len(expdf)
- feeding_incidence[stim].append((n_fish - zeros) / n_fish * 100)
- for exp in ablated_stimdf.Experiment.unique():
- for plate in ablated_stimdf[ablated_stimdf.Experiment == exp].plate.unique():
- expdf = ablated_stimdf[(ablated_stimdf.Experiment == exp) & (ablated_stimdf.plate == plate)]
- zeros = len(expdf[expdf.RawIntDen == 0])
- n_fish = len(expdf)
- feeding_incidence_ablated[stim].append((n_fish - zeros) / n_fish * 100)
- # Find the maximum number of columns needed for each stimulus.
- max_values_per_stim = {stim: max([len(feeding_incidence[stim]),
- len(feeding_incidence_ablated[stim])])
- for stim in stims}
- max_columns = int(max(max_values_per_stim.values()))
- print(f"Number of columns: {max_columns}")
- # Organize the feeding incidence data into a single DataFrame.
- organized_results = {stim: [] for stim in stims}
- for stim, values in feeding_incidence.items():
- organized_results[stim] = values + [np.nan] * (max_columns - len(values))
- organized_results_ablated = {stim: [] for stim in stims}
- for stim, values in feeding_incidence_ablated.items():
- organized_results_ablated[stim] = values + [np.nan] * (max_columns - len(values))
- # Create a DataFrame from the organized feeding incidence data.
- df_results = pd.DataFrame(organized_results)
- df_results_ablated = pd.DataFrame(organized_results_ablated)
- # Combine the two DataFrames into a single DataFrame.
- feeding_incidence_combined = pd.concat([df_results.transpose(), df_results_ablated.transpose()], axis=1)
- # Rename the columns of the DataFrame
- feeding_incidence_combined.index = ["Ctrl", "NaCl", "Glu", "Gly", "Ala"]
- # Print and copy the combined DataFrame to clipboard
- print(feeding_incidence_combined)
- feeding_incidence_combined.to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `feeding incidence`, for plotting the graph.
- # %%
- # Check if the feeding incidence data is normally distributed.
- for stim in stims:
- check_normality(feeding_incidence[stim], feeding_incidence_ablated[stim])
- # %% [markdown]
- # Since there are arrays that are not normally distributed, we need to run a test that does not assume normality to determine whether there are any genotype and stimulus effects. Therefore, we transition to Generalized Linear Models (GLMs). Since feeding incidences have a lower and upper bound (0-100), run the GLM with a beta regression.
- # %%
- # Prepare the data for the GLM
- # Combine the feeding incidence data into a single DataFrame
- data = []
- for stim in stims:
- for val in feeding_incidence[stim]:
- data.append({'Stimulus': stim, 'Value': val, 'Genotype': 'WT'})
- for val in feeding_incidence_ablated[stim]:
- data.append({'Stimulus': stim, 'Value': val, 'Genotype': 'EECDTA'})
- data = pd.DataFrame(data)
- # Beta regression requires the response variable to be in the range (0, 1), without any
- # zeros or ones.
- # To avoid this, we will transform the data according to Smithson and Verkuilen (2006).
- data["Value"] = data["Value"] / 100
- N = len(data)
- s = 0.5 # constant between 0 and 1
- for i, row in data.iterrows():
- data.at[i, "Value"] = ((row["Value"] * (N - 1)) + s) / N
- # Fit full model with interaction
- model = BetaModel.from_formula(f"Value ~ C(Stimulus, Treatment(reference='empty')) * C(Genotype, Treatment(reference='WT'))",
- data)
- result = model.fit(reml=True)
- print(result.summary())
- # %% [markdown]
- # We see a genotype effect in the GLM, so we combine stimuli.
- # %%
- # Check the variability of the feeding incidences between WT and EECDTA fish
- fligner_test(np.concatenate(list(feeding_incidence.values())),
- np.concatenate(list(feeding_incidence_ablated.values())))
- # %% [markdown]
- # EEC<sup>DTA</sup> fish have significantly lower and more variable feeding incidence values compared to WT.
- # %% [markdown]
- # ## Gut fluorescence - EEC<sup>DTA</sup>
- # %%
- # Combine the raw gut fluorescence for each experiment and store it in a dictionary.
- # Define the list of stimuli
- stims = ['empty', 'NaCl', 'glucose', 'glycine', 'alanine']
- aggregate_ablated = {stim: [] for stim in stims}
- ablated_df = df[(df.ablated == True) & (df.RawIntDen != 0)]
- # Calculate gut fluorescence for each stimulus
- for stim in stims:
- stimdf = ablated_df[ablated_df.Stimulus == stim]
- aggregate_ablated[stim].extend(stimdf.RawIntDen.values)
- aggregate_ablated = dict([(k,pd.Series(v)) for k,v in aggregate_ablated.items()])
- # Rename the columns of the DataFrame
- df_EECDTA = pd.DataFrame(aggregate_ablated)
- df_EECDTA.columns = ["Ctrl", "NaCl", "Glu", "Gly", "Ala"]
- # Print and copy the combined DataFrame to clipboard
- print(df_EECDTA)
- df_EECDTA.to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `EEC-DTA total gut fluorescence`, for plotting the graph.
- # %% [markdown]
- # ### Check if there are differences across batches
- # %%
- # Determine whether fish from different batches eat in different amounts.
- # Filter out WT data
- ablated_df = df[df.ablated == True]
- # Initialize a dictionary to store 'empty' stimulus data per experiment
- empty_per_exp = dict()
- # Iterate over unique experiments
- for i, exp in enumerate(ablated_df.Experiment.unique()):
- # Filter data for the current experiment with 'empty' stimulus and non-zero RawIntDen
- exp_df = ablated_df[(ablated_df.Experiment == exp) & (ablated_df.Stimulus == 'empty') & (ablated_df.RawIntDen != 0)]
- # Store RawIntDen values in the dictionary
- empty_per_exp[f'batch {i+1}'] = exp_df.RawIntDen.values
- print(f'batch {i+1}: {exp}')
- # Convert dictionary values to pandas Series
- empty_per_exp = dict([(k, pd.Series(v)) for k, v in empty_per_exp.items()])
- # Print the DataFrame created from the dictionary
- print(pd.DataFrame(empty_per_exp))
- # Copy the DataFrame to clipboard
- pd.DataFrame(empty_per_exp).to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `EEC-DTA batch differences`, for further analysis.
- # %% [markdown]
- # ### Fold change in gut fluorescence intensity
- # %%
- # Calculate the fold change in Raw Integrated Density (RawIntDen) for different stimuli
- # compared to the 'empty' condition. The results are stored in a dictionary and then
- # converted to a DataFrame for further analysis or copying to the clipboard.
- stims = ['empty', 'NaCl', 'glucose', 'glycine', 'alanine']
- aggregate_foldchange_ablated = {stim: [] for stim in stims}
- # Filter the DataFrame to include only relevant data.
- ablated_df = df[(df.ablated == True) & (df.RawIntDen != 0)]
- for exp in ablated_df.Experiment.unique():
- exp_df = ablated_df[ablated_df.Experiment == exp]
- # Median RawIntDen for the 'empty' condition.
- empty_fei = 0
- for stim in stims:
- stimdf = exp_df[exp_df.Stimulus == stim]
- if stim == 'empty':
- # For each experiment, calculate the median RawIntDen for the 'empty' condition.
- empty_fei = np.median(stimdf.RawIntDen.values)
- # Calculate the fold change for each stimulus compared to the 'empty' condition.
- aggregate_foldchange_ablated[stim].extend((stimdf.RawIntDen.values - empty_fei)/empty_fei)
- # %% [markdown]
- # #### Check whether there is a difference between the two genotypes across stimuli
- # %%
- # Check if the gut fluorescence data is normally distributed.
- for stim in stims:
- normality = check_normality(aggregate_foldchange[stim], aggregate_foldchange_ablated[stim], verbose=False)
- if False in normality:
- print(f"Data for {stim} is not normally distributed.")
- # %% [markdown]
- # Since we have arrays that are not normally distributed, we need to run Generalized Linear Models (GLMs). Since fold changes are heavily skewed, continuous data, run a GLM with a gamma distribution.
- # %%
- # Prepare the data for generalized linear model (GLM)
- # Combine the fold change data into a single DataFrame
- data = []
- for stim in stims:
- for val in aggregate_foldchange[stim]:
- data.append({'Stimulus': stim, 'FoldChange': val, 'Genotype': 'WT'})
- for val in aggregate_foldchange_ablated[stim]:
- data.append({'Stimulus': stim, 'FoldChange': val, 'Genotype': 'EECDTA'})
- data = pd.DataFrame(data)
- glm_data = pd.DataFrame(data)
- # Gamma regression requires the response variable to be positive.
- # To avoid this, we will transform the data by adding a small constant to ensure all values
- # are positive.
- glm_data["FoldChange"] = glm_data["FoldChange"] + np.abs(glm_data["FoldChange"].min()) + 0.001
- # Fit Gamma Regression Model
- model = smf.glm(
- formula="FoldChange ~ C(Genotype, Treatment(reference='WT')) * C(Stimulus, Treatment(reference='empty'))",
- data=glm_data,
- family=sm.families.Gamma(link=sm.families.links.log())
- )
- result = model.fit()
- print(result.summary())
- # %%
- sidak_results = sidak_multiple_comparisons_test(data, between=["Stimulus", "Genotype"], between_reference=["empty", "WT"],
- interaction=True, melt_df=False, dv='FoldChange',
- parametric=False)
- sidak_results = add_statistical_asterisks(sidak_results[sidak_results["p-corr"] < 0.1])
- sidak_results
- # %% [markdown]
- # Since there are no significant differences between WT and EECDTA fish across stimuli, we decided to run Kruskal-Wallis tests to determine stimulus effects per genotype.
- # %%
- # Convert the EECDTA fold change data into a dataframe and copy it to the clipboard.
- aggregate_foldchange_ablated = dict([(k,pd.Series(v)) for k,v in aggregate_foldchange_ablated.items()])
- # Rename the columns of the DataFrame
- df_foldchange_ablated = pd.DataFrame(aggregate_foldchange_ablated)
- df_foldchange_ablated.columns = ["Ctrl", "NaCl", "Glu", "Gly", "Ala"]
- # Print the DataFrame and copy it to the clipboard
- print(df_foldchange_ablated)
- df_foldchange_ablated.to_clipboard()
- # Paste the copied DataFrame into the feeding_behavior_analysis Prism file,
- # data table `EEC-DTA fold change in fluorescence`, for further analysis.
- # %% [markdown]
- # #### Compare fold changes between genotypes
- # %%
- stimulus = 'Glu'
- wt_median = np.median(df_foldchange[stimulus][df_foldchange[stimulus].notnull()])
- eecdta_median = np.median(df_foldchange_ablated[stimulus][df_foldchange_ablated[stimulus].notnull()])
- fold_change_ratio = eecdta_median / wt_median
- print(f"EEC-DTA fold change in fluorescence is {fold_change_ratio} times higher than WT with {stimulus} particles")
- # %%
- stimulus = 'Gly'
- wt_median = np.median(df_foldchange[stimulus][df_foldchange[stimulus].notnull()])
- eecdta_median = np.median(df_foldchange_ablated[stimulus][df_foldchange_ablated[stimulus].notnull()])
- fold_change_ratio = eecdta_median / wt_median
- print(f"EEC-DTA fold change in fluorescence is {fold_change_ratio} times higher than WT with {stimulus} particles")
- # %%
- stimulus = 'Ala'
- wt_median = np.median(df_foldchange[stimulus][df_foldchange[stimulus].notnull()])
- eecdta_median = np.median(df_foldchange_ablated[stimulus][df_foldchange_ablated[stimulus].notnull()])
- fold_change_ratio = eecdta_median / wt_median
- print(f"EEC-DTA fold change in fluorescence is {fold_change_ratio} times higher than WT with {stimulus} particles")
1_feeding_behavior_analysis.ipynb at commit adf1dab, no license · at the source
Overview
- Department of Neurobiology, Duke University School of Medicine, Durham, NC, USA
- Aquaculture Research Institute, University of Maine, Orono, ME, USA
- Department of Cell Biology, Duke University School of Medicine, Durham, NC, USA
- Department of Psychology & Neuroscience, Duke University, Durham, NC, USA
- Department of Biomedical Engineering, Duke University, Durham, NC, USA
Abstract
Animals sense food quantity and quality to regulate feeding behaviors. Enteroendocrine cells (EECs) in the gut epithelium detect luminal distension and nutrients, signaling this information to the brain via vagal sensory neurons. However, how mechanosensory and chemosensory signals are dynamically encoded by gut-brain circuits remains unclear, particularly during early development. Using larval zebrafish, we developed a feeding assay with particles releasing specific nutrients after consumption, demonstrating that EECs regulate nutrient-specific feeding days after gut formation. To determine how post-ingestive signals are encoded along gut-brain circuitry, we developed a microgavage method enabling simultaneous gut stimulation and two-photon imaging. Gut distension alone drove widespread activation and suppression in vagal and dorsal hindbrain neurons. Although nutrient-evoked responses shared temporal features with distension, allyl isothiocyanate elicited slower-onset dynamics. These findings reveal that fast gut-to-brain communication emerges early in life, with distension and aversive chemical cues encoded through distinct temporal dynamics in developing interoceptive circuits.
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 19 matches between paragraphs and lines of code.
gitlab.oit.duke.edu/ean26/arinel-et-al_2026
adf1daba06a24e51cae6960ae9d149413b2a92b5, 23 June 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
7 files
- Analysis/
Figure 1/ , Jupyter, 533 lines, 6 matches1_feeding_behavior_analy sis.ipynb - Analysis/
Figure 2/ , Jupyter, 236 lines, 2 matches1_extract_neurons.ipynb - Analysis/
Figure 2/ , Jupyter, 127 lines2_temporal_analysis.ipyn b - Analysis/
Figure 3/ , Jupyter, 253 lines, 3 matches1_extract_neurons.ipynb - Analysis/
Figure 3/ , Jupyter, 98 lines2_fix_phase.ipynb - Analysis/
Figure 3/ , Jupyter, 713 lines3_vagal_stretch_analysis .ipynb - Analysis/
Figure 3/ , Jupyter, 255 lines, 2 matches4_vagal_alignment.ipynb - repository limit reached (2,000 files or 30 MB): the rest is at the source (24 files)
naumann-lab/caimageanalysis
497918684f1aafd0066b06af651537937eae38d3, 18 December 2023Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
36 files
- angles.py, Python, 97 lines
- bruker_images.py, Python, 332 lines
- constants.py, Python, 113 lines
- examples/
Alignment example.ipynb , Jupyter, 94 lines - examples/
legacy fish to fishy.ipynb , Jupyter, 102 lines - examples/
new_fish_examples.ipynb , Jupyter, 122 lines - examples/
plot_top_n.ipynb , Jupyter, 173 lines - examples/
roi_example.ipynb , Jupyter, 107 lines - fishy.py, Python, 1,738 lines
- old_stuff/
ImageAnalysisCodes/ , Python, 598 linescore.py - old_stuff/
ImageAnalysisCodes/ , Python, 1,653 linessitk_gui.py - old_stuff/
ImageAnalysisCodes/ , Python, 130 linestracking.py - old_stuff/
ImageAnalysisCodes/ , Python, 2,030 linesutils.py - old_stuff/
ImageAnalysisCodes/ , Python, 2,225 linesvisualize.py - old_stuff/
ImageAnalysisCodesV2/ , Python, 167 linesangles.py - old_stuff/
ImageAnalysisCodesV2/ , Python, 22 linesdictionaries.py - old_stuff/
ImageAnalysisCodesV2/ , Python, 1,671 linesmain.py - old_stuff/
ImageAnalysisCodesV2/ , Python, 273 linesstandalone.py - old_stuff/
fish.py , Python, 1,680 lines - old_stuff/
unknown/ , Python, 598 linescore.py - old_stuff/
unknown/ , Python, 2,030 linesutils.py - old_stuff/
unknown/ , Python, 2,226 linesvisualize.py - process.py, Python, 144 lines
- registration/
conductor_alignment_lega , Python, 151 linescy.py - registration/
online_alignment.py , Python, 605 lines - registration/
sitkalignment.py , Python, 584 lines - stimuli.py, Python, 320 lines
- tailtracking.py, Python, 73 lines
- utilities/
arrutils.py , Python, 101 lines - utilities/
misc/ , Python, 161 linesphotostimconfirmation.py - utilities/
pathutils.py , Python, 27 lines - utilities/
roiutils.py , Python, 83 lines - utilities/
volutils.py , Python, 194 lines - utilities/
zmqutils.py , Python, 43 lines - volumes.py, Python, 118 lines
- README.md, Text, 90 lines
Naumann-Lab/alignment
4e5c3f58b3974446581ea5f92bf1c21f6ad3c8db, 16 May 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
9 files
- alignment.py, Python, 171 lines
- notebooks/
hindbrain_alignment.ipyn , Jupyter, 370 linesb - notebooks/
hindbrain_alignment_to_m , Jupyter, 445 lines, 3 matchesapzebrain.ipynb - notebooks/
vagal_alignment.ipynb , Jupyter, 320 lines, 1 match - registration/
conductor_alignment_lega , Python, 151 linescy.py - registration/
online_alignment.py , Python, 605 lines - registration/
sitkalignment.py , Python, 586 lines - LICENSE, License, 21 lines
- README.md, Text, 26 lines
Zenodo 20127931
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
Zenodo 20128341
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
- 27 September 2026: the link answers (HTTP 200)
9 files
- alignment.py, Python, 171 lines
- notebooks/
hindbrain_alignment.ipyn , Jupyter, 370 linesb - notebooks/
hindbrain_alignment_to_m , Jupyter, 445 linesapzebrain.ipynb - notebooks/
vagal_alignment.ipynb , Jupyter, 320 lines - registration/
conductor_alignment_lega , Python, 151 linescy.py - registration/
online_alignment.py , Python, 605 lines - registration/
sitkalignment.py , Python, 586 lines - LICENSE, License, 21 lines
- README.md, Text, 26 lines
arthur-pe/slicetca
61d77c6f8326ab20b2c92f9c9ea7f6e9d9095b36, 7 March 2025Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
25 files
- setup.py, Python, 32 lines
- sliceTCA_notebook_1.ipyn
b , Jupyter, 333 lines - slicetca/
__init__.py , Python, 8 lines - slicetca/
core/ , Python, 3 lines__init__.py - slicetca/
core/ , Python, 333 linesdecompositions.py - slicetca/
core/ , Python, 12 lineshelper_functions.py - slicetca/
invariance/ , Python, 3 lines__init__.py - slicetca/
invariance/ , Python, 38 linesanalytic_invariance.py - slicetca/
invariance/ , Python, 34 linescriteria.py - slicetca/
invariance/ , Python, 52 lineshelper.py - slicetca/
invariance/ , Python, 28 linesinvariance.py - slicetca/
invariance/ , Python, 73 linesiterative_invariance.py - slicetca/
invariance/ , Python, 101 linestransformations.py - slicetca/
plotting/ , Python, 4 lines__init__.py - slicetca/
plotting/ , Python, 1 lineadditional.py - slicetca/
plotting/ , Python, 137 linesfactors.py - slicetca/
plotting/ , Python, 85 linesgrid.py - slicetca/
run/ , Python, 5 lines__init__.py - slicetca/
run/ , Python, 72 lines, 1 matchdecompose.py - slicetca/
run/ , Python, 128 lines, 1 matchgrid_search.py - slicetca/
run/ , Python, 71 linesutils.py - slicetca/
tests/ , Python, 1 line__init__.py - slicetca/
tests/ , Python, 132 linestests.py - LICENSE.txt, License, 21 lines
- README.md, Text, 56 lines
The paper's code and data availability statement is in the Data section.
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:
- 6 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 79 scripts, each with its path and the digest of its content;
- 19 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data and code availability
All data reported in this paper will be shared by the lead contact upon request.
All original code has been deposited at https://
Any additional information required to reanalyze the data reported in this paper is available from the lead contact upon request.
Reproduced under the paper's license (CC BY-NC), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 6 authors, 4 keywords, 6 funders, 165 references, 9 RRIDs.
Cite
This paper
Arinel, M., Atkinson, J. A., Matos-Fernández, K. M., Drage, E. P., Hawkyard, M., & Naumann, E. A. (2026). Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish. iScience, 29(6), 116206. https://
BibTeX
@article{arinel2026gut,
author = {Arinel, Minel and Atkinson, John A and Matos-Fernández, Karina M and Drage, Evan P and Hawkyard, Matt and Naumann, Eva A},
title = {{Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish}},
journal = {iScience},
year = {2026},
month = jun,
volume = {29},
number = {6},
pages = {116206},
publisher = {Elsevier},
issn = {2589-0042},
doi = {10.1016/
url = {https://
pmid = {42325267},
pmcid = {PMC13276583}
}
RIS
TY - JOUR
AU - Arinel, Minel
AU - Atkinson, John A
AU - Matos-Fernández, Karina M
AU - Drage, Evan P
AU - Hawkyard, Matt
AU - Naumann, Eva A
TI - Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish
T2 - iScience
J2 - iScience
PY - 2026
DA - 2026/
VL - 29
IS - 6
SP - 116206
SN - 2589-0042
PB - Elsevier
DO - 10.1016/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1016/
"type": "article-journal",
"title": "Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish",
"container-title": "iScience",
"author": [
{
"family": "Arinel",
"given": "Minel"
},
{
"family": "Atkinson",
"given": "John A"
},
{
"family": "Matos-Fernández",
"given": "Karina M"
},
{
"family": "Drage",
"given": "Evan P"
},
{
"family": "Hawkyard",
"given": "Matt"
},
{
"family": "Naumann",
"given": "Eva A"
}
],
"container-title-short":
"volume": "29",
"issue": "6",
"page": "116206",
"DOI": "10.1016/
"PMID": "42325267",
"PMCID": "PMC13276583",
"ISSN": "2589-0042",
"publisher": "Elsevier",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
11
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s41467-026-76242-8 [code]
- Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish.Journal: Nature communicationsIn common: SimpleITK, tifffile, NetworkX, 7 other tools, zebrafish, systems, 14 references
- [2] doi:10.1016/j.cpblue.2026.100072 [code]
- NodoMap: A single-cell and spatial transcriptomic atlas of the mouse nodose ganglion.Journal: Cell press blueIn common: 13 references
- [3] 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: Pillow, statsmodels, seaborn, 4 other tools, systems, 7 references - [4] doi:10.1126/sciadv.adv3770 [code]
- Evolution of a central dopamine circuit underlies adaptation of a light-evoked sensorimotor response in the blind cavefish.Journal: Science advancesIn common: CaImAn, tifffile, OpenCV, 8 other tools, systems, 1 reference
- [5] doi:10.1016/j.molmet.2026.102371
- A distinct vagus-beta cell neural circuit senses glucose and modulates insulin secretion.Journal: Molecular metabolismIn common: optical imaging (calcium, voltage, 2-photon), 9 references
- [6] doi:10.1038/s41467-026-69633-4 [code]
- Visuomotor decision-making through multifeature convergence in the larval zebrafish hindbrain.Journal: Nature communicationsIn common: Pillow, seaborn, scikit-learn, 4 other tools, zebrafish, 6 references
- [7] doi:10.1111/ejn.70582 [code]
- Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain.Journal: The European journal of neuroscienceIn common: SimpleITK, tifffile, OpenCV, 6 other tools, optical imaging (calcium, voltage, 2-photon), systems, 2 references
- [8] doi:10.1016/j.xpro.2026.104659 [code]
- Protocol for simultaneous in vivo two-photon imaging and locomotion quantification during olfactory stimulation and pharmacology in walking Drosophila.Journal: STAR protocolsIn common: CaImAn, tifffile, OpenCV, 6 other tools, optical imaging (calcium, voltage, 2-photon), 2 references
- [9] doi:10.1371/journal.pcbi.1014571 [code]
- SynAPSeg: A novel dataset and image analysis framework for deep learning-based synapse detection and quantification.Journal: PLoS computational biologyIn common: tifffile, NetworkX, OpenCV, 10 other tools
- [10] doi:10.1364/boe.600665 [code]
- NeuroSeg-MF: robust neuron segmentation in two-photon Ca&
lt;sup& gt;2+& lt;/ sup& gt; imaging using multi-feature fusion and detection-guided SAM. Journal: Biomedical optics expressIn common: tifffile, OpenCV, Pillow, 6 other tools, optical imaging (calcium, voltage, 2-photon), 3 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 6 repositories of the authors' code, each at its verified commit and with its license, 79 scripts, and 19 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:68308cd87d8acde1…
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.
