OSCR

PinkyCaMP: an mScarlet-based calcium sensor with enhanced brightness, photostability and multiplexing capabilities.

Code ↔ Paper

1 match 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 1 match
  1. [1] § Results › In vivo multiplexed and optogenetic fiber photometry ↔ Fiber-Photometry-Analysis-PinkyCaMP.ipynb, lines 201–220 · score 0.61 · closed arm, open arm, aversive airpuff, fiber photometry, behaviors

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 · 832 lines · 25 KB · MIT · 1 match

  1. # %% [markdown]
  2. # The purpose of this Jupyter notebook is to analyze Fiber Photometry Data recorded by a TDT system
  3. #
  4. # The notebook is adapted from Thoam Akam & Lauren Burgeno by referring to Simpson et al. 2023
  5. #
  6. # The preprocessing consists of the following steps:
  7. #
  8. # 1. Lowpass filtering to reduce noise (10 Hz filter).
  9. #
  10. # 2. Correction for photobleaching, over time. A double exponential fit is utilized for this purpose.
  11. #
  12. # 3. Movement correction by subtracting a linear fit of the movement control channel.
  13. #
  14. # 4. z-scoring the data
  15. #
  16. # %% [markdown]
  17. # Import all necessary packages
  18. # %%
  19. import pandas as pd
  20. import numpy as np
  21. import matplotlib
  22. import tdt
  23. import scipy.stats as stats
  24. import matplotlib.pyplot as plt
  25. from scipy.signal import butter, filtfilt
  26. import matplotlib.pyplot as plt
  27. from scipy.signal import medfilt, butter,filtfilt
  28. from scipy.stats import linregress
  29. from scipy.optimize import curve_fit
  30. import matplotlib.pyplot as plt
  31. # %% [markdown]
  32. # Jupyter has a bug that requires import of matplotl
  33. # matplotlib inline magic to properly apply rcParams
  34. # Set some other parameter
  35. # %%
  36. matplotlib.rcParams["font.size"]
  37. REF_EPOC = "Note" # event store
  38. ISOS = "_405A" # 405nm channel.
  39. GCaMP = "_465A" # 465nm channel.
  40. Pinky = "_560B" # 560nm channel.
  41. # %% [markdown]
  42. # First define the path to your data
  43. # %%
  44. BLOCKPATH = "example-data-0934-241017-143128" # insert your file path here
  45. # %% [markdown]
  46. # Read the data
  47. # %%
  48. data = tdt.read_block(BLOCKPATH)
  49. # %% [markdown]
  50. # Make time vectors and plot the unprocessed data
  51. # %%
  52. # Make time vector for plotting
  53. # Make time vector for plotting
  54. time_405A = (
  55. np.linspace(
  56. 0,
  57. len(getattr(data.streams, ISOS).data) / getattr(data.streams, ISOS).fs,
  58. len(getattr(data.streams, ISOS).data)
  59. )
  60. )
  61. # Sampling rates
  62. sampling_rate_405 = getattr(data.streams, ISOS).fs
  63. sampling_rate_465 = getattr(data.streams, GCaMP).fs
  64. sampling_rate_560 = getattr(data.streams, Pinky).fs
  65. # Make time vectors for plotting
  66. time_465A = (
  67. np.linspace(
  68. 0,
  69. len(getattr(data.streams, GCaMP).data) / getattr(data.streams, GCaMP).fs,
  70. len(getattr(data.streams, GCaMP).data)
  71. )
  72. )
  73. time_560B = (
  74. np.linspace(
  75. 0,
  76. len(getattr(data.streams, Pinky).data) / getattr(data.streams, Pinky).fs,
  77. len(getattr(data.streams, Pinky).data)
  78. )
  79. )
  80. # Plot raw traces
  81. import matplotlib.pyplot as plt
  82. # Create subplots
  83. fig, axs = plt.subplots(3, 1)
  84. fig.suptitle("Raw Data")
  85. # Plotting on the first subplot
  86. axs[0].plot(time_405A, getattr(data.streams, ISOS).data, color="limegreen")
  87. axs[0].set_title('ISOS Data')
  88. axs[0].set_xlabel('Time (s)')
  89. axs[0].set_ylabel('Signal')
  90. # Plotting on the second subplot
  91. axs[1].plot(time_465A, getattr(data.streams, GCaMP).data, color="cyan")
  92. axs[1].set_title('GCaMP Data')
  93. axs[1].set_xlabel('Time (s)')
  94. axs[1].set_ylabel('Signal')
  95. # Plotting on the third subplot
  96. axs[2].plot(time_560B, getattr(data.streams, Pinky).data, color="magenta")
  97. axs[2].set_title('Pinky Data')
  98. axs[2].set_xlabel('Time (s)')
  99. axs[2].set_ylabel('Signal')
  100. # Adjust layout to prevent overlap
  101. plt.tight_layout(rect=[0, 0, 1, 0.96]) # Adjust `rect` to fit suptitle
  102. plt.show()
  103. # %% [markdown]
  104. # Typically you get an artifact from the LEDs in the beginning of the recording.Here we remove the first seconds to get rid of it
  105. # %%
  106. # Trim data to start of LED onset via values /PC0 and video recording onset
  107. length_of_array = len(time_405A)
  108. offset = length_of_array / data.streams._405A.fs
  109. onset_LED = 10 # choose where to start the trial
  110. offset_LED = offset
  111. #offset_LED = 305 #alternatialy also choose the end of the recording
  112. isobestic_raw = []
  113. GCaMP_raw = []
  114. Pinky_raw = []
  115. duration = offset_LED - onset_LED
  116. delay = 0
  117. # trim isobestic data
  118. for t, x in zip(time_405A, getattr(data.streams, ISOS).data):
  119. # Check if the time falls within the LEDon period
  120. if onset_LED + delay <= t <= offset_LED:
  121. isobestic_raw.append(x)
  122. for t, x in zip(time_465A, getattr(data.streams, GCaMP).data):
  123. # Check if the time falls within the LEDon period
  124. if onset_LED + delay <= t <= offset_LED:
  125. GCaMP_raw.append(x)
  126. for t, x in zip(time_560B, getattr(data.streams, Pinky).data):
  127. # Check if the time falls within the LEDon period
  128. if onset_LED + delay <= t <= offset_LED:
  129. Pinky_raw.append(x)
  130. time_LED_465A = np.linspace(0, len(GCaMP_raw), len(GCaMP_raw)) / data.streams._465A.fs
  131. time_LED_405A = (
  132. np.linspace(0, len(isobestic_raw), len(isobestic_raw)) / data.streams._405A.fs
  133. )
  134. time_LED_560B = np.linspace(0, len(Pinky_raw), len(Pinky_raw)) / data.streams._560B.fs
  135. time_seconds = time_LED_405A
  136. # %% [markdown]
  137. # Now implement a 10 Hz cut off filter
  138. # %%
  139. # Define the filter
  140. def butter_lowpass(cutoff, fs, order=5):
  141. nyquist = 0.5 * fs
  142. normal_cutoff = cutoff / nyquist
  143. b, a = butter(order, normal_cutoff, btype="low", analog=False)
  144. return b, a
  145. def butter_lowpass_filter(data, cutoff, fs, order=5):
  146. b, a = butter_lowpass(cutoff, fs, order=order)
  147. y = filtfilt(b, a, data)
  148. return y
  149. # Filter requirements 465A
  150. order = 2
  151. fs = data.streams._465A.fs # sample rate, Hz
  152. cutoff = 10 # desired cutoff frequency of the filter, Hz
  153. # Filter requirements 405A
  154. order = 2
  155. fs = data.streams._405A.fs # sample rate, Hz
  156. cutoff = 10 # desired cutoff frequency of the filter, Hz
  157. # Filter requirements 560B
  158. order = 2
  159. fs = data.streams._560B.fs # sample rate, Hz
  160. cutoff = 10 # desired cutoff frequency of the filter, Hz
  161. # Apply filter to all of your data
  162. filtered_data_405A = butter_lowpass_filter(isobestic_raw, cutoff, fs, order)
  163. filtered_data_465A = butter_lowpass_filter(GCaMP_raw, cutoff, fs, order)
  164. filtered_data_560B = butter_lowpass_filter(Pinky_raw, cutoff, fs, order)
  165. # %% [markdown]
  166. # Find events, such as an aversive Airpuff, open arm entry (...) that have been marked during your recording to later plot and align these to the FibPho data
  167. # %%
  168. # find the events, such as open arm to closed arm, airpuff (...)that are stored as a Note in the TDT data tank or insert the timestamps for these events manually in the varibale (onset_behavior)
  169. events = data.epocs.Note.notes
  170. onset = data.epocs.Note.onset
  171. offset = data.epocs.Note.offset
  172. EVENT = "Airpuff"
  173. ##EVENT = "closed arm to open"
  174. #EVENT = "open arm to closed arm"
  175. indices = np.where(events == EVENT)[0]
  176. event_values_onset = onset[indices]
  177. print(event_values_onset)
  178. # !!!! Subtract onset from each element in airpuff_values!!!! you trimmed the data before
  179. adjusted_event_values = event_values_onset - onset_LED
  180. onset_behavior = adjusted_event_values
  181. print(onset_behavior)
  182. # %% [markdown]
  183. # Plot filtered traces
  184. # %%
  185. # plotting
  186. # Adjust the figure size if necessary
  187. fig, axs = plt.subplots(6, 1, figsize=(6, 10))
  188. fig.suptitle("10Hz Lowpass Filter", fontsize=12)
  189. # Plot data in each subplot
  190. axs[0].plot(time_LED_405A, isobestic_raw, color="lime")
  191. axs[0].set_title("Unfiltered Isobestic Signal", fontsize=8)
  192. axs[1].plot(time_LED_405A, filtered_data_405A, color="limegreen")
  193. axs[1].set_title("Filtered Isos Signal", fontsize=8)
  194. axs[2].plot(time_LED_465A, GCaMP_raw, color="darkorchid")
  195. axs[2].set_title("Unfiltered GCaMP Signal", fontsize=8)
  196. axs[3].plot(time_LED_560B, filtered_data_465A, color="cyan")
  197. axs[3].set_title("Filtered GCaMP Signal", fontsize=8)
  198. axs[4].plot(time_LED_560B, Pinky_raw, color="blueviolet")
  199. axs[4].set_title("Unfiltered Pinky Signal", fontsize=8)
  200. axs[5].plot(time_LED_560B, filtered_data_560B, color="magenta")
  201. axs[5].set_title("Filtered Pinky Signal", fontsize=8)
  202. # Plotting behavioral events as vertical lines
  203. axs[5].vlines(
  204. onset_behavior, # X-coordinates for the lines
  205. # Starting point of the vertical line (y-min)
  206. ymin=min(filtered_data_560B),
  207. ymax=max(filtered_data_560B), # Ending point of the vertical line (y-max)
  208. color="black", # Line color
  209. linestyle="--", # Line style (dashed)
  210. label="Behavioral Event", # Legend label
  211. )
  212. # Set the font size for all axis tick labels
  213. for ax in axs:
  214. ax.tick_params(axis="both", labelsize=10) # Adjust the font size as needed
  215. # Adjust layout to prevent overlap and ensure everything fits
  216. plt.tight_layout(rect=[0, 0, 1, 0.96]) # Leaves space for the suptitle
  217. # Display the plot
  218. plt.show()
  219. # %% [markdown]
  220. # Correction for photobleaching via a double exponential fit
  221. # %%
  222. def double_exponential(t, const, amp_fast, amp_slow, tau_slow, tau_multiplier):
  223. """Compute a double exponential function with constant offset.
  224. Parameters:
  225. t : Time vector in seconds.
  226. const : Amplitude of the constant offset.
  227. amp_fast: Amplitude of the fast component.
  228. amp_slow: Amplitude of the slow component.
  229. tau_slow: Time constant of slow component in seconds.
  230. tau_multiplier: Time constant of fast component relative to slow.
  231. """
  232. tau_fast = tau_slow * tau_multiplier
  233. return const + amp_slow * np.exp(-t / tau_slow) + amp_fast * np.exp(-t / tau_fast)
  234. # Fit curve to GCaMP.
  235. max_sig = np.max(filtered_data_465A)
  236. inital_params = [max_sig / 2, max_sig / 4, max_sig / 4, 3600, 0.1]
  237. bounds = ([0, 0, 0, 600, 0], [max_sig, max_sig, max_sig, 36000, 1])
  238. GCaMP_parms, parm_cov = curve_fit(
  239. double_exponential,
  240. time_LED_465A,
  241. filtered_data_465A,
  242. p0=inital_params,
  243. bounds=bounds,
  244. maxfev=1000,
  245. )
  246. GCaMP_expfit = double_exponential(time_LED_465A, *GCaMP_parms)
  247. # fit cure to isobestic
  248. max_sig = np.max(filtered_data_405A)
  249. inital_params = [max_sig / 2, max_sig / 4, max_sig / 4, 3600, 0.1]
  250. bounds = ([0, 0, 0, 600, 0], [max_sig, max_sig, max_sig, 36000, 1])
  251. isos_parms, parm_cov = curve_fit(
  252. double_exponential,
  253. time_LED_405A,
  254. filtered_data_405A,
  255. p0=inital_params,
  256. bounds=bounds,
  257. maxfev=1000,
  258. )
  259. isos_expfit = double_exponential(time_LED_405A, *isos_parms)
  260. # fit curve to Pinky
  261. max_sig = np.max(filtered_data_560B)
  262. inital_params = [max_sig / 2, max_sig / 4, max_sig / 4, 3600, 0.1]
  263. bounds = ([0, 0, 0, 600, 0], [max_sig, max_sig, max_sig, 36000, 1])
  264. Pinky_parms, parm_cov = curve_fit(
  265. double_exponential,
  266. time_LED_560B,
  267. filtered_data_560B,
  268. p0=inital_params,
  269. bounds=bounds,
  270. maxfev=1000,
  271. )
  272. Pinky_expfit = double_exponential(time_LED_560B, *Pinky_parms)
  273. # Fit the double exponential curve to the data 405A by substraction of
  274. # the fit this is used if the bleaching is dominated by autofluorescence, then it will affect the baseline
  275. # but not the amplitude of pyhsiological variation recommendation by Simpson et al. 2023
  276. photobleaching_corr_465 = filtered_data_465A - GCaMP_expfit
  277. photobleaching_corr_405 = filtered_data_405A - isos_expfit
  278. photobleaching_corr_560 = filtered_data_560B - Pinky_expfit
  279. # Alternatively fit the double exponential curve to the data by division. Note: the signal is converted to deltaF/F by the division
  280. # photobleaching_corr_465 = filtered_data_465A - GCaMP_expfit / GCaMP_expfit
  281. # photobleaching_corr_405 = filtered_data_405A - isos_expfit / isos_expfit
  282. # photobleaching_corr_560 = filtered_data_560B - Pinky_expfit / Pinky_expfit #
  283. # %% [markdown]
  284. # Plot the original data and the fitted curve
  285. # %%
  286. fig, axs = plt.subplots(6, 1, figsize=(6, 10)) # Adjust figure size if needed
  287. # Set the main title font size
  288. fig.suptitle("Double Exponential Fit", fontsize=10)
  289. # Plot data in each subplot and set font sizes
  290. axs[0].plot(time_LED_405A, filtered_data_405A, label="Original data", color="lime")
  291. axs[0].plot(time_LED_405A, isos_expfit, color="black", label="Fitted curve")
  292. axs[0].set_title("Isos Signal + Fit", fontsize=10)
  293. axs[0].legend(fontsize=10) # Set legend font size
  294. axs[1].plot(
  295. time_LED_465A, photobleaching_corr_405, color="limegreen", label="Fitted curve"
  296. )
  297. axs[1].set_title("Fitted Isos Signal", fontsize=10)
  298. axs[1].legend(fontsize=10) # Set legend font size
  299. axs[2].plot(time_LED_465A, filtered_data_465A, label="Original data")
  300. axs[2].plot(time_LED_465A, GCaMP_expfit, color="black", label="Fitted curve")
  301. axs[2].set_title("GCaMP Signal + Fit", fontsize=10)
  302. axs[2].legend(fontsize=10) # Set legend font size
  303. axs[3].plot(time_LED_465A, photobleaching_corr_465, color="cyan", label="Fitted curve")
  304. axs[3].set_title("Fitted GCaMP Signal", fontsize=10)
  305. axs[3].legend(fontsize=10) # Set legend font size
  306. axs[4].plot(time_LED_560B, filtered_data_560B, label="Original data")
  307. axs[4].plot(time_LED_560B, Pinky_expfit, color="black", label="Fitted curve")
  308. axs[4].set_title("Pinky Signal + Fit", fontsize=10)
  309. axs[4].legend(fontsize=10) # Set legend font size
  310. axs[5].plot(
  311. time_LED_560B, photobleaching_corr_560, color="magenta", label="Fitted curve"
  312. )
  313. axs[5].set_title("Fitted Pinky Signal", fontsize=10)
  314. axs[5].legend(fontsize=10) # Set legend font size
  315. # Plotting behavioral events as vertical lines
  316. axs[5].vlines(
  317. onset_behavior, # X-coordinates for the lines
  318. ymin=min(photobleaching_corr_560), # Starting point of the vertical line (y-min)
  319. ymax=max(photobleaching_corr_560), # Ending point of the vertical line (y-max)
  320. color="black", # Line color
  321. linestyle="--", # Line style (dashed)
  322. label="Behavioral Event", # Legend label
  323. )
  324. # Set the font size for all axis tick labels
  325. for ax in axs:
  326. ax.tick_params(axis="both", labelsize=10) # Set tick label font size
  327. # Adjust layout to prevent overlap
  328. plt.tight_layout(
  329. rect=[0, 0, 1, 0.96]
  330. ) # Adjust the rect parameter as needed to fit the suptitle
  331. plt.show()
  332. # %% [markdown]
  333. # Substitute the data in data stream with the photoblaahcing corrected
  334. # %%
  335. # Ersetzen der Daten in data Struc mit neuen gefitteten
  336. data.streams._405A.data = photobleaching_corr_405
  337. data.streams._465A.data = photobleaching_corr_465
  338. data.streams._560B.data = photobleaching_corr_560
  339. # %% [markdown]
  340. # Motion correction by finding the best linear fit of the
  341. # isobestic signal to the signal and subtracting this estimated motion component from it.
  342. # We will use the data that was bleaching corrected using the double exponential fit as this is less likely to remove meaningful
  343. # slow variation in the signals.
  344. # %%
  345. isobestic_detrended = photobleaching_corr_405
  346. GCaMP_detrended = photobleaching_corr_465
  347. Pinky_detrended = photobleaching_corr_560
  348. time_seconds = time_LED_405A
  349. slope, intercept, r_value, p_value, std_err = linregress(
  350. x=isobestic_detrended, y=GCaMP_detrended
  351. )
  352. plt.scatter(isobestic_detrended[::5], GCaMP_detrended[::5], alpha=0.1, marker=".")
  353. x = np.array(plt.xlim())
  354. plt.plot(x, intercept + slope * x)
  355. plt.xlabel("isobestic")
  356. plt.ylabel("GCamP")
  357. plt.title("GCaMP - isobestic correlation.")
  358. print("Slope : {:.3f}".format(slope))
  359. print("R-squared: {:.3f}".format(r_value**2))
  360. # We now calculate the estimated motion component of the GCaMP signal and subtract to get the motion corrected
  361. GCaMP_est_motion = intercept + slope * isobestic_detrended
  362. GCaMP_corrected = GCaMP_detrended - GCaMP_est_motion
  363. fig, ax1 = plt.subplots()
  364. plot1 = ax1.plot(
  365. time_seconds, GCaMP_detrended, "b", label="GCaMP - pre motion correction", alpha=0.5
  366. )
  367. plot3 = ax1.plot(
  368. time_seconds, GCaMP_corrected, "g", label="GCaMP - motion corrected", alpha=0.5
  369. )
  370. plot4 = ax1.plot(time_seconds, GCaMP_est_motion - 0.05, "y", label="estimated motion")
  371. ax1.set_xlabel("Time (seconds)")
  372. ax1.set_ylabel("GCaMP Signal (V)", color="g")
  373. ax1.set_title("Motion Correction")
  374. plt.tight_layout()
  375. plt.show()
  376. slope, intercept, r_value, p_value, std_err = linregress(
  377. x=isobestic_detrended, y=Pinky_detrended
  378. )
  379. plt.scatter(isobestic_detrended[::5], Pinky_detrended[::5], alpha=0.1, marker=".")
  380. x = np.array(plt.xlim())
  381. plt.plot(x, intercept + slope * x)
  382. plt.xlabel("isobestic")
  383. plt.ylabel("Pinky")
  384. plt.title("Pinky - isobestic correlation.")
  385. print("Slope : {:.3f}".format(slope))
  386. print("R-squared: {:.3f}".format(r_value**2))
  387. # We now calculate the estimated motion component of the Pinky signal and subtract to get the motion corrected
  388. Pinky_est_motion = intercept + slope * isobestic_detrended
  389. Pinky_corrected = Pinky_detrended - Pinky_est_motion
  390. fig, ax1 = plt.subplots(figsize=(10, 6))
  391. # Plot Pinky - pre motion correction (detrended)
  392. plot1 = ax1.plot(
  393. time_seconds,
  394. Pinky_detrended,
  395. color="violet",
  396. label="Pinky - Pre Motion Correction",
  397. alpha=0.7,
  398. linewidth=2,
  399. )
  400. # Plot Pinky - motion corrected
  401. plot3 = ax1.plot(
  402. time_seconds,
  403. Pinky_corrected,
  404. color="magenta",
  405. label="Pinky - Motion Corrected",
  406. alpha=0.7,
  407. linewidth=2,
  408. )
  409. # Plot estimated motion, offset for better visibility
  410. plot4 = ax1.plot(
  411. time_seconds,
  412. Pinky_est_motion - 0.05,
  413. color="lightgray",
  414. label="Estimated Motion",
  415. linestyle="--",
  416. linewidth=2,
  417. )
  418. # Add grid, titles, and labels with enhanced font size
  419. ax1.set_xlabel("Time (seconds)", fontsize=12)
  420. ax1.set_ylabel("Pinky Signal (V)", fontsize=12)
  421. ax1.set_title("Motion Correction - Pinky Signal", fontsize=14, fontweight="bold")
  422. # Improve the appearance of the legend and place it outside the plot
  423. lines = plot1 + plot3 + plot4
  424. labels = [l.get_label() for l in lines]
  425. legend = ax1.legend(
  426. lines, labels, loc="upper left", bbox_to_anchor=(1, 1), fontsize=10, frameon=True
  427. )
  428. # Add gridlines
  429. ax1.grid(True, which="both", linestyle="--", linewidth=0.5)
  430. # Add shaded region for better visual emphasis on important signal parts (optional)
  431. ax1.axhspan(-0.1, 0.1, color="lightyellow", alpha=0.3, label="Shaded Area")
  432. # Make the y-axis labels a little more distinguishable
  433. ax1.tick_params(axis="y", colors="green", labelsize=10)
  434. ax1.tick_params(axis="x", labelsize=10)
  435. # Adjust layout to fit the legend
  436. plt.tight_layout()
  437. plt.show()
  438. # %% [markdown]
  439. # Z-scoring of the data
  440. # %%
  441. # Z-scoring all data _corrected is the motion corrected signal
  442. # Z-score the GCaMP data
  443. GCaMP_zscored = (GCaMP_corrected - np.mean(GCaMP_corrected)) / np.std(GCaMP_corrected)
  444. # Create the figure and axis
  445. fig, ax1 = plt.subplots(figsize=(10, 6))
  446. # Plot the GCaMP z-scored signal
  447. plot1 = ax1.plot(
  448. time_seconds,
  449. GCaMP_zscored,
  450. color="cyan",
  451. label="GCaMP z-score",
  452. linewidth=2,
  453. alpha=0.8,
  454. )
  455. # Plot reward cue markers
  456. reward_ticks = ax1.plot(
  457. onset_behavior,
  458. np.full(np.size(onset_behavior), 6), # Plot at a constant value of 6
  459. label="Reward Cue",
  460. color="k", # Black marker
  461. marker="v", # Downward triangle marker
  462. linestyle="None",
  463. mfc="white", # Marker face color white
  464. mec="black", # Marker edge color black
  465. ms=10, # Marker size
  466. )
  467. # Set labels and title
  468. ax1.set_xlabel("Time (seconds)", fontsize=12)
  469. ax1.set_ylabel("GCaMP z-score", fontsize=12)
  470. ax1.set_title("GCaMP z-scored Signal with Reward Cue", fontsize=14, fontweight="bold")
  471. # Combine plot lines for the legend
  472. lines = plot1 + reward_ticks
  473. labels = [l.get_label() for l in lines]
  474. # Create legend
  475. legend = ax1.legend(
  476. lines,
  477. labels,
  478. loc="upper right",
  479. bbox_to_anchor=(0.95, 0.98),
  480. fontsize=10,
  481. frameon=True,
  482. )
  483. # Add grid for better visibility of values
  484. ax1.grid(True, which="both", linestyle="--", linewidth=0.5)
  485. #ax1.set_xlim(0,300)
  486. # Adjust layout to make room for legend and avoid overlap
  487. plt.tight_layout()
  488. # Show the plot
  489. plt.show()
  490. # Z-score the Pinky data
  491. Pinky_zscored = (Pinky_corrected - np.mean(Pinky_corrected)) / np.std(Pinky_corrected)
  492. # Create figure and axis
  493. fig, ax1 = plt.subplots(figsize=(10, 6))
  494. # Plot the Pinky z-scored signal
  495. plot1 = ax1.plot(
  496. time_seconds,
  497. Pinky_zscored,
  498. color="magenta",
  499. label="Pinky z-score",
  500. linewidth=2,
  501. alpha=0.8,
  502. )
  503. # Plot reward cue markers
  504. reward_ticks = ax1.plot(
  505. onset_behavior,
  506. np.full(np.size(onset_behavior), 6), # Position markers at y=6
  507. label="Reward Cue",
  508. color="black", # Black outline and marker
  509. marker="v", # Downward triangle marker
  510. linestyle="None",
  511. mfc="white", # White face color for markers
  512. mec="black", # Black edge color for markers
  513. ms=10, # Size of the markers
  514. )
  515. # Set x and y axis labels
  516. ax1.set_xlabel("Time (seconds)", fontsize=12)
  517. ax1.set_ylabel("Pinky z-score", fontsize=12)
  518. #ax1.set_xlim(30,300)
  519. # Set title
  520. ax1.set_title("Pinky z-scored Signal with Reward Cue", fontsize=14, fontweight="bold")
  521. # Add legend
  522. lines = plot1 + reward_ticks
  523. labels = [l.get_label() for l in lines]
  524. legend = ax1.legend(
  525. lines,
  526. labels,
  527. loc="upper right",
  528. bbox_to_anchor=(0.95, 0.98),
  529. fontsize=10,
  530. frameon=True,
  531. )
  532. # Add gridlines for better readability
  533. ax1.grid(True, which="both", linestyle="--", linewidth=0.5)
  534. # Adjust the layout for better spacing
  535. plt.tight_layout()
  536. # Display the plot
  537. plt.show()
  538. # %% [markdown]
  539. # Plot z-scored data according to the choosen event, e.g. airpuff
  540. # %%
  541. # Sort data in time windws around the EVENT
  542. timing_vector = time_seconds
  543. # Define the window size (5 seconds before and after each onset)
  544. time_window = 5 # in seconds
  545. # Initialize lists to store extracted windows
  546. windows_time = []
  547. windows_gcamp = []
  548. windows_isos = []
  549. windows_pinky = []
  550. # Extract windows around each timepoint of interest
  551. for timepoint_of_interest in onset_behavior:
  552. # Find the index in the time vector closest to the timepoint of interest
  553. index = np.abs(timing_vector - timepoint_of_interest).argmin()
  554. # Calculate the start and end indices for the window
  555. start_index = max(
  556. 0,
  557. index
  558. - int(
  559. time_window * len(timing_vector) / (timing_vector[-1] - timing_vector[0])
  560. ),
  561. )
  562. end_index = min(
  563. len(timing_vector) - 1,
  564. index
  565. + int(
  566. time_window * len(timing_vector) / (timing_vector[-1] - timing_vector[0])
  567. ),
  568. )
  569. # Extract the window of time vector and corresponding data
  570. window_time = timing_vector[start_index : end_index + 1]
  571. window_gcamp = GCaMP_detrended[start_index : end_index + 1]
  572. window_pinky = Pinky_detrended[start_index : end_index + 1]
  573. window_isos = isobestic_detrended[start_index : end_index + 1]
  574. # Store the extracted window
  575. windows_time.append(window_time)
  576. windows_gcamp.append(window_gcamp)
  577. windows_isos.append(window_isos)
  578. windows_pinky.append(window_pinky)
  579. # calculate mean over all trials for each channel
  580. mean_GCaMP_event = np.mean(windows_gcamp, axis=0)
  581. time_vector = np.linspace(0, time_window + time_window, len(mean_GCaMP_event))
  582. sem_gcamp = np.std(windows_gcamp, axis=0) / np.sqrt(len(windows_gcamp))
  583. # calculate for isos
  584. mean_isos_event = np.mean(windows_isos, axis=0)
  585. # time_vector = np.linspace(0, 1, len(mean_GCamP_event))
  586. sem_isos = np.std(windows_isos, axis=0) / np.sqrt(len(windows_isos))
  587. mean_Pinky_event = np.mean(windows_pinky, axis=0)
  588. time_vector = np.linspace(0, time_window + time_window, len(mean_Pinky_event))
  589. sem_Pinky = np.std(windows_pinky, axis=0) / np.sqrt(len(windows_pinky))
  590. # Plot the mean GCaMP data
  591. plt.figure(figsize=(10, 6))
  592. plt.plot(time_vector, mean_GCaMP_event, "cyan", label="Mean GCaMP Data")
  593. # plt.plot(time_vector, mean_Pinky_event, "magenta", label="Mean Pinky Data")
  594. # Plot the error band representing SEM
  595. plt.fill_between(
  596. time_vector,
  597. mean_GCaMP_event - sem_gcamp,
  598. mean_GCaMP_event + sem_gcamp,
  599. alpha=0.2,
  600. label="SEM",
  601. )
  602. plt.xlabel("Time")
  603. plt.ylabel("z-Score sDarken")
  604. plt.title("Mean sDarken Data with Error Band (SEM)")
  605. plt.legend()
  606. # plt.grid(True)
  607. plt.show()
  608. plt.figure(figsize=(10, 6))
  609. plt.plot(time_vector, mean_Pinky_event, "magenta", label="Mean Pinky Data", zorder=3)
  610. plt.fill_between(
  611. time_vector,
  612. mean_Pinky_event - sem_Pinky,
  613. mean_Pinky_event + sem_Pinky,
  614. alpha=0.2,
  615. label="SEM",
  616. zorder=2,
  617. )
  618. plt.xlabel("Time")
  619. plt.ylabel("z-score PinkyCaMP", fontsize=10)
  620. plt.title("Mean PinkyCaMP Data with Error Band (SEM)")
  621. plt.show()
  622. # %% [markdown]
  623. # Heatmaps
  624. # %%
  625. # Heatmap GCaMP
  626. plt.figure(figsize=(10, 6))
  627. plt.imshow(windows_gcamp, aspect="auto", cmap="viridis", interpolation="nearest")
  628. # cbar = fig.colorbar(cs, pad=0.01, fraction=0.02)
  629. plt.colorbar(label="Value")
  630. plt.xlabel("Time")
  631. plt.ylabel("Trial")
  632. plt.title("Heatmap of Multiple Trials")
  633. # Define and set x-ticks and labels
  634. plt.xticks(
  635. ticks=np.linspace(-5, 5, 11), # Create 11 ticks from -5 to 5
  636. labels=np.linspace(-5, 5, 11).astype(int), # Labels for ticks
  637. )
  638. plt.show()
  639. # Heatmap PinkyCaMP
  640. plt.figure(figsize=(10, 6))
  641. plt.imshow(windows_pinky, aspect="auto", cmap="inferno", interpolation="nearest")
  642. # cbar = fig.colorbar(cs, pad=0.01, fraction=0.02)
  643. plt.colorbar(label="z-score")
  644. # Define and set x-ticks and labels
  645. # Here we map data range to label range -5 to 5
  646. x_ticks = np.linspace(0, 10000, num=6) # Create ticks from 0 to 10000
  647. x_labels = np.linspace(-5, 5, num=6) # Corresponding labels
  648. plt.xticks(ticks=x_ticks, labels=x_labels) # Set tick positions # Set tick labels
  649. plt.xlabel("Time")
  650. plt.ylabel("Trial")
  651. plt.title("Heatmap of Multiple Trials")
  652. # %% [markdown]
  653. # Export of z-score data as csv.
  654. # %%
  655. import pandas as pd
  656. import numpy as np
  657. import os
  658. # convert lists in NumPy-Arrays
  659. windows_gcamp_array = np.array(windows_gcamp)
  660. windows_pinky_array = np.array(windows_pinky)
  661. # make data frames for each data array
  662. df_gcamp = pd.DataFrame(
  663. windows_gcamp_array,
  664. columns=[f"GCaMP_{i}" for i in range(windows_gcamp_array.shape[1])],
  665. )
  666. df_pinky = pd.DataFrame(
  667. windows_pinky_array,
  668. columns=[f"Pinky_{i}" for i in range(windows_pinky_array.shape[1])],
  669. )
  670. # Check if path exsists and make directory
  671. directory = os.path.dirname(BLOCKPATH)
  672. if not os.path.exists(directory):
  673. os.makedirs(directory)
  674. # choose name for the CSV- data file
  675. gcamp_path = BLOCKPATH + "_GCaMP_data.csv"
  676. pinky_path = BLOCKPATH + "_Pinky_data.csv"
  677. time_path = BLOCKPATH + "_time_data.csv"
  678. # save GCamP/green channel
  679. df_gcamp.to_csv(gcamp_path, index=False)
  680. print(f"GCaMP Daten wurden erfolgreich in '{gcamp_path}' gespeichert.")
  681. # save PinkyCaMP/red channel
  682. df_pinky.to_csv(pinky_path, index=False)
  683. # print(f"Pinky Daten wurden erfolgreich in '{pinky_path}' gespeichert.")

Fiber-Photometry-Analysis-PinkyCaMP.ipynb at commit 18a0179, under MIT · at the source

Overview

Authors: Ryan Fink1,2, Shosei Imai3, Nala Gockel4, German Lauer5, Kim Renken2, Jonas Wietek6,7, Paul J. Lamothe-Molina8, Falko Fuhrmann4, Manuel Mittag4, Tim Ziebarth5, Annika Canziani8, Martin Kubitschke2, Vivien Kistmacher9, Anny Kretschmer10, Eva Sebastian11, Jana Ottens2, Dietmar Schmitz6,7,10,12,13,14, Takuya Terai3, Jan Gründemann11,15, Sami I. Hassan9, Tommaso Patriarchi8,16, Andreas Reiner5, Martin Fuhrmann4, Robert E. Campbell3,17, Olivia Andrea Masseck1,2
17 affiliations
  1. Neuromodulatory Circuits, Institute of Zoology, University of Cologne,Cologne, Germany
  2. Synthetic Biology, University of Bremen,Bremen, Germany
  3. Department of Chemistry, Graduate School of Science, The University of Tokyo,Tokyo, Japan
  4. Neuroimmunology and Imaging Group, German Center for Neurodegenerative Diseases (DZNE),Bonn, Germany
  5. Cellular Neurobiology, Department of Biology and Biotechnology, Ruhr University Bochum,Bochum, Germany
  6. Charité-Universitätsmedizin Berlin, corporate member of Freie Universität Berlin and Humboldt-Universität zu Berlin, Neuroscience Research Center,Berlin, Germany
  7. Charité-Universitätsmedizin Berlin, corporate member of Freie Universität Berlin and Humboldt-Universität zu Berlin, Institute of Cell and Neurobiology,Berlin, Germany
  8. Institute of Pharmacology and Toxicology, University of Zürich,Zurich, Switzerland
  9. System Neurobiology, University of Bremen,Bremen, Germany
  10. Network Dysfunction, German Center for Neurodegenerative Diseases (DZNE),Bonn, Germany
  11. Neural Circuit Computation, German Center for Neurodegenerative Diseases (DZNE),Bonn, Germany
  12. Charité-Universitätsmedizin Berlin, corporate member of Freie Universität Berlin and Humboldt-Universität Berlin, Einstein Center for Neuroscience,Berlin, Germany
  13. Charité-Universitätsmedizin Berlin, corporate member of Freie Universität Berlin and Humboldt-Universität Berlin, NeuroCure Cluster of Excellence,Berlin, Germany
  14. Humboldt-Universität zu Berlin, Bernstein Center for Computational Neuroscience,Berlin, Germany
  15. University of Bonn, Medical Faculty,Bonn, Germany
  16. Neuroscience Center Zürich, University and ETH Zürich,Zürich, Switzerland
  17. CERVO Brain Research Center and Department of Biochemistry, Microbiology, and Bioinformatics, Université Laval,Quebec, Quebec Canada
Journal: Nature methods, volume 23, issue 5, pages 998-1010
Dates: received 16 December 2024; accepted 13 March 2026; published online 24 April 2026; in print 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41592-026-03065-2 · PMID 42032066 · PMCID PMC13167472 · OpenAlex W7155507564
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: optical imaging (calcium, voltage, 2-photon) (modality), human (organism), mouse (organism), cellular / molecular (subfield)
Methods: Spectral & time-frequency, Connectivity, Statistics, Evoked potentials, Machine learning, fMRI & imaging, Single-unit activity, calcium imaging
Keywords: Neuroscience, Protein design
MeSH: Calcium*, Luminescent Proteins*, Animals, Fluorescent Chemosensor Compounds, Humans, Mice, Neurons, Optogenetics, Red Fluorescent Protein, Signal-To-Noise Ratio (* major topic)
Topic: Photochromic and Fluorescence Chemistry (Materials Chemistry, Materials Science), according to OpenAlex
Funding: Deutsche Forschungsgemeinschaft (DFG) (MA4692/6-3, MA4692/12-1, 184695641, SFB1315, FOR3004, SFB1089, SPP2411, 394431587, FOR 3004, SPP2395); Japan Society for the Promotion of Science (KAKENHI 21H00273, 24H02267, 24H00489, 19H05633); EC | EU Framework Programme for Research and Innovation H2020 | H2020 Priority Excellent Science | H2020 European Research Council (H2020 Excellent Science - European Research Council) (891959, MicroSynCom 865618)
Citations: cited by 4 papers (Europe PMC); 63 references in the paper

Abstract

Genetically encoded calcium (Ca2+) indicators (GECIs) are essential tools for monitoring neuronal activity, but the performance of red fluorescent GECIs has remained limited. In particular, many red indicators are relatively dim, produce low signal-to-noise ratios and can undergo unwanted photoswitching when exposed to blue light, restricting their use in all-optical experiments that combine imaging with optogenetics or multicolor imaging. Here we show the development of PinkyCaMP, a Ca2+ sensor based on the bright red fluorescent protein mScarlet. PinkyCaMP exhibits markedly improved brightness, photostability and signal-to-noise ratio compared to existing red GECIs, while remaining fully compatible with blue-light-based optogenetic and dual-color imaging approaches. PinkyCaMP is well-tolerated by neurons, showing no detectable toxicity or aggregation, both in vitro and in vivo. PinkyCaMP enables a broad spectrum of imaging modalities, including single-photon methods, such as fiber photometry, widefield imaging and miniature microscopy imaging, as well as two-photon imaging in awake mice.

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

Repository

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

masseck/FibPho-PinkyCaMP

License: MIT
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: 18a0179077a897492b128144f6442240ff92fee6, 15 October 2025
Languages: Jupyter (2)
Size: 16 files, 2 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, 2 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Matplotlib (2 files), NumPy (2 files), pandas (2 files), SciPy (2 files)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
4 files

Code availability

The Fiber Photometry analysis script is publicly available on GitHub (https://github.com/masseck/FibPho-PinkyCaMP.git), MIT License.

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:

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

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

Data

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

Data availability

DNA sequences are available in Supplementary Information and at GenBank under accession number: BankIt3060018 syntheticPZ111304. DNA plasmids used for viral production have been deposited both on the UZH Viral Vector Facility (https://vvf.ethz.ch/, v1177, v1197) and on Addgene (plasmids #232857–232861). Viral vectors can be obtained either from the UZH Viral Vector Facility or from the Masseck laboratory. Due to the large size of the raw imaging datasets, public deposition is currently not feasible. Raw data can be obtained by emailing the corresponding author. Source data are provided with this paper.

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, 30 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 25 authors, 2 keywords, 10 MeSH terms, 3 funders, 59 references.

Cite

This paper

Fink, R., Imai, S., Gockel, N., Lauer, G., Renken, K., Wietek, J., Lamothe-Molina, P. J., Fuhrmann, F., Mittag, M., Ziebarth, T., Canziani, A., Kubitschke, M., Kistmacher, V., Kretschmer, A., Sebastian, E., Ottens, J., Schmitz, D., Terai, T., Gründemann, J., . . . Masseck, O. A. (2026). PinkyCaMP: an mScarlet-based calcium sensor with enhanced brightness, photostability and multiplexing capabilities. Nature methods, 23(5), 998-1010. https://doi.org/10.1038/s41592-026-03065-2

BibTeX

@article{fink2026pinkycamp,
author = {Fink, Ryan and Imai, Shosei and Gockel, Nala and Lauer, German and Renken, Kim and Wietek, Jonas and Lamothe-Molina, Paul J. and Fuhrmann, Falko and Mittag, Manuel and Ziebarth, Tim and Canziani, Annika and Kubitschke, Martin and Kistmacher, Vivien and Kretschmer, Anny and Sebastian, Eva and Ottens, Jana and Schmitz, Dietmar and Terai, Takuya and Gründemann, Jan and Hassan, Sami I. and Patriarchi, Tommaso and Reiner, Andreas and Fuhrmann, Martin and Campbell, Robert E. and Masseck, Olivia Andrea},
title = {{PinkyCaMP: an mScarlet-based calcium sensor with enhanced brightness, photostability and multiplexing capabilities}},
journal = {Nature methods},
year = {2026},
month = apr,
volume = {23},
number = {5},
pages = {998--1010},
publisher = {Nature Portfolio},
issn = {1548-7091},
doi = {10.1038/s41592-026-03065-2},
url = {https://doi.org/10.1038/s41592-026-03065-2},
pmid = {42032066},
pmcid = {PMC13167472}
}

RIS

TY - JOUR
AU - Fink, Ryan
AU - Imai, Shosei
AU - Gockel, Nala
AU - Lauer, German
AU - Renken, Kim
AU - Wietek, Jonas
AU - Lamothe-Molina, Paul J.
AU - Fuhrmann, Falko
AU - Mittag, Manuel
AU - Ziebarth, Tim
AU - Canziani, Annika
AU - Kubitschke, Martin
AU - Kistmacher, Vivien
AU - Kretschmer, Anny
AU - Sebastian, Eva
AU - Ottens, Jana
AU - Schmitz, Dietmar
AU - Terai, Takuya
AU - Gründemann, Jan
AU - Hassan, Sami I.
AU - Patriarchi, Tommaso
AU - Reiner, Andreas
AU - Fuhrmann, Martin
AU - Campbell, Robert E.
AU - Masseck, Olivia Andrea
TI - PinkyCaMP: an mScarlet-based calcium sensor with enhanced brightness, photostability and multiplexing capabilities
T2 - Nature methods
J2 - Nat Methods
PY - 2026
DA - 2026/04/24
VL - 23
IS - 5
SP - 998
EP - 1010
SN - 1548-7091
PB - Nature Portfolio
DO - 10.1038/s41592-026-03065-2
UR - https://doi.org/10.1038/s41592-026-03065-2
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41592-026-03065-2",
"type": "article-journal",
"title": "PinkyCaMP: an mScarlet-based calcium sensor with enhanced brightness, photostability and multiplexing capabilities",
"container-title": "Nature methods",
"author": [
{
"family": "Fink",
"given": "Ryan"
},
{
"family": "Imai",
"given": "Shosei"
},
{
"family": "Gockel",
"given": "Nala"
},
{
"family": "Lauer",
"given": "German"
},
{
"family": "Renken",
"given": "Kim"
},
{
"family": "Wietek",
"given": "Jonas"
},
{
"family": "Lamothe-Molina",
"given": "Paul J."
},
{
"family": "Fuhrmann",
"given": "Falko"
},
{
"family": "Mittag",
"given": "Manuel"
},
{
"family": "Ziebarth",
"given": "Tim"
},
{
"family": "Canziani",
"given": "Annika"
},
{
"family": "Kubitschke",
"given": "Martin"
},
{
"family": "Kistmacher",
"given": "Vivien"
},
{
"family": "Kretschmer",
"given": "Anny"
},
{
"family": "Sebastian",
"given": "Eva"
},
{
"family": "Ottens",
"given": "Jana"
},
{
"family": "Schmitz",
"given": "Dietmar"
},
{
"family": "Terai",
"given": "Takuya"
},
{
"family": "Gründemann",
"given": "Jan"
},
{
"family": "Hassan",
"given": "Sami I."
},
{
"family": "Patriarchi",
"given": "Tommaso"
},
{
"family": "Reiner",
"given": "Andreas"
},
{
"family": "Fuhrmann",
"given": "Martin"
},
{
"family": "Campbell",
"given": "Robert E."
},
{
"family": "Masseck",
"given": "Olivia Andrea"
}
],
"container-title-short": "Nat Methods",
"volume": "23",
"issue": "5",
"page": "998-1010",
"DOI": "10.1038/s41592-026-03065-2",
"PMID": "42032066",
"PMCID": "PMC13167472",
"ISSN": "1548-7091",
"publisher": "Nature Portfolio",
"URL": "https://doi.org/10.1038/s41592-026-03065-2",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
24
]
]
}
}

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.7554/elife.107939 [code]
Resolving synaptic events using subsynaptically targeted GCaMP8 variants.
Journal: eLife
In common: pandas, SciPy, Matplotlib, 1 other tool, optical imaging (calcium, voltage, 2-photon), cellular / molecular, 9 references
[2] doi:10.1002/advs.202515887 [code]
An Open-Source Pipeline for Calcium Imaging and All-Optical Physiology in Human Stem Cell-Derived Neurons.
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)
In common: pandas, SciPy, Matplotlib, 1 other tool, optical imaging (calcium, voltage, 2-photon), 5 references
[3] doi:10.1111/ejn.70480 [code]
Astrocyte Proximity Protects Synapses From Human Amyloid-Beta Induced Degeneration in a Mouse Ex Vivo Model of Early Alzheimer's Disease.
Journal: The European journal of neuroscience
In common: pandas, SciPy, Matplotlib, 1 other tool, mouse, cellular / molecular, 6 references
[4] doi:10.1111/ejn.70582 [code]
Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain.
Journal: The European journal of neuroscience
In common: pandas, SciPy, Matplotlib, 1 other tool, optical imaging (calcium, voltage, 2-photon), mouse, 4 references
[5] 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 express
In common: pandas, SciPy, Matplotlib, 1 other tool, optical imaging (calcium, voltage, 2-photon), 4 references
[6] doi:10.1038/s41598-026-52253-9 [code]
Sequential visual stimuli increase high frequency power in the visual cortex.
Journal: Scientific reports
In common: pandas, SciPy, Matplotlib, 1 other tool, mouse, author Dietmar Schmitz
[7] 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: pandas, SciPy, Matplotlib, 1 other tool, optical imaging (calcium, voltage, 2-photon), 4 references
[8] doi:10.1038/s41593-026-02379-w
Norepinephrine and dopamine sensor crosstalk depends on local innervation density.
Journal: Nature neuroscience
In common: mouse, cellular / molecular, 1 reference, author Tommaso Patriarchi
[9] doi:10.1038/s41592-026-03125-7
Simultaneous two- and three-photon multiplane imaging across cortical layers in freely moving mice.
Journal: Nature methods
In common: optical imaging (calcium, voltage, 2-photon), mouse, 5 references
[10] doi:10.1038/s41598-026-50423-3 [code]
Theoretical analysis of low power synergistic sono-optogenetic control of calcium-dependent synaptic plasticity.
Journal: Scientific reports
In common: cellular / molecular, 5 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.

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.