Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain.
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 · 521 lines · 20 KB · GPL-3.0
- import nrrd
- import numpy as np
- import matplotlib.pyplot as plt
- from matplotlib.widgets import Slider, Button, TextBox, RadioButtons
- from matplotlib.colors import ListedColormap, Normalize
- import json
- def load_annotation(filepath):
- """Load the NRRD annotation file"""
- data, header = nrrd.read(filepath)
- return data, header
- def load_structure_tree(filepath):
- """Load the structure tree JSON file and create ID to name mapping"""
- with open(filepath, 'r') as f:
- data = json.load(f)
- # Create a mapping from structure ID to structure info
- id_to_info = {}
- def traverse_tree(node):
- """Recursively traverse the structure tree"""
- structure_id = node.get('id')
- name = node.get('name', 'Unknown')
- acronym = node.get('acronym', '')
- if structure_id is not None:
- id_to_info[structure_id] = {
- 'name': name,
- 'acronym': acronym,
- 'color_hex': node.get('color_hex_triplet', 'FFFFFF')
- }
- # Process children
- if 'children' in node:
- for child in node['children']:
- traverse_tree(child)
- # Handle different JSON structures
- if isinstance(data, dict):
- # Check if there's a 'msg' key (common in Allen Institute files)
- if 'msg' in data:
- root_nodes = data['msg']
- else:
- root_nodes = [data]
- elif isinstance(data, list):
- root_nodes = data
- else:
- root_nodes = [data]
- # Traverse all root nodes
- for root in root_nodes:
- traverse_tree(root)
- return id_to_info
- def create_color_mapped_image(slice_data, structure_info):
- """Create RGB image from structure IDs using their defined colors"""
- # Create RGB image
- height, width = slice_data.shape
- rgb_image = np.zeros((height, width, 3), dtype=np.uint8)
- for i in range(height):
- for j in range(width):
- struct_id = int(slice_data[i, j])
- if struct_id in structure_info and struct_id != 0:
- hex_color = structure_info[struct_id]['color_hex']
- # Convert hex to RGB
- r = int(hex_color[0:2], 16)
- g = int(hex_color[2:4], 16)
- b = int(hex_color[4:6], 16)
- rgb_image[i, j] = [r, g, b]
- else:
- # Black for background or unknown
- rgb_image[i, j] = [0, 0, 0]
- return rgb_image
- def interactive_viewer_advanced(annotation_data, structure_info):
- """
- Advanced interactive viewer with:
- - Slice navigation (slider + mouse wheel)
- - Colorbar
- - Adjustable color range (slider + manual input)
- - Axis switching
- - Rotation
- - Zoom and Pan
- - Structure name display
- - Color mode selection (ID vs Structure colors)
- """
- # Create figure and axis
- fig = plt.figure(figsize=(16, 10))
- # Main image axis
- ax_img = plt.axes([0.1, 0.30, 0.62, 0.60])
- # Colorbar axis
- ax_cbar = plt.axes([0.74, 0.30, 0.02, 0.60])
- # Info panel axis (for displaying structure details)
- ax_info = plt.axes([0.78, 0.65, 0.20, 0.25])
- ax_info.axis('off')
- # Radio buttons for color mode
- ax_radio = plt.axes([0.78, 0.92, 0.15, 0.07])
- # Slider axes
- ax_slice = plt.axes([0.1, 0.20, 0.62, 0.03])
- ax_vmin = plt.axes([0.1, 0.15, 0.62, 0.03])
- ax_vmax = plt.axes([0.1, 0.10, 0.62, 0.03])
- # Text box axes for manual input
- ax_text_vmin = plt.axes([0.1, 0.05, 0.08, 0.03])
- ax_text_vmax = plt.axes([0.22, 0.05, 0.08, 0.03])
- # Button axes for switching views
- ax_btn_coronal = plt.axes([0.78, 0.57, 0.08, 0.04])
- ax_btn_sagittal = plt.axes([0.87, 0.57, 0.08, 0.04])
- ax_btn_axial = plt.axes([0.78, 0.52, 0.08, 0.04])
- # Button axes for rotation
- ax_btn_rot_ccw = plt.axes([0.78, 0.45, 0.08, 0.04])
- ax_btn_rot_cw = plt.axes([0.87, 0.45, 0.08, 0.04])
- # Button axes for zoom
- ax_btn_zoom_in = plt.axes([0.78, 0.38, 0.08, 0.04])
- ax_btn_zoom_out = plt.axes([0.87, 0.38, 0.08, 0.04])
- # Other buttons
- ax_btn_reset = plt.axes([0.78, 0.31, 0.08, 0.04])
- ax_btn_apply = plt.axes([0.34, 0.05, 0.06, 0.03])
- ax_btn_reset_view = plt.axes([0.87, 0.31, 0.08, 0.04])
- # Initialize parameters
- current_axis = [0] # 0=coronal, 1=sagittal, 2=axial
- rotation_angle = [0] # Current rotation angle in degrees
- zoom_level = [1.0] # Current zoom level
- current_slice_idx = [annotation_data.shape[0] // 2] # Store current slice index
- color_mode = ['by_id'] # 'by_id' or 'by_structure'
- # Get initial min/max values
- data_min = float(np.min(annotation_data))
- data_max = float(np.max(annotation_data))
- axis_names = ['Coronal', 'Sagittal', 'Axial']
- # Create function to get slice data
- def get_slice_data(slice_idx=None, axis=None, rotation=None):
- """Get current slice data based on axis and rotation"""
- if slice_idx is None:
- slice_idx = current_slice_idx[0]
- if axis is None:
- axis = current_axis[0]
- if rotation is None:
- rotation = rotation_angle[0]
- slice_idx = int(slice_idx)
- if axis == 0:
- slice_data = annotation_data[slice_idx, :, :].T
- elif axis == 1:
- slice_data = annotation_data[:, slice_idx, :].T
- else:
- slice_data = annotation_data[:, :, slice_idx].T
- # Apply rotation
- k = rotation // 90 # Number of 90-degree rotations
- if k != 0:
- slice_data = np.rot90(slice_data, k)
- return slice_data
- # Create initial image
- initial_slice = get_slice_data()
- # Display image (initially by ID)
- img = ax_img.imshow(initial_slice, cmap='nipy_spectral', origin='lower',
- vmin=data_min, vmax=data_max)
- ax_img.set_title(f'{axis_names[current_axis[0]]} Slice {current_slice_idx[0]} (Rotation: {rotation_angle[0]}°) - Color by ID',
- fontsize=14, fontweight='bold')
- ax_img.axis('on')
- # Add colorbar
- cbar = plt.colorbar(img, cax=ax_cbar)
- cbar.set_label('Structure ID', rotation=270, labelpad=20, fontsize=12)
- # Info panel text
- info_text = ax_info.text(0.05, 0.95, 'Hover over image\nfor structure info',
- transform=ax_info.transAxes,
- fontsize=10, verticalalignment='top',
- family='monospace',
- bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
- # Create radio buttons for color mode
- radio = RadioButtons(ax_radio, ('Color by ID', 'Color by Structure'))
- # Create sliders
- slider_slice = Slider(ax_slice, 'Slice', 0, annotation_data.shape[current_axis[0]]-1,
- valinit=current_slice_idx[0], valstep=1)
- slider_vmin = Slider(ax_vmin, 'Min ID', data_min, data_max,
- valinit=data_min, valstep=1)
- slider_vmax = Slider(ax_vmax, 'Max ID', data_min, data_max,
- valinit=data_max, valstep=1)
- # Create text boxes for manual input
- text_box_vmin = TextBox(ax_text_vmin, 'Min:', initial=str(int(data_min)))
- text_box_vmax = TextBox(ax_text_vmax, 'Max:', initial=str(int(data_max)))
- # Create buttons
- btn_coronal = Button(ax_btn_coronal, 'Coronal')
- btn_sagittal = Button(ax_btn_sagittal, 'Sagittal')
- btn_axial = Button(ax_btn_axial, 'Axial')
- btn_rot_ccw = Button(ax_btn_rot_ccw, '↺ 90°')
- btn_rot_cw = Button(ax_btn_rot_cw, '↻ 90°')
- btn_zoom_in = Button(ax_btn_zoom_in, 'Zoom +')
- btn_zoom_out = Button(ax_btn_zoom_out, 'Zoom -')
- btn_reset = Button(ax_btn_reset, 'Reset Range')
- btn_apply = Button(ax_btn_apply, 'Apply')
- btn_reset_view = Button(ax_btn_reset_view, 'Reset View')
- # Text for displaying current structure ID under cursor
- text_info = ax_img.text(0.02, 0.98, '', transform=ax_img.transAxes,
- fontsize=9, verticalalignment='top',
- bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.9))
- def update_image():
- """Update the displayed image"""
- current_slice_idx[0] = int(slider_slice.val)
- slice_data = get_slice_data()
- if color_mode[0] == 'by_structure':
- # Create RGB image using structure colors
- rgb_image = create_color_mapped_image(slice_data, structure_info)
- img.set_data(rgb_image)
- img.set_cmap(None) # Remove colormap for RGB
- img.set_clim(None, None)
- # Hide colorbar for structure color mode
- cbar.ax.set_visible(False)
- title_suffix = "Color by Structure"
- # Disable range sliders
- slider_vmin.ax.set_visible(False)
- slider_vmax.ax.set_visible(False)
- text_box_vmin.ax.set_visible(False)
- text_box_vmax.ax.set_visible(False)
- btn_apply.ax.set_visible(False)
- btn_reset.ax.set_visible(False)
- else:
- # Use ID-based coloring
- img.set_data(slice_data)
- img.set_cmap('nipy_spectral')
- vmin = slider_vmin.val
- vmax = slider_vmax.val
- img.set_clim(vmin, vmax)
- # Show colorbar for ID mode
- cbar.ax.set_visible(True)
- title_suffix = "Color by ID"
- # Enable range sliders
- slider_vmin.ax.set_visible(True)
- slider_vmax.ax.set_visible(True)
- text_box_vmin.ax.set_visible(True)
- text_box_vmax.ax.set_visible(True)
- btn_apply.ax.set_visible(True)
- btn_reset.ax.set_visible(True)
- img.set_extent([0, slice_data.shape[1], 0, slice_data.shape[0]])
- ax_img.set_title(f'{axis_names[current_axis[0]]} Slice {current_slice_idx[0]} (Rotation: {rotation_angle[0]}°) - {title_suffix}',
- fontsize=14, fontweight='bold')
- fig.canvas.draw_idle()
- def update_slice(val):
- """Update the displayed slice"""
- update_image()
- def on_scroll(event):
- """Handle mouse wheel scroll to navigate slices"""
- if event.inaxes == ax_img:
- # Get current slice and max slice
- current_slice = int(slider_slice.val)
- max_slice = annotation_data.shape[current_axis[0]] - 1
- # Scroll up = next slice, scroll down = previous slice
- if event.button == 'up':
- new_slice = min(current_slice + 1, max_slice)
- elif event.button == 'down':
- new_slice = max(current_slice - 1, 0)
- else:
- return
- # Update slider (this will trigger update_image through the slider callback)
- slider_slice.set_val(new_slice)
- def update_vmin(val):
- """Update minimum color value"""
- if color_mode[0] == 'by_id':
- vmin = slider_vmin.val
- vmax = slider_vmax.val
- if vmin < vmax:
- img.set_clim(vmin=vmin)
- text_box_vmin.set_val(str(int(vmin)))
- fig.canvas.draw_idle()
- else:
- slider_vmin.set_val(vmax - 1)
- def update_vmax(val):
- """Update maximum color value"""
- if color_mode[0] == 'by_id':
- vmin = slider_vmin.val
- vmax = slider_vmax.val
- if vmax > vmin:
- img.set_clim(vmax=vmax)
- text_box_vmax.set_val(str(int(vmax)))
- fig.canvas.draw_idle()
- else:
- slider_vmax.set_val(vmin + 1)
- def apply_manual_range(event):
- """Apply manually entered min/max values"""
- if color_mode[0] == 'by_id':
- try:
- vmin = float(text_box_vmin.text)
- vmax = float(text_box_vmax.text)
- if vmin >= vmax:
- print("Error: Min ID must be less than Max ID")
- return
- if vmin < data_min or vmax > data_max:
- print(f"Warning: Values outside data range [{data_min}, {data_max}]")
- slider_vmin.set_val(vmin)
- slider_vmax.set_val(vmax)
- img.set_clim(vmin=vmin, vmax=vmax)
- fig.canvas.draw_idle()
- print(f"Applied range: [{vmin}, {vmax}]")
- except ValueError:
- print("Error: Please enter valid numbers")
- def submit_vmin(text):
- """Handle text box submit for vmin"""
- apply_manual_range(None)
- def submit_vmax(text):
- """Handle text box submit for vmax"""
- apply_manual_range(None)
- def change_color_mode(label):
- """Change between ID and structure color modes"""
- if label == 'Color by ID':
- color_mode[0] = 'by_id'
- else:
- color_mode[0] = 'by_structure'
- update_image()
- def rotate_ccw(event):
- """Rotate counter-clockwise by 90 degrees"""
- rotation_angle[0] = (rotation_angle[0] - 90) % 360
- update_image()
- def rotate_cw(event):
- """Rotate clockwise by 90 degrees"""
- rotation_angle[0] = (rotation_angle[0] + 90) % 360
- update_image()
- def zoom_in(event):
- """Zoom in by reducing view limits"""
- zoom_level[0] *= 1.3
- xlim = ax_img.get_xlim()
- ylim = ax_img.get_ylim()
- x_center = (xlim[0] + xlim[1]) / 2
- y_center = (ylim[0] + ylim[1]) / 2
- x_range = (xlim[1] - xlim[0]) / 1.3
- y_range = (ylim[1] - ylim[0]) / 1.3
- ax_img.set_xlim(x_center - x_range/2, x_center + x_range/2)
- ax_img.set_ylim(y_center - y_range/2, y_center + y_range/2)
- fig.canvas.draw_idle()
- def zoom_out(event):
- """Zoom out by expanding view limits"""
- zoom_level[0] /= 1.3
- xlim = ax_img.get_xlim()
- ylim = ax_img.get_ylim()
- x_center = (xlim[0] + xlim[1]) / 2
- y_center = (ylim[0] + ylim[1]) / 2
- x_range = (xlim[1] - xlim[0]) * 1.3
- y_range = (ylim[1] - ylim[0]) * 1.3
- # Don't zoom out beyond initial limits
- slice_data = get_slice_data()
- max_x = slice_data.shape[1]
- max_y = slice_data.shape[0]
- new_xlim = [max(0, x_center - x_range/2), min(max_x, x_center + x_range/2)]
- new_ylim = [max(0, y_center - y_range/2), min(max_y, y_center + y_range/2)]
- ax_img.set_xlim(new_xlim)
- ax_img.set_ylim(new_ylim)
- fig.canvas.draw_idle()
- def reset_view(event):
- """Reset zoom and pan to original view"""
- zoom_level[0] = 1.0
- slice_data = get_slice_data()
- ax_img.set_xlim(0, slice_data.shape[1])
- ax_img.set_ylim(0, slice_data.shape[0])
- fig.canvas.draw_idle()
- def switch_axis(new_axis):
- """Switch viewing axis"""
- current_axis[0] = new_axis
- rotation_angle[0] = 0 # Reset rotation when switching axis
- # Update slice slider range and value
- current_slice_idx[0] = annotation_data.shape[new_axis] // 2
- slider_slice.valmax = annotation_data.shape[new_axis] - 1
- slider_slice.ax.set_xlim(0, annotation_data.shape[new_axis] - 1)
- slider_slice.set_val(current_slice_idx[0])
- # Reset view
- reset_view(None)
- def reset_range(event):
- """Reset color range to full data range"""
- slider_vmin.set_val(data_min)
- slider_vmax.set_val(data_max)
- text_box_vmin.set_val(str(int(data_min)))
- text_box_vmax.set_val(str(int(data_max)))
- def on_mouse_move(event):
- """Display structure ID and name under cursor"""
- if event.inaxes == ax_img and event.xdata is not None and event.ydata is not None:
- # Get current slice data to determine dimensions
- slice_data = get_slice_data()
- x, y = int(event.xdata), int(event.ydata)
- if 0 <= x < slice_data.shape[1] and 0 <= y < slice_data.shape[0]:
- structure_id = int(slice_data[y, x])
- # Get structure information
- if structure_id in structure_info:
- info = structure_info[structure_id]
- name = info['name']
- acronym = info['acronym']
- # Update small overlay text
- text_info.set_text(f'Pos: ({x}, {y})\nID: {structure_id}\n{acronym}')
- # Update info panel with word wrapping for long names
- info_display = f"Structure ID: {structure_id}\n\n"
- info_display += f"Acronym: {acronym}\n\n"
- info_display += f"Name:\n{name}\n\n"
- info_display += f"Position: ({x}, {y})"
- info_text.set_text(info_display)
- else:
- text_info.set_text(f'Pos: ({x}, {y})\nID: {structure_id}\n(Unknown)')
- info_text.set_text(f"Structure ID: {structure_id}\n\nName: Unknown\n\nPosition: ({x}, {y})")
- fig.canvas.draw_idle()
- # Connect callbacks
- slider_slice.on_changed(update_slice)
- slider_vmin.on_changed(update_vmin)
- slider_vmax.on_changed(update_vmax)
- text_box_vmin.on_submit(submit_vmin)
- text_box_vmax.on_submit(submit_vmax)
- radio.on_clicked(change_color_mode)
- btn_coronal.on_clicked(lambda event: switch_axis(0))
- btn_sagittal.on_clicked(lambda event: switch_axis(1))
- btn_axial.on_clicked(lambda event: switch_axis(2))
- btn_rot_ccw.on_clicked(rotate_ccw)
- btn_rot_cw.on_clicked(rotate_cw)
- btn_zoom_in.on_clicked(zoom_in)
- btn_zoom_out.on_clicked(zoom_out)
- btn_reset.on_clicked(reset_range)
- btn_apply.on_clicked(apply_manual_range)
- btn_reset_view.on_clicked(reset_view)
- fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)
- fig.canvas.mpl_connect('scroll_event', on_scroll) # Add scroll event
- plt.show()
- # Main execution
- if __name__ == "__main__":
- # Define file paths
- annotation_filepath = r"C:\DATA\MFA\uCT\uCT2CCF\data\ccf\annotation_25.nrrd"
- structure_tree_filepath = r"C:\DATA\MFA\uCT\uCT2CCF\data\ccf\structure_tree.json"
- print("Loading annotation file...")
- annotation_data, header = load_annotation(annotation_filepath)
- print(f"Annotation shape: {annotation_data.shape}")
- print(f"Unique structure IDs: {len(np.unique(annotation_data))}")
- print(f"Data type: {annotation_data.dtype}")
- print(f"Min ID: {np.min(annotation_data)}, Max ID: {np.max(annotation_data)}")
- print("\nLoading structure tree...")
- structure_info = load_structure_tree(structure_tree_filepath)
- print(f"Loaded {len(structure_info)} brain structures")
- # Print first few structures to verify loading
- if len(structure_info) > 0:
- print("\nSample structures:")
- for i, (struct_id, info) in enumerate(list(structure_info.items())[:5]):
- print(f" ID {struct_id}: {info['acronym']} - {info['name']} (Color: #{info['color_hex']})")
- print("\nLaunching interactive viewer...")
- print("- Use radio buttons to switch between 'Color by ID' and 'Color by Structure'")
- print("- Use 'Slice' slider to navigate through slices")
- print("- Scroll mouse wheel over image to move through slices (up=next, down=previous)")
- print("- In 'Color by ID' mode: Use sliders/text boxes to adjust color range")
- print("- In 'Color by Structure' mode: Each region shows its anatomical color")
- print("- Click '↺ 90°' or '↻ 90°' to rotate the view")
- print("- Click 'Zoom +' or 'Zoom -' to zoom in/out")
- print("- Click 'Reset View' to reset zoom and rotation")
- print("- Hover mouse over image to see structure name and ID")
- interactive_viewer_advanced(annotation_data, structure_info)
annotation_loader.py at commit e73b4cc, under GPL-3.0 · at the source
Overview
Abstract
Mesoscopic functional brain mapping is essential for a better understanding of various brain functions and dysfunctions. However, accessing distributed neural circuits in mammalian brain regions remains a significant challenge. While fiber photometry is a versatile optical approach, existing methods often suffer from invasiveness and limited scalability. Here we present an affordable multifiber array (MFA)‐based photometry system to monitor neural signals across multiple regions. Our system comprises a custom‐designed MFA utilizing 50‐μm diameter optical fibers and off‐the‐shelf optical components. To demonstrate the system's versatility, we monitored GABAergic population activity using jGCaMP8s across multiple brain regions in head‐fixed, awake mice. By combining this approach with pupillometry, we identified state‐dependent, region‐specific GABAergic dynamics. Our MFA‐based photometry system opens new avenues for investigating state‐dependent neural dynamics at the mesoscopic level. To facilitate wider adoption, all code and resources are publicly available on GitHub (https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above.
Sakata-Lab/mfaCTpy
e73b4cc0b7151b381d0d81fa2411a12c4b336743, 25 June 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
12 files
- src/
annotation_loader.py — Python, 521 lines - src/
data_loader.py — Python, 207 lines - src/
dicom_loader.py — Python, 138 lines - src/
fiber_tracker.py — Python, 1,266 lines - src/
fiber_visualizer_3d.py — Python, 620 lines - src/
landmark_registration.py — Python, 1,134 lines - src/
midline_alignment.py — Python, 1,028 lines - src/
movie_creator.py — Python, 822 lines - src/
preprocessing.py — Python, 440 lines - src/
registered_img_visualiza — Python, 399 linestion.py - LICENSE — License, 674 lines
- README.md — Text, 623 lines
Sakata-Lab/MFA
48f7ec65ead581f733ee3c718848428eed6bc7f2, 25 June 2026Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
3 files
- MFA_img_processing_workf
low.mlx — MATLAB, not shown here - LICENSE — License, 674 lines
- README.md — Text, 39 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 11 scripts, each with its path and the digest of its content;
- no match between paragraphs and code yet;
- 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 Statement
Code and resources are available on GitHub (https://
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 2, 28 September 2026
- Publisher: — → Wiley
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 5 keywords, 9 MeSH terms, 2 funders, 64 references.
Cite
This paper
Bradai, M., Merkler, M., Gil, G., Davie, R., & Sakata, S. (2026). Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain. The European journal of neuroscience, 63(12), e70582. https://
BibTeX
@article{bradai2026multi
author = {Bradai, Manil and Merkler, Mirna and Gil, Gabriela and Davie, Rebecca and Sakata, Shuzo},
title = {{Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain}},
journal = {The European journal of neuroscience},
year = {2026},
month = jun,
volume = {63},
number = {12},
pages = {e70582},
publisher = {Wiley},
issn = {0953-816X},
doi = {10.1111/
url = {https://
pmid = {42306926},
pmcid = {PMC13273707}
}
RIS
TY - JOUR
AU - Bradai, Manil
AU - Merkler, Mirna
AU - Gil, Gabriela
AU - Davie, Rebecca
AU - Sakata, Shuzo
TI - Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain
T2 - The European journal of neuroscience
J2 - Eur J Neurosci
PY - 2026
DA - 2026/
VL - 63
IS - 12
SP - e70582
SN - 0953-816X
PB - Wiley
DO - 10.1111/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1111/
"type": "article-journal",
"title": "Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain",
"container-title": "The European journal of neuroscience",
"author": [
{
"family": "Bradai",
"given": "Manil"
},
{
"family": "Merkler",
"given": "Mirna"
},
{
"family": "Gil",
"given": "Gabriela"
},
{
"family": "Davie",
"given": "Rebecca"
},
{
"family": "Sakata",
"given": "Shuzo"
}
],
"container-title-short":
"volume": "63",
"issue": "12",
"page": "e70582",
"DOI": "10.1111/
"PMID": "42306926",
"PMCID": "PMC13273707",
"ISSN": "0953-816X",
"publisher": "Wiley",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
1
]
]
}
}
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: iScienceIn common: SimpleITK, tifffile, OpenCV, 6 other tools, optical imaging (calcium, voltage, 2-photon), systems, 2 references
- [2] doi:10.7554/elife.109717 [code]
- Retrosplenial cortex enables context-dependent goal-directed sensorimotor transformation.Journal: eLifeIn common: tifffile, OpenCV, scikit-image, 5 other tools, systems, mouse, 3 references
- [3] doi:10.1038/s41467-026-72710-3 [code]
- A modular multi-color fluorescence microscope for simultaneous tracking of cellular activity and behavior.Journal: Nature communicationsIn common: tifffile, OpenCV, scikit-image, 5 other tools, optical imaging (calcium, voltage, 2-photon), 3 references
- [4] doi:10.1038/s41593-026-02232-0 [code]
- Entorhinal cortex represents task-relevant remote locations independently of CA1.Journal: Nature neuroscienceIn common: OpenCV, scikit-image, Pillow, 4 other tools, systems, mouse, 4 references
- [5] doi:10.1364/boe.605322 [code]
- Generalized plaque digitization framework for multi-dimensional mesoscopic images.Journal: Biomedical optics expressIn common: SimpleITK, tifffile, OpenCV, 6 other tools, mouse, 1 reference
- [6] doi: [code]
- Real-time closed-loop feedback system for mouse mesoscale cortical signal and movement controlJournal: eLifeIn common: tifffile, OpenCV, scikit-image, 5 other tools, optical imaging (calcium, voltage, 2-photon), mouse, 2 references
- [7] doi:10.21203/rs.3.rs-10218667/v1 [code]
- Combining ultra-flexible electrodes with two-photon imaging to illuminate brain-wide neural dynamicsJournal: Research Square (preprint)In common: SciPy, Matplotlib, NumPy, optical imaging (calcium, voltage, 2-photon), systems, 6 references
- [8] doi:10.3389/fnins.2026.1893619 [code]
- Direct laser carbonization of parylene-C toward microelectrodes for &
lt;i& gt;in vivo& lt;/ i& gt; action potential detection. Journal: Frontiers in neuroscienceIn common: scikit-image, Pillow, pandas, 3 other tools, 5 references - [9] doi:10.1016/j.crmeth.2026.101481 [code]
- A hybrid micro-ECoG for functionally targeted multi-site and multi-scale investigation.Journal: Cell reports methodsIn common: systems, 8 references
- [10] doi:10.7554/elife.110277 [code]
- Functional imaging of nine distinct neuronal populations under a miniscope in freely behaving animals.Journal: eLifeIn common: SimpleITK, tifffile, OpenCV, 4 other tools, optical imaging (calcium, voltage, 2-photon), systems, mouse, 1 reference
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 11 scripts, and 0 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:27cf71991b575e57…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
