OSCR

Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish.

Code ↔ Paper

5 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 5 matches
  1. [1] § Methods › Segmentation and time series extraction ↔ src/voluseg/_steps/step4d.py, lines 18–139 · score 0.77 · temporal footprints, matrix factorization, spatial footprints, copy, squares, voxels
  2. [2] § Methods › Gut-responsive cell selection ↔ gutBrainCode/gutBrainPipeline.py, lines 442–530 · score 0.69 · gut pulses, parts model, full model, rank, lag, regression
  3. [3] § Methods › Estimation of imaging resolution ↔ ijplugin/src/ImageDecorrelationAnalysis_.java, lines 314–396 · score 0.67 · ImageJ, ImageDecorrelationAnalysis, plugin, Ng, Nr, resolution
  4. [4] § Results ↔ gutBrain_cellSelection_example.ipynb, lines 54–69 · score 0.57 · motor activity, visual stimulation, UV stimulation, cells, gut, brain
  5. [5] § Methods › Regression analysis ↔ gutBrainCode/gutBrainPipeline.py, lines 622–637 · score 0.52 · ridge regularization strength, vector, matrix, Regression

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 · 788 lines · 30 KB · MIT · 2 matches

  1. # -*- coding: utf-8 -*-
  2. """
  3. Main Code for the gut-brain analysis pipeline
  4. """
  5. import h5py
  6. import numpy as np
  7. import scipy
  8. from scipy.optimize import curve_fit
  9. import matplotlib.pyplot as plt
  10. def windowed_variance(signal, kern_mean=None, kern_var=None, fs=6000):
  11. """
  12. Estimate smoothed sliding variance of the input signal
  13. signal : numpy array
  14. kern_mean : numpy array
  15. kernel to use for estimating baseline
  16. kern_var : numpy array
  17. kernel to use for estimating variance
  18. fs : int
  19. sampling rate of the data
  20. """
  21. from scipy.signal import gaussian, fftconvolve
  22. # set the width of the kernels to use for smoothing
  23. kw = int(0.04 * fs)
  24. if kern_mean is None:
  25. kern_mean = gaussian(kw, kw // 10)
  26. kern_mean /= kern_mean.sum()
  27. if kern_var is None:
  28. kern_var = gaussian(kw, kw // 10)
  29. kern_var /= kern_var.sum()
  30. mean_estimate = fftconvolve(signal, kern_mean, "same")
  31. var_estimate = (signal - mean_estimate) ** 2
  32. fltch = fftconvolve(var_estimate, kern_var, "same")
  33. return fltch, var_estimate, mean_estimate
  34. def load(in_file, num_channels=10, memmap=False):
  35. """Load multichannel binary data from disk, return as a [channels,samples] sized numpy array
  36. """
  37. from numpy import fromfile, float32
  38. if memmap:
  39. from numpy import memmap
  40. data = memmap(in_file, dtype=float32)
  41. else:
  42. with open(in_file, "rb") as fd:
  43. data = fromfile(file=fd, dtype=float32)
  44. trim = data.size % num_channels
  45. # transpose to make dimensions [channels, time]
  46. data = data[: (data.size - trim)].reshape(data.size // num_channels, num_channels).T
  47. if trim > 0:
  48. print("Data needed to be truncated!")
  49. return data
  50. def loadGutBrainData(baseDir:str):
  51. """
  52. Loads gut brain data from a defined path baseDir
  53. INPUTS:
  54. baseDir : path to data
  55. OUTPUTS:
  56. dffTrace, brainMap, VMask, V,W,X,Y,Z,nT
  57. """
  58. #Gather some naming stuff
  59. cellPath = baseDir + "/mika/cells0_clean.hdf5"
  60. metaPath = baseDir +"/ephys/channel_meta.npy"
  61. vName = baseDir + "/mika/volume0.hdf5"
  62. ephysPath = baseDir+'/ephys/eP.26chFlt-v10'
  63. # Load cell time series and ephys data
  64. f = h5py.File(cellPath,'r')
  65. a = h5py.File(vName,'r')
  66. ephysFile = load(ephysPath,26)
  67. ep = np.load(metaPath, allow_pickle = True).item()
  68. #Read data components
  69. F=f['cell_timeseries']
  70. base_f=f['cell_baseline']
  71. X=f['cell_x']
  72. Y=f['cell_y']
  73. Z=f['cell_z']
  74. brainMap=a['volume_mean'][:,:,:].T
  75. VMask=a['volume_mask'][:,:,:].T
  76. V=f['volume_weight']
  77. W=f['cell_weights'][()]
  78. # Pull out some basic aspects of the data
  79. nCells = X.shape[0]
  80. nT = F.shape[1]
  81. # Compute df/f using response time series and baseline
  82. dffTrace=(F[:,:]-base_f[:,:])/(base_f[:,:]-100) #100 is camera backgroud in spim2
  83. return dffTrace, ep, ephysFile,brainMap, VMask, V,W,X,Y,Z,nT,nCells,F
  84. def pullTimes(ephysFile, lsChannel, uvChannel,galvoChannel,thresh):
  85. """Pulls the timing of imaging frames, uv pulses, and galvo positions. Also finds which stacks occur concurrently with the UV
  86. INPUTS:
  87. ephysFile : ch janelia form ephys file
  88. lsChannel : lightsheet channel in ephys file
  89. uvChannel : uv chennel in ephys file
  90. galvoChannel : galvo channel in ephys file
  91. thresh : thresh for detecting changes
  92. OUTPUTS:
  93. stackTimes : stackTimes (in ephys freq)
  94. uvTimes : uv times
  95. badStacks : which stacks occur with uv
  96. endGalvo: where the galvo ended up during the imaging stack"""
  97. lsAbove = np.where(np.append(ephysFile[lsChannel],[thresh+1])>thresh)[0]
  98. stackTimes = lsAbove[np.where(np.diff(lsAbove)>1)[0]]
  99. uvAbove = np.where(np.append(ephysFile[uvChannel],[thresh+1])>thresh)[0]
  100. uvTimes = uvAbove[np.where(np.diff(uvAbove)>1)[0]]
  101. galvoVals = ephysFile[galvoChannel][uvTimes]
  102. whichStack = np.zeros(len(uvTimes))
  103. galvoPos = np.zeros(len(uvTimes))
  104. #if (np.sum(galvoPos)==0):## issue with alignment of uv and lightsheet
  105. # galvoPoses = np.where(ephysFile[galvoChannel]>0)[0]
  106. # galvoVals2 = ephysFile[galvoChannel][galvoPoses]
  107. # for i in range(0,len(uvTimes)):
  108. # galvoVals[i] = galvoVals2[np.where(galvoPoses<uvTimes[i])][-1]
  109. for i in range(0,len(uvTimes)):
  110. if uvTimes[i] < stackTimes[-1]:
  111. whichStack[i] = np.where(stackTimes>uvTimes[i])[0][0]-1
  112. galvoPos[i] = galvoVals[i]
  113. #whichStack[i] = np.where((stacktimes > 2) & (A < 8))
  114. [badStacks, idx] = np.unique(whichStack,return_index=True)
  115. badStacks = badStacks.astype(int)
  116. endGalvo = galvoPos[idx]
  117. return stackTimes, uvTimes, badStacks,endGalvo
  118. def getTrainsTwoTypes(ephysFile,ep,lsChannel,uvChannel,thresh,gutPos,ctrlPos,tailPos,nT):
  119. """Pulls the stim times of useable trials for gut and ctrl
  120. INPUTS:
  121. ephysFile : ch janelia form ephys file
  122. ep : ephys meta file
  123. lsChannel : lightsheet channel in ephys file
  124. uvChannel : uv chennel in ephys file
  125. thresh : threshold for detecting ls imaging frames
  126. gutPos : which integer UV position corresponds to gut pulses
  127. ctrlPos : same as above, but for ctrl
  128. nT : length of time series data
  129. OUTPUTS:
  130. uvOnGut:times of uv gut pulses
  131. uvOffGut: times of uv ctrl pulses
  132. onTrain: times series (nT vector) of uv gut pulses
  133. offTrain: time series (nT vector) of ctrl pulses
  134. sp: swim power
  135. visClosed: closed loop vis
  136. visOpen: open loop vis
  137. visISI: stationary grating
  138. visOpenGut: gut vis
  139. visISIGut: gut isi
  140. visOpenCtrl: ctrl vis
  141. visISICtrl: ctrl isi
  142. """
  143. stackTimes, uvTimes,badStacks,galvo = pullTimes(ephysFile,lsChannel,uvChannel,ep['ch_gpos'],thresh)
  144. uvStackTimes = badStacks[np.where(np.diff(badStacks)>1)[0]]
  145. galvoPos = galvo[np.where(np.diff(badStacks)>1)[0]]
  146. uvOnGut = uvStackTimes[np.where(galvoPos==gutPos)[0]]
  147. uvOffGut = uvStackTimes[np.where(galvoPos==ctrlPos)[0]]
  148. uvOnTail= uvStackTimes[np.where(galvoPos==tailPos)[0]]
  149. if uvOnGut[-1]+50<nT:
  150. uvOnGut=uvOnGut[:-1]
  151. onTrain = np.zeros(nT)
  152. offTrain = np.zeros(nT)
  153. tailTrain = np.zeros(nT)
  154. for i in range(0,len(uvOnGut)):
  155. onTrain[uvOnGut[i]] = 1
  156. for i in range(0,len(uvOffGut)):
  157. offTrain[uvOffGut[i]]=1
  158. for i in range(0,len(uvOnTail)):
  159. tailTrain[uvOnTail[i]]=1
  160. swim1 = ephysFile[0]
  161. swim2 = ephysFile[1]
  162. swimPower1 = windowed_variance(swim1)[0]
  163. swimPower2 = windowed_variance(swim2)[0]
  164. sp = (swimPower1[stackTimes]+swimPower2[stackTimes])/2
  165. vsG = ephysFile[15]
  166. vsV = ephysFile[13]
  167. visISI = np.zeros(len(vsV))
  168. visOpen = np.zeros(len(vsV))
  169. visClosed = np.zeros(len(vsV))
  170. visClosed[np.where((vsG>0) &(vsV>0))[0]]=1 # Closed Loop
  171. visOpen[np.where((vsG==0) &(vsV>0))[0]]=1 # Open Loop
  172. visISI[np.where(vsV==0)[0]]=1 # ISI
  173. visOpen = visOpen[stackTimes]
  174. visClosed = visClosed[stackTimes]
  175. visISI = visISI[stackTimes]
  176. visOpenGut =visClosed.copy()
  177. visISIGut = visISI.copy()
  178. visOpenCtrl = visClosed.copy()
  179. visISICtrl = visISI.copy()
  180. startGutInd = np.where(onTrain>0)[0][0]
  181. endGutInd = np.where(onTrain>0)[0][-1]
  182. visOpenCtrl[startGutInd:endGutInd+1] = 0
  183. visISIGut[:startGutInd-1] = 0
  184. visISIGut[endGutInd+1:] = 0
  185. visOpenGut[:startGutInd-1] = 0
  186. visOpenGut[endGutInd+1:] = 0
  187. visISICtrl[startGutInd:endGutInd+1]=0
  188. isGutPeriod = np.zeros(len(visOpen))
  189. isCtrlPeriod = np.zeros(len(visOpen))
  190. if uvOffGut[0]<uvOnGut[0]:
  191. onFirst = 0
  192. isCtrlPeriod[:uvOnGut[0]]=1
  193. isGutPeriod[uvOnGut[0]:]=1
  194. visGut = visOpen.copy()
  195. visGut*=isGutPeriod
  196. visISIGut = visISI.copy()
  197. visISIGut *=isGutPeriod
  198. visISICtrl = visISI.copy()*isCtrlPeriod
  199. visCtrl = visOpen.copy()*isCtrlPeriod
  200. return uvOnGut,uvOffGut,uvOnTail, onTrain, offTrain,tailTrain,sp,visClosed, visISI,visGut,visISIGut,visISICtrl,visCtrl,visOpen
  201. def getTrains(ephysFile,ep,lsChannel,uvChannel,thresh,gutPos,ctrlPos,nT):
  202. """Pulls the stim times of useable trials for gut and ctrl
  203. INPUTS:
  204. ephysFile : ch janelia form ephys file
  205. ep : ephys meta file
  206. lsChannel : lightsheet channel in ephys file
  207. uvChannel : uv chennel in ephys file
  208. thresh : threshold for detecting ls imaging frames
  209. gutPos : which integer UV position corresponds to gut pulses
  210. ctrlPos : same as above, but for ctrl
  211. nT : length of time series data
  212. OUTPUTS:
  213. uvOnGut:times of uv gut pulses
  214. uvOffGut: times of uv ctrl pulses
  215. onTrain: times series (nT vector) of uv gut pulses
  216. offTrain: time series (nT vector) of ctrl pulses
  217. sp: swim power
  218. visClosed: closed loop vis
  219. visOpen: open loop vis
  220. visISI: stationary grating
  221. visOpenGut: gut vis
  222. visISIGut: gut isi
  223. visOpenCtrl: ctrl vis
  224. visISICtrl: ctrl isi
  225. """
  226. stackTimes, uvTimes,badStacks,galvo = pullTimes(ephysFile,lsChannel,uvChannel,ep['ch_gpos'],thresh)
  227. uvStackTimes = badStacks[np.where(np.diff(badStacks)>1)[0]]
  228. galvoPos = galvo[np.where(np.diff(badStacks)>1)[0]]
  229. uvOnGut = uvStackTimes[np.where(galvoPos!=ctrlPos)[0]]
  230. uvOffGut = uvStackTimes[np.where(galvoPos==ctrlPos)[0]]
  231. if uvOnGut[-1]-50>nT:
  232. uvOnGut=uvOnGut[:-1]
  233. onTrain = np.zeros(nT)
  234. offTrain = np.zeros(nT)
  235. for i in range(0,len(uvOnGut)):
  236. onTrain[uvOnGut[i]] = 1
  237. for i in range(0,len(uvOffGut)):
  238. offTrain[uvOffGut[i]]=1
  239. swim1 = ephysFile[0]
  240. swim2 = ephysFile[1]
  241. swimPower1 = windowed_variance(swim1)[0]
  242. swimPower2 = windowed_variance(swim2)[0]
  243. sp = (swimPower1[stackTimes]+swimPower2[stackTimes])/2
  244. vsG = ephysFile[15]
  245. vsV = ephysFile[13]
  246. visISI = np.zeros(len(vsV))
  247. visOpen = np.zeros(len(vsV))
  248. visClosed = np.zeros(len(vsV))
  249. visClosed[np.where((vsG>0) &(vsV>0))[0]]=1 # Closed Loop
  250. visOpen[np.where((vsG==0) &(vsV>0))[0]]=1 # Open Loop
  251. visISI[np.where(vsV==0)[0]]=1 # ISI
  252. visOpen = visOpen[stackTimes]
  253. visClosed = visClosed[stackTimes]
  254. visISI = visISI[stackTimes]
  255. visOpenGut =visClosed.copy()
  256. visISIGut = visISI.copy()
  257. visOpenCtrl = visClosed.copy()
  258. visISICtrl = visISI.copy()
  259. startGutInd = np.where(onTrain>0)[0][0]
  260. endGutInd = np.where(onTrain>0)[0][-1]
  261. visOpenCtrl[startGutInd:endGutInd+1] = 0
  262. visISIGut[:startGutInd-1] = 0
  263. visISIGut[endGutInd+1:] = 0
  264. visOpenGut[:startGutInd-1] = 0
  265. visOpenGut[endGutInd+1:] = 0
  266. visISICtrl[startGutInd:endGutInd+1]=0
  267. isGutPeriod = np.zeros(len(visOpen))
  268. isCtrlPeriod = np.zeros(len(visOpen))
  269. visGut = visOpen.copy()
  270. visGut*=isGutPeriod
  271. visISIGut = visISI.copy()
  272. visISIGut *=isGutPeriod
  273. visISICtrl = visISI.copy()*isCtrlPeriod
  274. visCtrl = visOpen.copy()*isCtrlPeriod
  275. return uvOnGut,uvOffGut, onTrain, offTrain,sp,visClosed, visISI,visGut,visISIGut,visISICtrl,visCtrl,visOpen
  276. def shift(xs, n):
  277. """Helper fucntion to construct shifted time series. pads with zeros.
  278. Inputs:
  279. xs : time series
  280. n : shift degree
  281. Outputs:
  282. e: shifted time series"""
  283. e = np.empty_like(xs)
  284. if n >= 0:
  285. e[:n] = 0
  286. e[n:] = xs[:-n]
  287. else:
  288. e[n:] = 0
  289. e[:n] = xs[-n:]
  290. return e
  291. class fusedLoocv:
  292. """Runs 'Fused' regression with LOOCV.
  293. INPUTS (init):
  294. order : length of longest lag period (for gut and ctrl UV)
  295. lambdaRidge : ridge penalty
  296. lambdaSmooth : smoothing penalty
  297. INPUTS (running models):
  298. cellData: nCell x nT matrix of cell data
  299. fullReg: nT x nDim matrix of regression data for the full model
  300. fullType: nDim vector of lag orders for the full model
  301. partReg: nT x nDim matrix of regression data for the part model
  302. partType: nDim vector of lag orders for the part model
  303. trialTimes: gut pulse times"""
  304. def __init__(self,order,lambdaRidge,lambdaSmooth):
  305. "Init"
  306. self.order = order
  307. self.lambdaRidge = lambdaRidge
  308. self.lambdaSmooth = lambdaSmooth
  309. def constructLag(self,toReg,n):
  310. """Constructs lag matrix for regression for a single dimension
  311. INPUTS:
  312. toReg : vector of data to shift
  313. n : shift order
  314. OTUPUTS:
  315. xMat : lag matrix for a single dimension"""
  316. xMat = np.zeros((len(toReg),n))
  317. xMat[:,0] = toReg
  318. for i in range(1,n):
  319. xMat[:,i] = shift(toReg,i)
  320. return xMat
  321. def makeInputMats(self,testReg,trainReg,typeVec):
  322. """Constructs the lag regression matrix from individual regression vectors
  323. INPUTS:
  324. testReg : regression matrix for testing
  325. trainReg : regression matrix for training
  326. typeVec : vector of lag orders for testReg and trainReg
  327. OUTPUTS:
  328. trainXMat : final regression matrix for training of size (nT x sum(typeVec)+1)
  329. testXMat : same as above for testing"""
  330. trainXMat = []
  331. testXMat = []
  332. if trainReg.ndim>1:
  333. for i in range(0,len(trainReg)):
  334. if typeVec[i]>1:
  335. trainXMat.append(self.constructLag(trainReg[i,:],typeVec[i]))
  336. testXMat.append(self.constructLag(testReg[i,:],typeVec[i]))
  337. else:
  338. temp = np.zeros((trainReg.shape[1],1))
  339. temp2 = np.zeros((testReg.shape[1],1))
  340. temp[:,0] = trainReg[i,:]
  341. temp2[:,0] = testReg[i,:]
  342. trainXMat.append(temp)
  343. testXMat.append(temp2)
  344. else:
  345. trainXMat.append(self.constructLag(trainReg,typeVec[0]))
  346. testXMat.append(self.constructLag(testReg,typeVec[0]))
  347. trainXMat = np.hstack(trainXMat)
  348. testXMat = np.hstack(testXMat)
  349. return trainXMat, testXMat
  350. def makePsiMats(self,fullType,partType):
  351. """Construct Psi matrices (difference matrices + ridge matrices)
  352. INPUTS:
  353. fullType: vector of lag orders for the full model
  354. partType : vector of lag orders for the part model"""
  355. fullD = np.zeros((np.sum(fullType),np.sum(fullType)))
  356. partD = np.zeros((np.sum(partType),np.sum(partType)))
  357. testD = np.zeros((self.order,self.order))
  358. for i in range(1,self.order-1):
  359. testD[i,i] = 2
  360. testD[i-1,i]=-1
  361. testD[i+1,i] = -1
  362. testD[0,0] = 1
  363. testD[1,0] = -1
  364. testD[self.order-1,self.order-1]=1
  365. testD[self.order-2,self.order-1]=-1
  366. fullD[:self.order,:self.order] = testD
  367. fullD[self.order:2*self.order,self.order:2*self.order] = testD
  368. partD[:self.order,:self.order] = testD
  369. fullD = np.dot(fullD.T,fullD)*self.lambdaSmooth+ np.eye(np.sum(fullType))*self.lambdaRidge
  370. partD=np.dot(partD.T,partD)*self.lambdaSmooth + np.eye(np.sum(partType))*self.lambdaRidge
  371. return fullD,partD
  372. def runBothModels(self,cellData,fullReg,fullType,partReg,partType,trialTimes):
  373. """Run the model
  374. INPUTS:
  375. cellData : nCell x nT matrix of cell data
  376. fullReg : raw regression data for the full model (nT x nDim)
  377. partReg : same, but for the part model
  378. fullType: vector of lag orders for hte full model
  379. partType: same, but for part model
  380. trialTimes : times for UV gut pulses for LOOCV
  381. OUTPUTS:
  382. betaHats : full coefficient matrix of model for full model (nDim x nTrials x nCell)
  383. betaHats2 : same as above, but for the part model
  384. yHats: yHat data for full model (nT x nTrials x nCells)
  385. yHats2 : same as above for part model
  386. allY : true data (nT x nTrials x nCells)
  387. rmse : rmse matrix for model 1
  388. rmse2 : rmse for model2
  389. corr : corr for model 1
  390. corr2 : corr for model2
  391. data : data used in regression
  392. reg1 : reg mat for 1
  393. reg2 :
  394. type1 : lag orders for 1
  395. type2 : lag order for 2
  396. """
  397. self.reg1 = fullReg
  398. self.reg2 = partReg
  399. self.typ1 = fullType
  400. self.type2 = partType
  401. self.trialTimes= trialTimes
  402. nCells = len(cellData)
  403. fullRMSE = np.zeros((len(trialTimes),len(cellData)))
  404. partRMSE = np.zeros((len(trialTimes),len(cellData)))
  405. fullCorr = np.zeros((len(trialTimes),len(cellData)))
  406. partCorr = np.zeros((len(trialTimes),len(cellData)))
  407. allFullBetaHats = np.zeros((np.sum(fullType),len(trialTimes),nCells))
  408. allPartBetaHats = np.zeros((np.sum(partType),len(trialTimes),nCells))
  409. allFullYHats = np.zeros((self.order+10,len(trialTimes),nCells))
  410. allPartYHats = np.zeros((self.order+10,len(trialTimes),nCells))
  411. allY = np.zeros((self.order+10,len(trialTimes),nCells))
  412. ## Get Psi
  413. fullPsi, partPsi = self.makePsiMats(fullType,partType)
  414. for i in range(0,len(trialTimes)): # Loop over trials
  415. print('Running trial '+ str(i+1) +' of '+ str(len(trialTimes)+1))
  416. toDel = np.arange(trialTimes[i]-10,trialTimes[i]+self.order,1)
  417. trainData = np.delete(cellData.copy(),toDel,axis=1)
  418. testData = cellData[:,trialTimes[i]-10:trialTimes[i]+self.order]
  419. fullTrainReg = np.delete(fullReg.copy(),toDel,axis=1)
  420. fullTestReg = fullReg[:,trialTimes[i]-10:trialTimes[i]+self.order]
  421. toDelPart = np.arange(trialTimes[i]-10,trialTimes[i]+self.order,1)
  422. trainDataPart = np.delete(cellData.copy(),toDelPart,axis=1)
  423. if partReg.ndim >1:
  424. partTrainReg = np.delete(partReg.copy(),toDelPart,axis=1)
  425. partTestReg = partReg[:,trialTimes[i]-10:trialTimes[i]+self.order]
  426. else:
  427. partTrainReg =np.delete(partReg.copy(),toDelPart)
  428. partTestReg = partReg[trialTimes[i]-10:trialTimes[i]+self.order]
  429. fullTrainX, fullTestX = self.makeInputMats(fullTestReg,fullTrainReg,fullType)
  430. partTrainX, partTestX = self.makeInputMats(partTestReg,partTrainReg,partType)
  431. fullBetaHat = np.dot(np.linalg.inv(np.dot(fullTrainX.T,fullTrainX)+fullPsi),np.dot(fullTrainX.T,trainData.T))
  432. partBetaHat = np.dot(np.linalg.inv(np.dot(partTrainX.T,partTrainX)+partPsi),np.dot(partTrainX.T,trainDataPart.T))
  433. fullYHat = np.dot(fullTestX,fullBetaHat)
  434. partYHat = np.dot(partTestX,partBetaHat)
  435. allFullBetaHats[:,i,:] = fullBetaHat
  436. allPartBetaHats[:,i,:] = partBetaHat
  437. allFullYHats[:,i,:] = fullYHat
  438. allPartYHats[:,i,:] = partYHat
  439. allY[:,i,:] = testData.T
  440. fullRMSE[i,:] = np.mean(np.sqrt((fullYHat-testData.T)**2),axis=0)
  441. partRMSE[i,:] = np.mean(np.sqrt((partYHat-testData.T)**2),axis=0)
  442. fullCorr[i,:] = corr(fullYHat,testData.T)#c(rankY, rankFull)
  443. partCorr[i,:] = corr(partYHat,testData.T)#c(rankY,rankPart)
  444. self.betaHats = allFullBetaHats
  445. self.betaHats2 = allPartBetaHats
  446. self.yHats = allFullYHats
  447. self.yHats2 = allPartYHats
  448. self.allY = allY
  449. self.rmse = fullRMSE
  450. self.rmse2 = partRMSE
  451. self.corr = fullCorr
  452. self.corr2 = partCorr
  453. self.data = cellData
  454. def corr(a,b):
  455. """Fast row-wise correlation between two matrices of same size"""
  456. p1 = a-np.mean(a,axis=0)
  457. p2 = b-np.mean(b,axis=0)
  458. num = np.mean(p1*p2,axis=0)
  459. p3 = np.std(a,axis=0)
  460. p4 = np.std(b,axis=0)
  461. den = p3*p4
  462. c = num/den
  463. return c
  464. def pullCells(mod,thresh:float,pThresh: float,prePulseInds: int, postPulseInds: int,uvOnGut,uvOffGut):
  465. """Pulls gut-related cells
  466. INPUTS:
  467. mod : the regression class
  468. thresh : correlation threshold (full) for pulling cells
  469. pThresh : alpha value for comparing parts and full models
  470. OUTPUTS:
  471. firstPass : cells with corr > thresh
  472. secondPass : firstPass AND better corr for full model than parts
  473. thridPass : secondPass AND better rmse for full model than parts"""
  474. # Pull cells with mean corr > thresh
  475. mnCorr = np.mean(mod.corr,axis=0)
  476. firstPass = np.where(mnCorr>thresh)[0]
  477. #Pull cells with statistically better corr to full than parts
  478. secondPassP = np.zeros(len(firstPass))
  479. firstPassFull = mod.corr[:,firstPass]
  480. firstPassParts = mod.corr2[:,firstPass]
  481. for i in range(0,len(firstPass)):
  482. d= firstPassFull[:,i]-firstPassParts[:,i]
  483. secondPassP[i] = scipy.stats.wilcoxon(d,alternative = 'greater')[1]
  484. secondPass = firstPass[np.where(secondPassP<pThresh)[0]]
  485. pValues = secondPassP[np.where(secondPassP<pThresh)[0]]
  486. testDFF = mod.data[secondPass,:]
  487. onPulseResponse = np.zeros((postPulseInds+prePulseInds,len(secondPass),len(uvOnGut)))
  488. offPulseResponse = np.zeros((postPulseInds+prePulseInds,len(secondPass),len(uvOffGut)))
  489. for i in range(0,len(uvOnGut)):
  490. onPulseResponse[:,:,i] = testDFF[:,uvOnGut[i]-prePulseInds:uvOnGut[i]+postPulseInds].T
  491. for i in range(0,len(uvOffGut)):
  492. offPulseResponse[:,:,i] = testDFF[:,uvOffGut[i]-prePulseInds:uvOffGut[i]+postPulseInds].T
  493. rankP = np.zeros(len(secondPass))
  494. for i in range(0,len(secondPass)):
  495. rankP[i] = scipy.stats.ranksums(np.max(onPulseResponse[:18,i,:],axis=0),np.max(offPulseResponse[:18,i,:],axis=0))[1]
  496. thirdPass = secondPass[np.where(rankP<pThresh)[0]]
  497. rankP = rankP[np.where(rankP<pThresh)[0]]
  498. return firstPass, secondPass,thirdPass, pValues, rankP
  499. def pullCellMasks(W,V,X,Y,Z,whichCells):
  500. """Pulls masks for making brain maps
  501. INPUTS:
  502. W,V,W,Y,Z : outputs from Mika's pipeline
  503. whichCells : which cells to mask (gut-sensitive)
  504. OUTPUTS:
  505. maskAll : masks for brain map"""
  506. maskW = np.zeros(V.shape)
  507. ww = W[whichCells]
  508. for i in (range(0,len(whichCells))):
  509. ww = W[whichCells[i]]
  510. xx,yy,zz = X[whichCells[i]],Y[whichCells[i]],Z[whichCells[i]]
  511. maskW[xx,yy,zz] = np.maximum(maskW[xx,yy,zz],ww)
  512. maskW =np.ma.masked_where((maskW ==0), maskW)
  513. return maskW
  514. def makeBrainMap(brainMap,maskAll):
  515. """Makes a quick brain map from selected cells
  516. INPUTS:
  517. brainMap : map from Mika's pipeline
  518. maskAll : selected cell Mask
  519. OUTPUTS:
  520. NA"""
  521. plt.figure(figsize=(10, 10))
  522. fig, axs = plt.subplots(nrows=1, ncols=2, sharex='col',figsize=(18, 10 ))
  523. ax_im1 = axs[0]
  524. ax_im2 = axs[1]
  525. im1_m=ax_im1.imshow(brainMap[:,:,:-1].max(axis=2).T, vmin=100,vmax=np.percentile(brainMap[:].squeeze(), 99.98),cmap='gray')
  526. im1_0 = ax_im1.imshow(maskAll[:,:,:-1].max(axis=2).T, cmap='magma',alpha=0.5,vmin=0,vmax=0.0025)
  527. im2_m=ax_im2.imshow(np.flip(brainMap[:,:,:-1].max(axis=1).T,axis=0), cmap='gray',vmin =100, vmax=np.percentile(brainMap[:].squeeze(), 99.98),aspect=6,interpolation='nearest')
  528. im2=ax_im2.imshow(np.flip(maskAll[:,:,:-1].max(axis=1).T,axis=0), vmin = 0,vmax=0.005,cmap='magma',alpha=0.5,aspect=6,interpolation='nearest')
  529. def fusedRidge(y,toReg,orderVec,lambdaRidge,lambdaSmooth):
  530. """Runs the fused ridge regression
  531. INPUTS:
  532. y : matrix (nCells x nT) of neural data
  533. toReg : matrix (nRegressors x nT) of regressor data
  534. orderVec : vector (of size nRegressors) of lag orders
  535. lambdaRidge : ridge regularization strength
  536. lambdaSmooth : smooth regularization strength
  537. OUTPUTS:
  538. betaHat : matrix (sum(orderVec) x nCells)
  539. yHat : matrix (nT x nCells) of predicted data"""
  540. psiMat = makePsiMat(orderVec,2,10) # construct psi matrix
  541. xMat = makeInputMat(toReg,orderVec) #
  542. betaHat = np.dot(np.linalg.inv(np.dot(xMat.T,xMat)+psiMat),np.dot(xMat.T,y.T))
  543. yHat = np.dot(xMat,betaHat)
  544. return betaHat, yHat,xMat
  545. ############################ Fused Ridge Helper Functions #################
  546. def constructLag(toReg,n):
  547. """Constructs lag matrix for regression for a single dimension
  548. INPUTS:
  549. toReg : vector of data to shift
  550. n : shift order
  551. OTUPUTS:
  552. xMat : lag matrix for a single dimension"""
  553. xMat = np.zeros((len(toReg),n))
  554. xMat[:,0] = toReg
  555. for i in range(1,n):
  556. xMat[:,i] = shift(toReg,i)
  557. return xMat
  558. def makePsiMat(orderVec,lambdaRidge,lambdaSmooth):
  559. """ Constructs Psi Matrix (difference matrix + ridge matrix)
  560. INPUTS:
  561. orderVec : vector of lag orders
  562. OUTPUTS:
  563. psiMat : psi matrix"""
  564. psiMat = np.zeros((np.sum(orderVec),np.sum(orderVec)))
  565. psiMat[:orderVec[0],:orderVec[0]] = makeSinglePsiMat(orderVec[0])
  566. if len(orderVec)>1:
  567. for i in range(1,len(orderVec)-1):
  568. psiMat[np.sum(orderVec[:i]):np.sum(orderVec[:i+1]),np.sum(orderVec[:i]):np.sum(orderVec[:i+1])]= makeSinglePsiMat(orderVec[i])
  569. psiMat[np.sum(orderVec[:-1]):np.sum(orderVec),np.sum(orderVec[:-1]):np.sum(orderVec)]= makeSinglePsiMat(orderVec[-1])
  570. psiMat = psiMat * lambdaSmooth + np.eye(np.sum(orderVec))*lambdaRidge
  571. return psiMat
  572. def makeSinglePsiMat(orderScal):
  573. """Constructs a single D difference matrix
  574. INPUTS:
  575. orderScal : scalar of the lag order
  576. OUTPUTS:
  577. partPsi : single D matrix"""
  578. partPsi = np.zeros((orderScal,orderScal))
  579. for i in range(1,orderScal-1):
  580. partPsi[i,i] = 2
  581. partPsi[i-1,i] = -1
  582. partPsi[i+1,i] = -1
  583. partPsi[0,0] = 1
  584. partPsi[1,0] = -1
  585. partPsi[orderScal-1][orderScal-1]=1
  586. partPsi[orderScal-2][orderScal-1]=-1
  587. return partPsi
  588. def makeInputMat(toReg,orderVec):
  589. """Constructs the lag regression matrix from individual regression vectors
  590. INPUTS:
  591. toReg : regression matrix for training
  592. orderVec : vector of lag orders for testReg and trainReg
  593. OUTPUTS:
  594. xMat : final regression matrix for training of size (nT x sum(typeVec)+1)"""
  595. xMat =[]
  596. if toReg.ndim>1: #there are more than one regression time series
  597. for i in range(0,len(toReg)):
  598. if orderVec[i]>1:
  599. xMat.append(constructLag(toReg[i,:],orderVec[i]))
  600. else:
  601. temp = np.zeros((len(toReg[i,:]),1))
  602. temp[:,0] = toReg[i,:]
  603. xMat.append(temp)
  604. else:
  605. xMat.append(constructLag(toReg,orderVec[0]))
  606. return np.hstack(xMat)
  607. ############################ Fused Ridge Output Analysis Functions #################
  608. def gaus(x,a,x0,sigma):
  609. """Normal distribution function, used for curve fitting"""
  610. return a*np.exp(-(x-x0)**2/(2*sigma**2))
  611. def halfGaus(x,x0,sigma):
  612. """Normal distribution function, used for curve fitting"""
  613. return np.sqrt(2)/(np.sqrt(np.pi)*sigma)* np.exp(-(x-x0)**2/(2*sigma**2))
  614. def fitLeftGetThresh(corrs,stdThresh):
  615. """Estimates a correlation threshold for significantly correlated data. Relies upon
  616. fitting the left hand side of a normal distribution (relative to mode) for an estimate
  617. of noise variance
  618. INPUTS:
  619. corrs : vector of corr coefs
  620. stdThresh : threshold on STD for estimate (probabilities related to z-score"""
  621. counts, bins,bars= plt.hist(corrs,density=True,bins=100,alpha = .6,label = "Full")
  622. mode = bins[np.where(counts==np.max(counts))]+ (bins[1]-bins[0])/2
  623. leftDat = corrs[np.where(corrs<mode)[0]]
  624. countsL,binsL,barsL = plt.hist(leftDat,density=True,bins=100,alpha = .6,label = "Full")
  625. popt,pcov = curve_fit(halfGaus,binsL[:-1],countsL,p0=None, sigma=None)
  626. plt.plot(bins,halfGaus(bins,popt[0],popt[1]))
  627. thresh = popt[0]+(np.abs(popt[1])*stdThresh)
  628. plt.plot([thresh,thresh],[0,1])
  629. return thresh, popt[0],popt[1]
  630. def pullAverages(dffTrace,uvOnGut,uvOffGut,preTime,postTime):
  631. """Pulls average and se gut and ctrl pulses"""
  632. gutResponses = np.zeros((len(dffTrace),postTime+preTime,len(uvOnGut)))
  633. ctrlResponses = np.zeros((len(dffTrace),postTime+preTime,len(uvOffGut)))
  634. for i in range(0,len(uvOnGut)):
  635. gutResponses[:,:,i] = dffTrace[:,int(uvOnGut[i]-preTime):int(uvOnGut[i]+postTime)]
  636. for i in range(0,len(uvOffGut)):
  637. ctrlResponses[:,:,i] = dffTrace[:,int(uvOffGut[i]-preTime):int(uvOffGut[i]+postTime)]
  638. aveGutResponse = np.mean(gutResponses,axis=2)
  639. seGutResponse = np.std(gutResponses,axis=2)/np.sqrt(len(uvOnGut))
  640. aveCtrlResponse = np.mean(ctrlResponses,axis=2)
  641. seCtrlResponse = np.std(ctrlResponses,axis=2)/np.sqrt(len(uvOffGut))
  642. return aveGutResponse, seGutResponse,aveCtrlResponse,seCtrlResponse
  643. def meanAndSE(mat,trigs,preTime,postTime):
  644. trialResponses = np.zeros((len(mat),postTime+preTime,len(trigs)))
  645. for i in range(0,len(trigs)):
  646. trialResponses[:,:,i] = mat[:,trigs[i]-preTime:trigs[i]+postTime]
  647. trialMeans = np.mean(trialResponses,axis=2)
  648. trialSEs = np.std(trialResponses,axis=2)/np.sqrt(len(trigs))
  649. return trialResponses, trialMeans, trialSEs
  650. def pullCenters(X,Y,Z):
  651. """Pulls the mean X, Y, and Z coordinates for a set of cells
  652. INPUTS:
  653. X,Y,Z : mats of loc data
  654. outPuts:
  655. cellCenters : mean X,Y, and Z locations for each cell in X,Y,Z"""
  656. cellCenters = np.zeros((len(X),3))
  657. for i in range(0,len(X)):
  658. cellCenters[i,:] = pullLocs(X[i],Y[i],Z[i])
  659. return cellCenters
  660. def pullLocs(X,Y,Z):
  661. """Computes mean locs from data
  662. INPUTS:
  663. X,Y,Z : mats of loc data
  664. outPuts:
  665. xG,yG,zG : mean locs of cells
  666. """
  667. xx = X
  668. yy = Y
  669. zz = Z
  670. xG = np.mean(xx[np.where(xx>=0)[0]])
  671. yG = np.mean(yy[np.where(yy>=0)[0]])
  672. zG = np.mean(zz[np.where(zz>=0)[0]])
  673. return xG, yG,zG

gutBrainPipeline.py at commit 4c62612, under MIT · at the source

Overview

Authors: Weiyu Chen1, Ben James1,2, Virginie M. S. Ruetten1,3, Sambashiva Banala1, Ziqiang Wei1, Xueying Yang1, Greg Fleishman1, Igor Siwanowicz1, Mikail Rubinov4, Jeremy Delahanty1, Mark C. Fishman5, Florian Engert6, Maneesh Sahani3, Luke D. Lavis1, James E. Fitzgerald1,2,7, Misha B. Ahrens1
  1. Janelia Research Campus, Howard Hughes Medical Institute,Ashburn, VA USA
  2. Department of Neurobiology, Northwestern University,Evanston, IL USA
  3. Gatsby Computational Neuroscience Unit, University College London,London, UK
  4. Department of Biomedical Engineering, Vanderbilt, Nashville, TN USA
  5. Harvard Stem Cell Institute, Harvard University,Cambridge, MA USA
  6. Department of Molecular and Cellular Biology, Harvard University,Cambridge, MA USA
  7. NSF-Simons National Institute for Theory and Mathematics in Biology, Chicago, IL USA
Institutions: Howard Hughes Medical Institute (United States); Northwestern University (United States); University College London (United Kingdom); Vanderbilt University (United States); Harvard University (United States)
Journal: Nature communications, volume 17, issue 1, article 9881
Dates: received 31 December 2025; accepted 24 July 2026; published online 27 August 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41467-026-76242-8 · PMID 42749707 · PMCID PMC13583002 · OpenAlex W7204453203
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: zebrafish (organism), systems (subfield)
Methods: Spectral & time-frequency, Statistics, Machine learning, Connectivity, Graphs, fMRI & imaging, Single-unit activity, calcium imaging
Keywords: Neuroscience, Physiology, Neural circuits, Peripheral nervous system
MeSH: Brain*, Gastrointestinal Tract*, Neurons*, Zebrafish*, Amino Acids, Animals, Glucose, Larva, Photic Stimulation, Swimming (* major topic)
Topic: Zebrafish Biomedical Research Applications (Cell Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: Howard Hughes Medical Institute (HHMI); NSF (DMS-2235451); Simons Foundation (MPTMPS-00005320)
Citations: not cited yet (Europe PMC); 96 references in the paper

Abstract

To select behaviors appropriate to their circumstances and needs, animals integrate information about the external environment with information about the state of their bodies, derived from sensing and processing internal signals (interoception). However, the brain-wide circuit activity underlying interoception and its integration with sensorimotor processing remains unclear, partly because of technical barriers to accessing whole-brain activity at the cellular level during physiological perturbations. We developed an all-optical system for whole-brain neuronal imaging in behaving larval zebrafish during optical uncaging of gut- or bloodstream-targeted nutrients and visuo-motor stimulation. Widespread neural activity throughout the brain encoded nutrient delivery, unfolding on multiple timescales across many peripheral and central regions. Evoked activity depended on delivery location and occurred in response to both amino acids and D-glucose, but not L-glucose. Many gut responsive neurons also responded to swimming and visual stimuli, with brainstem areas primarily integrating gut and motor signals and midbrain regions integrating jointly gut, visual, and motor signals. This platform links body-brain communication studies to brain-wide neural computation in awake, behaving vertebrates.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.

benJames1212/gutBrainPipeline

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 4c62612ecd540ec786c43fe9ce67cc78259a6ec1, 27 May 2026
Languages: Python (4), Jupyter (1)
Size: 7 files, 5 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, 1 notebook
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (4 files), Matplotlib (3 files), SciPy (2 files), h5py (1 file), tifffile (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
7 files

mikarubi/voluseg

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 55c619d7de0f56f303ae0f64e9eaa11cdd6819c9, 3 September 2026
Languages: Python (38), JavaScript (5)
Size: 156 files, 43 scripts
Software Heritage: archived
Found in: the text, “Microgavage”
Holds: README, license file, environment (Dockerfile, pyproject.toml, requirements-docker.txt, requirements.txt, docs/requirements-docs.txt, tests/requirements.txt, iac/aws_batch/requirements-dev.txt, iac/aws_batch/requirements.txt), tests, continuous integration, documentation
Not found: CITATION.cff
Tools: NumPy (21 files), h5py (10 files), SciPy (6 files), scikit-image (3 files), NiBabel (2 files), scikit-learn (2 files), Matplotlib (1 file), Neurodata Without Borders (PyNWB, MatNWB) (1 file), pandas (1 file), tifffile (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
45 files

ades91/imdecorr

License: GPL-3.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: db536a36d12db95f5e4ea6c8644144a10cc42646, 23 April 2021
Languages: MATLAB (16), Java (4)
Size: 36 files, 20 scripts
Software Heritage: not archived
Found in: the text, “Microgavage”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
22 files

JaneliaSciComp/bigstream

License: BSD-3-Clause
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 3dd1d66cfda0529669d416f20fed676f183fcaa5, 13 July 2026
Languages: Jupyter (30), Python (28)
Size: 446 files, 58 scripts
Software Heritage: not archived
Found in: the text, “Construction of brain maps”
Holds: README, license file, environment (conda-env.yaml, Dockerfile, pyproject.toml, setup.py), 30 notebooks
Not found: CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (52 files), h5py (27 files), SciPy (22 files), SimpleITK (6 files), tifffile (4 files), scikit-image (3 files), OpenCV (2 files), NetworkX (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
60 files

Code availability

All original code has been deposited at GitHub and is publicly available: https://github.com/benJames1212/gutBrainPipeline. 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), from the paper cited above.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 4 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 126 scripts, each with its path and the digest of its content;
  • 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability

All datasets are deposited to Figshare: https://doi.org/10.25378/janelia.31967640.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 16 authors, 4 keywords, 10 MeSH terms, 3 funders, 95 references.

Cite

This paper

Chen, W., James, B., Ruetten, V. M. S., Banala, S., Wei, Z., Yang, X., Fleishman, G., Siwanowicz, I., Rubinov, M., Delahanty, J., Fishman, M. C., Engert, F., Sahani, M., Lavis, L. D., Fitzgerald, J. E., & Ahrens, M. B. (2026). Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish. Nature communications, 17(1), 9881. https://doi.org/10.1038/s41467-026-76242-8

BibTeX

@article{chen2026whole,
author = {Chen, Weiyu and James, Ben and Ruetten, Virginie M. S. and Banala, Sambashiva and Wei, Ziqiang and Yang, Xueying and Fleishman, Greg and Siwanowicz, Igor and Rubinov, Mikail and Delahanty, Jeremy and Fishman, Mark C. and Engert, Florian and Sahani, Maneesh and Lavis, Luke D. and Fitzgerald, James E. and Ahrens, Misha B.},
title = {{Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish}},
journal = {Nature communications},
year = {2026},
month = aug,
volume = {17},
number = {1},
pages = {9881},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-76242-8},
url = {https://doi.org/10.1038/s41467-026-76242-8},
pmid = {42749707},
pmcid = {PMC13583002}
}

RIS

TY - JOUR
AU - Chen, Weiyu
AU - James, Ben
AU - Ruetten, Virginie M. S.
AU - Banala, Sambashiva
AU - Wei, Ziqiang
AU - Yang, Xueying
AU - Fleishman, Greg
AU - Siwanowicz, Igor
AU - Rubinov, Mikail
AU - Delahanty, Jeremy
AU - Fishman, Mark C.
AU - Engert, Florian
AU - Sahani, Maneesh
AU - Lavis, Luke D.
AU - Fitzgerald, James E.
AU - Ahrens, Misha B.
TI - Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/08/27
VL - 17
IS - 1
SP - 9881
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-76242-8
UR - https://doi.org/10.1038/s41467-026-76242-8
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-76242-8",
"type": "article-journal",
"title": "Whole-brain, all-optical interrogation of neuronal dynamics underlying gut and vascular interoception in zebrafish",
"container-title": "Nature communications",
"author": [
{
"family": "Chen",
"given": "Weiyu"
},
{
"family": "James",
"given": "Ben"
},
{
"family": "Ruetten",
"given": "Virginie M. S."
},
{
"family": "Banala",
"given": "Sambashiva"
},
{
"family": "Wei",
"given": "Ziqiang"
},
{
"family": "Yang",
"given": "Xueying"
},
{
"family": "Fleishman",
"given": "Greg"
},
{
"family": "Siwanowicz",
"given": "Igor"
},
{
"family": "Rubinov",
"given": "Mikail"
},
{
"family": "Delahanty",
"given": "Jeremy"
},
{
"family": "Fishman",
"given": "Mark C."
},
{
"family": "Engert",
"given": "Florian"
},
{
"family": "Sahani",
"given": "Maneesh"
},
{
"family": "Lavis",
"given": "Luke D."
},
{
"family": "Fitzgerald",
"given": "James E."
},
{
"family": "Ahrens",
"given": "Misha B."
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "9881",
"DOI": "10.1038/s41467-026-76242-8",
"PMID": "42749707",
"PMCID": "PMC13583002",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-76242-8",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
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.1016/j.isci.2026.116206 [code]
Gut distension evokes rapid neural dynamics in vagal and hindbrain populations of larval zebrafish.
Journal: iScience
In common: SimpleITK, tifffile, NetworkX, 7 other tools, zebrafish, systems, 14 references
[2] doi:10.7554/elife.100880 [code]
An applicable and efficient retrograde monosynaptic circuit mapping tool for larval zebrafish.
Journal: eLife
In common: tifffile, NetworkX, OpenCV, 8 other tools, zebrafish, systems, 2 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 neuroscience
In common: tifffile, NetworkX, scikit-image, 7 other tools, systems, 3 references
[4] doi:10.1038/s41467-026-71458-0 [code]
Early differential impact of MeCP2 mutations on functional networks in Rett syndrome patient-derived human cortical organoids.
Journal: Nature communications
In common: Neurodata Without Borders (PyNWB, MatNWB), tifffile, Parallel Computing Toolbox, 8 other tools
[5] doi:10.1038/s41593-026-02232-0 [code]
Entorhinal cortex represents task-relevant remote locations independently of CA1.
Journal: Nature neuroscience
In common: Neurodata Without Borders (PyNWB, MatNWB), NetworkX, OpenCV, 8 other tools, systems
[6] doi:10.1038/s41592-026-03179-7 [code]
Voltage imaging of neurons distributed across entire brains of larval zebrafish.
Journal: Nature methods
In common: OpenCV, scikit-image, h5py, 3 other tools, zebrafish, systems, 4 references
[7] doi:10.1038/s41467-026-69633-4 [code]
Visuomotor decision-making through multifeature convergence in the larval zebrafish hindbrain.
Journal: Nature communications
In common: h5py, scikit-learn, pandas, 3 other tools, zebrafish, 5 references
[8] 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 advances
In common: tifffile, OpenCV, scikit-image, 6 other tools, systems, 2 references
[9] doi:10.1038/s41467-026-73373-w [code]
Mapping neuro-vascular unit communications reveals distinct angiogenic programs across developing mouse brain regions.
Journal: Nature communications
In common: SimpleITK, tifffile, OpenCV, 8 other tools
[10] doi:10.7554/elife.109717 [code]
Retrosplenial cortex enables context-dependent goal-directed sensorimotor transformation.
Journal: eLife
In common: Neurodata Without Borders (PyNWB, MatNWB), tifffile, OpenCV, 7 other tools, systems

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.

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.