# install cell skipped during CI (deps preinstalled into system Python)
⚠️ Restart runtime after install
The install may upgrade packages already loaded in the kernel. Go to Runtime → Restart session, then Run all cells below (skip this install cell on re-run).
# IBL - Anatomical Localization of Widefield Imaging Data with ndx-anatomical-localization¶
This notebook shows how to stream and visualise the atlas-registration and
anatomical-coordinate data from DANDI:001712 using the
ndx-anatomical-localization
NWB extension.
Extension overview¶
| Type | Where | Description |
|---|---|---|
AtlasRegistration |
nwbfile.lab_meta_data["atlas_registration"] |
Images + affine transform + landmarks |
Localization |
nwbfile.lab_meta_data["localization"] |
Per-pixel coordinates + region masks + coordinate tables |
AffineTransformation |
inside AtlasRegistration |
3×3 homogeneous matrix: source px → registered px |
Landmarks |
inside AtlasRegistration |
Manually placed control-point table |
AnatomicalCoordinatesImage |
localization.anatomical_coordinates_images |
Per-pixel (x, y, z) + region acronym arrays |
AnatomicalCoordinatesTable |
localization.anatomical_coordinates_tables |
3-D coordinates for discrete objects (landmarks) |
Contents¶
- Setup and Data Access
- Atlas Registration
- Anatomical Coordinates Image
- Anatomical Coordinates Tables
- Extract Brain Region Activity
1. Setup and Data Access ¶
# IMPORTANT: import ndx_anatomical_localization BEFORE read_nwb.
# This executes all @register_class decorators so PyNWB maps
# custom types (e.g. BrainRegionMasks) to the correct Python classes.
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import ndx_anatomical_localization # noqa: F401
import numpy as np
from matplotlib.colors import ListedColormap
from skimage.transform import SimilarityTransform
plt.rcParams["figure.figsize"] = (12, 6)
plt.rcParams["font.size"] = 10
from load_nwb_utils import *
dandiset_id = "001712"
subject_id = "FD-28" # Example subject
session_id = "81f90b18-e61c-4d32-bbce-3e0c5f33f06c" # EID for the session
# Choose data source (DANDI streaming or local)
USE_DANDI = True # Set to False to use local files
if USE_DANDI:
nwbfile, io = load_nwb_from_dandi(dandiset_id, subject_id, session_id, description="raw")
else:
# TODO Specify your local directory path
local_directory = f"E:/IBL-widefield-nwbfiles/full/"
nwbfile, io = load_nwb_local(local_directory, subject_id, session_id, description="raw")
print("=== SESSION INFORMATION ===")
print(f"Experiment description:\n {nwbfile.experiment_description}")
print(f"Session description:\n {nwbfile.session_description}")
print(f"Session start time:\n {nwbfile.session_start_time}")
=== SESSION INFORMATION === Experiment description: In dynamic environments, updating beliefs based on past experiences (priors) is essential for optimal decision-making. Prior utilization is often impaired in psychiatric disorders, affecting perception and behavior. We investigate how Neurexin1α (Nrxn1α) loss-of-function disrupts this process, providing insight into circuit deficits underlying sensorimotor dysfunction. While the synaptic role of Nrxn1α is well studied, its impact on network dynamics and decision-making behavior remain unclear. Using widefield calcium imaging, we assess cortex-wide activity in mice performing a two-choice task to probe how priors influence visually-guided decisions. This task requires the mouse to combine sensory evidence with the prior probability over the stimulus side. We find Nrxn1α KO mice underutilized priors and were slower to update choices based on feedback. During decision-making, cortex-wide cortical activity is both elevated and increasingly correlated in Nrxn1α KO mice, independent of task period. Moreover, a larger fraction of cortical variance was explained by movement variables, consistent with stronger coupling of cortical activity to motor signals and a bias toward movement-related dynamics. These findings suggest that core computations underlying decision-making, such as integrating past experience with current evidence, depend on intact synaptic mechanisms shaped by genes like Nrxn1α. Session description: The task protocol(s) performed in this experimental session: 1. Biased choice world — the standard IBL data-collection task for trained mice. A Gabor patch appears at ±35° azimuth and the mouse turns a wheel to bring it to the center. Correct responses earn a water reward (~1.5 µL); incorrect responses trigger white noise and a 2s timeout. Stimulus probability alternates between 80/20 and 20/80 blocks (starting with a 50/50 block), with block lengths drawn from a truncated exponential distribution (min 20, max 100 trials). Full contrast set: [1.0, 0.25, 0.125, 0.0625, 0.0]. Session start time: 2023-11-14 12:10:33.757227-08:00
2. Atlas Registration ¶
AtlasRegistration lives at nwbfile.lab_meta_data["atlas_registration"] and groups
all outputs of the atlas-registration pipeline:
| Field | Type | Description |
|---|---|---|
source_image |
GrayscaleImage |
Mean FOV in camera space |
registered_image |
GrayscaleImage |
FOV after affine warp to atlas space |
atlas_projection |
GrayscaleImage |
2-D Allen CCF dorsal-cortex reference |
affine_transformation |
AffineTransformation |
3×3 homogeneous matrix |
landmarks |
Landmarks |
Manually placed control-point table |
atlas_registration = nwbfile.lab_meta_data["atlas_registration"]
atlas_registration
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[4], line 1 ----> 1 atlas_registration = nwbfile.lab_meta_data["atlas_registration"] 2 atlas_registration File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/utils.py:1069, in LabelledDict.__getitem__(self, args) 1067 return super().__getitem__(val) 1068 else: -> 1069 return super().__getitem__(key) KeyError: 'atlas_registration'
Summary Images ¶
source_img = atlas_registration.source_image.data[:] # raw FOV (camera space)
registered_img = atlas_registration.registered_image.data[:] # affine-warped to atlas space
atlas_proj = atlas_registration.atlas_projection.data[:] # Allen CCF dorsal-cortex reference
print(f"source_image shape : {source_img.shape}")
print(f"registered_image shape : {registered_img.shape}")
print(f"atlas_projection shape : {atlas_proj.shape}")
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[5], line 1 ----> 1 source_img = atlas_registration.source_image.data[:] # raw FOV (camera space) 2 registered_img = atlas_registration.registered_image.data[:] # affine-warped to atlas space 3 atlas_proj = atlas_registration.atlas_projection.data[:] # Allen CCF dorsal-cortex reference 4 NameError: name 'atlas_registration' is not defined
Affine Transformation ¶
AffineTransformation stores a 3×3 matrix in homogeneous coordinates that maps
pixel positions from the source (camera) image to the registered (atlas-aligned)
image. The inverse maps registered pixels back to source space.
affine_transform = atlas_registration.affine_transformation
M = SimilarityTransform(affine_transform.affine_matrix)
print("Affine matrix (3×3 homogeneous — source px → registered px):")
for row in affine_transform.affine_matrix:
print(f" [{row[0]: .5f} {row[1]: .5f} {row[2]: .5f}]")
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[6], line 1 ----> 1 affine_transform = atlas_registration.affine_transformation 2 M = SimilarityTransform(affine_transform.affine_matrix) 3 4 print("Affine matrix (3×3 homogeneous — source px → registered px):") NameError: name 'atlas_registration' is not defined
Landmarks Table ¶
Landmarks is a DynamicTable of manually identified control points used to
estimate the affine transform. Each row is one anatomical landmark.
| Column | Description |
|---|---|
source_x, source_y |
Pixel coords in the raw (source) FOV |
registered_x, registered_y |
Pixel coords in the registered (atlas-aligned) FOV |
reference_x, reference_y |
Pixel coords in the Allen dorsal-cortex atlas projection |
landmark_labels |
Anatomical label string (e.g. "OB_center", "RSP_base") |
bregma_offset_x, bregma_offset_y |
Bregma position in atlas projection pixel coords |
resolution |
µm per pixel of the atlas reference projection |
landmarks = atlas_registration.landmarks
print(landmarks.description)
landmarks_df = landmarks[:]
landmarks_df
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[7], line 1 ----> 1 landmarks = atlas_registration.landmarks 2 print(landmarks.description) 3 landmarks_df = landmarks[:] 4 landmarks_df NameError: name 'atlas_registration' is not defined
fig, axes = plt.subplots(1, 3, figsize=(21, 6), dpi=100)
# --- Source image ---
axes[0].imshow(source_img, cmap="gray")
axes[0].plot(
landmarks_df["source_x"], landmarks_df["source_y"],
"g+", ms=16, mew=2, label="Landmarks (source)",
)
for _, row in landmarks_df.iterrows():
axes[0].text(
row["source_x"], row["source_y"], row["landmark_labels"],
color="w", fontsize=8, va="bottom", ha="center",
)
axes[0].set_title("Source image (raw FOV, camera space)")
axes[0].axis("off")
axes[0].legend(loc="lower right", fontsize=9, frameon=True, facecolor="black", framealpha=0.5)
# --- Atlas projection ---
proj_masked = np.ma.masked_equal(atlas_proj, 0)
cmap_jet = plt.get_cmap("jet").copy()
cmap_jet.set_bad(alpha=0)
axes[1].imshow(proj_masked, cmap=cmap_jet)
axes[1].plot(
landmarks_df["reference_x"], landmarks_df["reference_y"],
"w+", ms=16, mew=2, label="Landmarks (reference)",
)
for _, row in landmarks_df.iterrows():
axes[1].text(
row["reference_x"], row["reference_y"], row["landmark_labels"],
color="w", fontsize=8, va="bottom", ha="center",
)
axes[1].set_title("Allen CCF — dorsal cortex projection")
axes[1].axis("off")
axes[1].legend(loc="lower right", fontsize=9, frameon=True, facecolor="black", framealpha=0.5)
# --- Registered image ---
axes[2].imshow(registered_img, cmap="gray")
axes[2].plot(
landmarks_df["registered_x"], landmarks_df["registered_y"],
"rx", ms=16, mew=2, label="Landmarks (registered)",
)
for _, row in landmarks_df.iterrows():
axes[2].text(
row["registered_x"], row["registered_y"], row["landmark_labels"],
color="w", fontsize=8, va="bottom", ha="center",
)
axes[2].set_title("Registered image (atlas space)")
axes[2].axis("off")
axes[2].legend(loc="lower right", fontsize=9, frameon=True, facecolor="black", framealpha=0.5)
plt.suptitle("AtlasRegistration", fontsize=13)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[8], line 4 1 fig, axes = plt.subplots(1, 3, figsize=(21, 6), dpi=100) 2 3 # --- Source image --- ----> 4 axes[0].imshow(source_img, cmap="gray") 5 axes[0].plot( 6 landmarks_df["source_x"], landmarks_df["source_y"], 7 "g+", ms=16, mew=2, label="Landmarks (source)", NameError: name 'source_img' is not defined
3. Anatomical Coordinates Image ¶
AnatomicalCoordinatesImage assigns a physical 3-D coordinate and a brain-region
label to every pixel in an image. It lives under
nwbfile.lab_meta_data["localization"].anatomical_coordinates_images.
IBL Bregma (RAS)
| Name | Linked to | Description |
|---|---|---|
AnatomicalCoordinatesImageIBLBregma |
GrayscaleImage (RegisteredImage) |
Registered-space per-pixel IBL bregma coordinates |
Coordinate system:
| Array | Shape | Description |
|---|---|---|
x |
(H, W) |
Mediolateral (positive = Right) |
y |
(H, W) |
Anteroposterior (positive = Anterior) |
z |
(H, W) |
Dorsoventral (positive = Superior; ≈ 0 for 2-D FOV) |
brain_region |
(H, W) |
Allen acronym string ("out-of-atlas" outside atlas) |
localization = nwbfile.lab_meta_data["localization"]
aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageIBLBregma"]
space = aci.space
x_coords = aci.x[:] # ML in µm
y_coords = aci.y[:] # AP in µm
region_names = np.asarray(aci.brain_region[:])
in_atlas = region_names != "out-of-atlas"
print(f"Name : {aci.name}")
print(f"Description : {aci.description}")
print(f"Space : {space.space_name}")
print(f" Origin : {space.origin}")
print(f" Units : {space.units}")
print(f" Orientation : {space.orientation} (x={space.orientation[0]}, y={space.orientation[1]}, z={space.orientation[2]})")
print(f"Image shape : {aci.image.data[:].shape}")
print(f"ML (x) range : [{x_coords[in_atlas].min():.0f}, {x_coords[in_atlas].max():.0f}] µm")
print(f"AP (y) range : [{y_coords[in_atlas].min():.0f}, {y_coords[in_atlas].max():.0f}] µm")
print(f"Brain regions : {len(np.unique(region_names[in_atlas]))} unique Allen acronyms in atlas")
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[9], line 1 ----> 1 localization = nwbfile.lab_meta_data["localization"] 2 aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageIBLBregma"] 3 4 space = aci.space File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/utils.py:1069, in LabelledDict.__getitem__(self, args) 1067 return super().__getitem__(val) 1068 else: -> 1069 return super().__getitem__(key) KeyError: 'localization'
# Brain region overlay on the registered image
background = "out-of-atlas"
names = np.unique(region_names)
names = names[names != background]
n = len(names)
name_to_idx = {name: i + 1 for i, name in enumerate(names)}
idx_img = np.zeros(region_names.shape, dtype=np.int16)
for name, i in name_to_idx.items():
idx_img[region_names == name] = i
idx_masked = np.ma.masked_where(idx_img == 0, idx_img)
base_cmap = plt.get_cmap("tab20b", max(n, 1))
colors = np.vstack([[0, 0, 0, 0], base_cmap(np.arange(n))])
region_cmap = ListedColormap(colors)
region_cmap.set_bad(alpha=0)
fig, ax = plt.subplots(figsize=(9, 8), dpi=100)
ax.imshow(registered_img, cmap="gray")
ax.imshow(idx_masked, cmap=region_cmap, alpha=0.35, interpolation="nearest")
ax.plot(
landmarks_df["registered_x"], landmarks_df["registered_y"],
"w+", ms=14, mew=2, label="Landmarks",
)
ax.set_title(
f"AnatomicalCoordinatesImage — brain region overlay\n({n} regions, IBL Bregma, registered space)",
fontsize=11,
)
ax.axis("off")
handles = [
mpatches.Patch(color=region_cmap(name_to_idx[name]), label=name)
for name in names[::2] # every other region to keep legend readable
]
ax.legend(
handles=handles,
loc="center left", bbox_to_anchor=(1.02, 0.5),
frameon=True, title="Regions (every other)",
fontsize=7, title_fontsize=8,
)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[10], line 3 1 # Brain region overlay on the registered image 2 background = "out-of-atlas" ----> 3 names = np.unique(region_names) 4 names = names[names != background] 5 n = len(names) 6 name_to_idx = {name: i + 1 for i, name in enumerate(names)} NameError: name 'region_names' is not defined
Allen CCF (PIR)
| Name | Linked to | Description |
|---|---|---|
AnatomicalCoordinatesImageCCFv3 |
GrayscaleImage (RegisteredImage) |
Registered-space per-pixel Allen CCF coordinates |
AnatomicalCoordinatesCCFv3MappedOnSourceImage |
GrayscaleImage (SourceImage) |
Source-space per-pixel Allen CCF coordinates |
Coordinate system:
| Array | Shape | Description |
|---|---|---|
x |
(H, W) |
Anteroposterior (positive = Anterior) |
y |
(H, W) |
Dorsoventral (positive = Superior) |
z |
(H, W) |
Mediolateral (positive = Right) |
brain_region |
(H, W) |
Allen acronym string ("out-of-atlas" outside atlas) |
localization = nwbfile.lab_meta_data["localization"]
aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"]
space = aci.space
x_coords = aci.x[:] # ML in µm
y_coords = aci.y[:] # AP in µm
region_names = np.asarray(aci.brain_region[:])
in_atlas = region_names != "out-of-atlas"
print(f"Name : {aci.name}")
print(f"Description : {aci.description}")
print(f"Space : {space.space_name}")
print(f" Origin : {space.origin}")
print(f" Units : {space.units}")
print(f" Orientation : {space.orientation} (x={space.orientation[0]}, y={space.orientation[1]}, z={space.orientation[2]})")
print(f"Image shape : {aci.image.data[:].shape}")
print(f"ML (x) range : [{x_coords[in_atlas].min():.0f}, {x_coords[in_atlas].max():.0f}] µm")
print(f"AP (y) range : [{y_coords[in_atlas].min():.0f}, {y_coords[in_atlas].max():.0f}] µm")
print(f"Brain regions : {len(np.unique(region_names[in_atlas]))} unique Allen acronyms in atlas")
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[11], line 1 ----> 1 localization = nwbfile.lab_meta_data["localization"] 2 aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"] 3 4 space = aci.space File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/utils.py:1069, in LabelledDict.__getitem__(self, args) 1067 return super().__getitem__(val) 1068 else: -> 1069 return super().__getitem__(key) KeyError: 'localization'
# Brain region overlay on the registered image
background = "out-of-atlas"
names = np.unique(region_names)
names = names[names != background]
n = len(names)
name_to_idx = {name: i + 1 for i, name in enumerate(names)}
idx_img = np.zeros(region_names.shape, dtype=np.int16)
for name, i in name_to_idx.items():
idx_img[region_names == name] = i
idx_masked = np.ma.masked_where(idx_img == 0, idx_img)
base_cmap = plt.get_cmap("tab20b", max(n, 1))
colors = np.vstack([[0, 0, 0, 0], base_cmap(np.arange(n))])
region_cmap = ListedColormap(colors)
region_cmap.set_bad(alpha=0)
fig, ax = plt.subplots(figsize=(9, 8), dpi=100)
ax.imshow(registered_img, cmap="gray")
ax.imshow(idx_masked, cmap=region_cmap, alpha=0.35, interpolation="nearest")
ax.plot(
landmarks_df["registered_x"], landmarks_df["registered_y"],
"w+", ms=14, mew=2, label="Landmarks",
)
ax.set_title(
f"AnatomicalCoordinatesImage — brain region overlay\n({n} regions, Allen CCF, registered space)",
fontsize=11,
)
ax.axis("off")
handles = [
mpatches.Patch(color=region_cmap(name_to_idx[name]), label=name)
for name in names[::2] # every other region to keep legend readable
]
ax.legend(
handles=handles,
loc="center left", bbox_to_anchor=(1.02, 0.5),
frameon=True, title="Regions (every other)",
fontsize=7, title_fontsize=8,
)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[12], line 3 1 # Brain region overlay on the registered image 2 background = "out-of-atlas" ----> 3 names = np.unique(region_names) 4 names = names[names != background] 5 n = len(names) 6 name_to_idx = {name: i + 1 for i, name in enumerate(names)} NameError: name 'region_names' is not defined
localization = nwbfile.lab_meta_data["localization"]
aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesCCFv3MappedOnSourceImage"]
space = aci.space
x_coords = aci.x[:] # ML in µm
y_coords = aci.y[:] # AP in µm
region_names = np.asarray(aci.brain_region[:])
in_atlas = region_names != "out-of-atlas"
print(f"Name : {aci.name}")
print(f"Description : {aci.description}")
print(f"Space : {space.space_name}")
print(f" Origin : {space.origin}")
print(f" Units : {space.units}")
print(
f" Orientation : {space.orientation} (x={space.orientation[0]}, y={space.orientation[1]}, z={space.orientation[2]})"
)
print(f"Image shape : {aci.image.data[:].shape}")
print(f"ML (x) range : [{x_coords[in_atlas].min():.0f}, {x_coords[in_atlas].max():.0f}] µm")
print(f"AP (y) range : [{y_coords[in_atlas].min():.0f}, {y_coords[in_atlas].max():.0f}] µm")
print(f"Brain regions : {len(np.unique(region_names[in_atlas]))} unique Allen acronyms in atlas")
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In[13], line 1 ----> 1 localization = nwbfile.lab_meta_data["localization"] 2 aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesCCFv3MappedOnSourceImage"] 3 4 space = aci.space File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/utils.py:1069, in LabelledDict.__getitem__(self, args) 1067 return super().__getitem__(val) 1068 else: -> 1069 return super().__getitem__(key) KeyError: 'localization'
# Brain region overlay on the source image
background = "out-of-atlas"
names = np.unique(region_names)
names = names[names != background]
n = len(names)
name_to_idx = {name: i + 1 for i, name in enumerate(names)}
idx_img = np.zeros(region_names.shape, dtype=np.int16)
for name, i in name_to_idx.items():
idx_img[region_names == name] = i
idx_masked = np.ma.masked_where(idx_img == 0, idx_img)
base_cmap = plt.get_cmap("tab20b", max(n, 1))
colors = np.vstack([[0, 0, 0, 0], base_cmap(np.arange(n))])
region_cmap = ListedColormap(colors)
region_cmap.set_bad(alpha=0)
fig, ax = plt.subplots(figsize=(9, 8), dpi=100)
ax.imshow(source_img, cmap="gray")
ax.imshow(idx_masked, cmap=region_cmap, alpha=0.35, interpolation="nearest")
ax.plot(
landmarks_df["source_x"],
landmarks_df["source_y"],
"w+",
ms=14,
mew=2,
label="Landmarks",
)
ax.set_title(
f"AnatomicalCoordinatesImage — brain region overlay\n({n} regions, Allen CCF, source space)",
fontsize=11,
)
ax.axis("off")
handles = [
mpatches.Patch(color=region_cmap(name_to_idx[name]), label=name)
for name in names[::2] # every other region to keep legend readable
]
ax.legend(
handles=handles,
loc="center left",
bbox_to_anchor=(1.02, 0.5),
frameon=True,
title="Regions (every other)",
fontsize=7,
title_fontsize=8,
)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[14], line 3 1 # Brain region overlay on the source image 2 background = "out-of-atlas" ----> 3 names = np.unique(region_names) 4 names = names[names != background] 5 n = len(names) 6 name_to_idx = {name: i + 1 for i, name in enumerate(names)} NameError: name 'region_names' is not defined
CCFv3 coordinate sanity check ¶
The three cells below visualise the per-pixel CCFv3 coordinate fields and perform a quick sanity check on the landmark positions.
What to look for
| Map | Expected pattern |
|---|---|
| AP heatmap | Smooth gradient — more-anterior (smaller x) at the top of the image, more-posterior (larger x) at the bottom |
| DV heatmap | Nearly uniform — all dorsal-cortex pixels sit at roughly the same depth (~332 µm from the superior face) |
| ML heatmap | Smooth symmetric gradient — left hemisphere (smaller z) on one side, right hemisphere (larger z) on the other |
Landmark scatter (AP vs ML plane)
| Landmark | Expected position |
|---|---|
OB_left, OB_right |
Symmetric about the midline (~5 700 µm ML), at the anterior pole (large x) |
OB_center |
On the midline, same AP as OB_left / OB_right |
RSP_base |
On the midline, at the posterior pole (small x, since CCF PIR x increases posterior) |
# CCFv3 PIR orientation:
# x = Posterior (AP axis, increases anterior→posterior from ASL corner)
# y = Inferior (DV axis, increases superior→inferior)
# z = Right (ML axis, increases left→right)
#
# Sanity checks:
# AP map → should show a smooth anterior-to-posterior gradient top→bottom
# DV map → should be nearly uniform (~332 µm for dorsal-cortex surface)
# ML map → should show a symmetric left-to-right gradient
ccf_aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"]
ap_img = ccf_aci.x[:] # PIR x = AP (Posterior direction)
dv_img = ccf_aci.y[:] # PIR y = DV (Inferior direction)
ml_img = ccf_aci.z[:] # PIR z = ML (Right direction)
region_names_ccf = np.asarray(ccf_aci.brain_region[:])
in_atlas_ccf = region_names_ccf != "out-of-atlas"
ap_masked = np.where(in_atlas_ccf, ap_img, np.nan)
dv_masked = np.where(in_atlas_ccf, dv_img, np.nan)
ml_masked = np.where(in_atlas_ccf, ml_img, np.nan)
lm_df = landmarks[:] # already loaded in the Atlas-Registration section
def _add_landmarks(ax, df):
ax.plot(df["registered_x"], df["registered_y"], "w+", ms=14, mew=2, zorder=5)
for _, row in df.iterrows():
ax.text(
row["registered_x"],
row["registered_y"],
row["landmark_labels"],
color="white",
fontsize=8,
va="bottom",
ha="center",
zorder=6,
)
fig, axes = plt.subplots(1, 3, figsize=(22, 7))
# --- AP (x in PIR) ---
im0 = axes[0].imshow(ap_masked, cmap="coolwarm", interpolation="nearest")
_add_landmarks(axes[0], lm_df)
axes[0].set_title(
f"AP (x in CCFv3 PIR)\nAnterior ← small | Posterior → large\n"
f"range [{np.nanmin(ap_masked):.0f}, {np.nanmax(ap_masked):.0f}] µm",
fontsize=9,
)
axes[0].axis("off")
plt.colorbar(im0, ax=axes[0], label="µm from ASL corner", shrink=0.75)
# --- DV (y in PIR) — expect near-constant for a dorsal projection ---
im1 = axes[1].imshow(dv_masked, cmap="viridis", interpolation="nearest")
_add_landmarks(axes[1], lm_df)
axes[1].set_title(
f"DV (y in CCFv3 PIR)\nSuperior ← small | Inferior → large\n"
f"range [{np.nanmin(dv_masked):.0f}, {np.nanmax(dv_masked):.0f}] µm",
fontsize=9,
)
axes[1].axis("off")
plt.colorbar(im1, ax=axes[1], label="µm from ASL corner", shrink=0.75)
# --- ML (z in PIR) ---
im2 = axes[2].imshow(ml_masked, cmap="RdYlGn", interpolation="nearest")
_add_landmarks(axes[2], lm_df)
axes[2].set_title(
f"ML (z in CCFv3 PIR)\nLeft ← small | Right → large\n"
f"range [{np.nanmin(ml_masked):.0f}, {np.nanmax(ml_masked):.0f}] µm",
fontsize=9,
)
axes[2].axis("off")
plt.colorbar(im2, ax=axes[2], label="µm from ASL corner", shrink=0.75)
plt.suptitle(
"AnatomicalCoordinatesImageCCFv3 — per-pixel CCF coordinate fields\n"
"(out-of-atlas pixels shown as white / NaN; landmark crosses from registered image space)",
fontsize=12,
)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[15], line 11 7 # AP map → should show a smooth anterior-to-posterior gradient top→bottom 8 # DV map → should be nearly uniform (~332 µm for dorsal-cortex surface) 9 # ML map → should show a symmetric left-to-right gradient 10 ---> 11 ccf_aci = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"] 12 ap_img = ccf_aci.x[:] # PIR x = AP (Posterior direction) 13 dv_img = ccf_aci.y[:] # PIR y = DV (Inferior direction) 14 ml_img = ccf_aci.z[:] # PIR z = ML (Right direction) NameError: name 'localization' is not defined
# Landmark positions in the CCF AP–ML plane
# Expected anatomy:
# - OB (olfactory bulb) is at the anterior pole of the dorsal cortex
# - RSP (retrosplenial cortex) is near the posterior pole
# - OB_left and OB_right should be symmetric about the midline
# - OB_center and RSP_base should lie on the midline (ML ≈ 5700 µm in CCFv3)
#
# In CCFv3 PIR the AP axis runs: 0 µm (anterior face) → ~13 200 µm (posterior face)
# so SMALLER x values are more ANTERIOR.
ccf_lm = localization.anatomical_coordinates_tables["AnatomicalCoordinatesCCFv3"][:]
print("CCF landmark coordinates (PIR orientation, µm from ASL corner):")
print(f" {'Landmark':15s} {'AP (x) µm':>12s} {'DV (y) µm':>12s} {'ML (z) µm':>12s}")
print(" " + "-" * 53)
for _, row in ccf_lm.iterrows():
print(f" {row['brain_region']:15s} {row['x']:12.1f} {row['y']:12.1f} {row['z']:12.1f}")
# Derived sanity metrics
ob_left_ml = ccf_lm.loc[ccf_lm["brain_region"] == "OB_left", "z"].values[0]
ob_right_ml = ccf_lm.loc[ccf_lm["brain_region"] == "OB_right", "z"].values[0]
ob_center_ml = ccf_lm.loc[ccf_lm["brain_region"] == "OB_center", "z"].values[0]
ob_center_ap = ccf_lm.loc[ccf_lm["brain_region"] == "OB_center", "x"].values[0]
rsp_ml = ccf_lm.loc[ccf_lm["brain_region"] == "RSP_base", "z"].values[0]
rsp_ap = ccf_lm.loc[ccf_lm["brain_region"] == "RSP_base", "x"].values[0]
midline_est = (ob_left_ml + ob_right_ml) / 2
CCF_MIDLINE_UM = 5700 # approximate midline in Allen CCFv3
CCF_BREGMA_AP_UM = 5400 # approximate bregma AP position in CCFv3
print()
print("AP ordering (smaller x = more anterior in CCF PIR):")
ob_is_anterior = ob_center_ap > rsp_ap # in CCF, larger x = more posterior
print(f" OB_center AP = {ob_center_ap:.0f} µm, RSP_base AP = {rsp_ap:.0f} µm")
# ── Build per-region colormap ─────────────────────────────────────────────────
unique_regions_ccf = np.unique(region_names_ccf[in_atlas_ccf])
n_regions = len(unique_regions_ccf)
region_palette = plt.get_cmap("tab20b")(np.linspace(0, 1, n_regions))
region_color_map = {r: region_palette[i] for i, r in enumerate(unique_regions_ccf)}
# ── Scatter plot: AP vs ML ────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(8, 6))
# One scatter call per region so each gets a legend entry
for region in unique_regions_ccf:
mask = region_names_ccf == region
ax.scatter(
ml_img[mask],
ap_img[mask],
s=5,
color=region_color_map[region],
alpha=0.4,
label=region,
rasterized=True,
)
# Landmark markers on top
colors = plt.get_cmap("tab10")(range(len(ccf_lm)))
for i, (_, row) in enumerate(ccf_lm.iterrows()):
ax.scatter(
row["z"],
row["x"],
s=160,
color=colors[i],
zorder=4,
edgecolors="white",
linewidths=0.8,
label=f"{row['brain_region']} (landmark)",
)
ax.annotate(
row["brain_region"],
xy=(row["z"], row["x"]),
xytext=(80, 0),
textcoords="offset points",
fontsize=9,
va="center",
arrowprops=dict(arrowstyle="-", color="gray", lw=0.8),
)
ax.axvline(CCF_MIDLINE_UM, color="gray", ls="--", lw=1.5, label=f"Midline ≈ {CCF_MIDLINE_UM} µm")
ax.axhline(CCF_BREGMA_AP_UM, color="tab:blue", ls=":", lw=1.5, label=f"Bregma AP ≈ {CCF_BREGMA_AP_UM} µm")
ax.set_xlabel("ML (z in CCFv3 PIR) — Left → Right [µm]")
ax.set_ylabel("AP (x in CCFv3 PIR) — Anterior → Posterior [µm]")
ax.set_title("Landmark positions in CCFv3 AP–ML plane\n")
ax.invert_yaxis() # small AP (anterior) at top
# Split legend: region pixels on the left panel, landmarks/lines on the right
region_handles = [mpatches.Patch(color=region_color_map[r], label=r) for r in unique_regions_ccf]
landmark_handles, landmark_labels = [], []
for h, l in zip(*ax.get_legend_handles_labels()):
if l not in unique_regions_ccf:
landmark_handles.append(h)
landmark_labels.append(l)
legend1 = ax.legend(
handles=region_handles,
loc="center left",
bbox_to_anchor=(1.02, 0.5),
fontsize=7,
title="Brain regions",
title_fontsize=8,
frameon=True,
)
ax.add_artist(legend1)
ax.legend(
landmark_handles,
landmark_labels,
loc="upper right",
fontsize=9,
)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[16], line 11 7 # 8 # In CCFv3 PIR the AP axis runs: 0 µm (anterior face) → ~13 200 µm (posterior face) 9 # so SMALLER x values are more ANTERIOR. 10 ---> 11 ccf_lm = localization.anatomical_coordinates_tables["AnatomicalCoordinatesCCFv3"][:] 12 13 print("CCF landmark coordinates (PIR orientation, µm from ASL corner):") 14 print(f" {'Landmark':15s} {'AP (x) µm':>12s} {'DV (y) µm':>12s} {'ML (z) µm':>12s}") NameError: name 'localization' is not defined
4. Anatomical Coordinates Tables ¶
AnatomicalCoordinatesTable stores 3-D anatomical coordinates for discrete
objects (the registration landmarks here). Each row gives (x, y, z) in a
named Space and a back-reference (localized_entity) to the Landmarks table.
Two tables are stored per session under localization.anatomical_coordinates_tables:
| Name | Space | Orientation | Description |
|---|---|---|---|
AnatomicalCoordinatesIBLBregma |
IBL Bregma | RAS | x=ML, y=AP, z=DV; bregma=origin; µm |
AnatomicalCoordinatesCCFv3 |
Allen CCFv3 | PIR | x=AP, y=DV, z=ML; ASL corner=origin; µm |
ibl_table = localization.anatomical_coordinates_tables["AnatomicalCoordinatesIBLBregma"]
print(f"Space : {ibl_table.space.space_name}")
print(f" Origin : {ibl_table.space.origin}")
print(f" Orient. : {ibl_table.space.orientation}")
print(f" Units : {ibl_table.space.units}")
print(f"Method : {ibl_table.method}")
print()
ibl_table[:]
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[17], line 1 ----> 1 ibl_table = localization.anatomical_coordinates_tables["AnatomicalCoordinatesIBLBregma"] 2 3 print(f"Space : {ibl_table.space.space_name}") 4 print(f" Origin : {ibl_table.space.origin}") NameError: name 'localization' is not defined
ccf_table = localization.anatomical_coordinates_tables["AnatomicalCoordinatesCCFv3"]
print(f"Space : {ccf_table.space.space_name}")
print(f" Origin : {ccf_table.space.origin}")
print(f" Orient. : {ccf_table.space.orientation}")
print(f" Units : {ccf_table.space.units}")
print(f"Method : {ccf_table.method}")
print()
ccf_table[:]
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[18], line 1 ----> 1 ccf_table = localization.anatomical_coordinates_tables["AnatomicalCoordinatesCCFv3"] 2 3 print(f"Space : {ccf_table.space.space_name}") 4 print(f" Origin : {ccf_table.space.origin}") NameError: name 'localization' is not defined
5. Extract Brain Region Activity ¶
The per-pixel atlas data lets us select an anatomically-defined sub-region of
the field of view and extract its mean activity directly from the raw
OnePhotonSeries. We demonstrate two equivalent approaches:
| Approach | Mask space | Frames used |
|---|---|---|
| A — mask stays in camera space | Source space (AnatomicalCoordinatesCCFv3MappedOnSourceImage) |
Raw OnePhotonSeriesCalcium (no warping) |
| B — frames are warped into atlas space | Registered space (AnatomicalCoordinatesImageCCFv3) |
Each frame warped via AffineTransformation |
Both are applied to two kinds of ROI:
- A named Allen region (e.g.
"VISp") from the per-pixelbrain_regionarray. - A CCF bounding box built directly from the per-pixel
(x, y, z)arrays.
Note: for physiologically-meaningful activity, one typically uses the haemodynamic-corrected SVD traces in the
desc-processedfile (seeprocessed_widefield.ipynb). The cells below showcase the mechanics of spatially-selective extraction on the raw fluorescence.
5.1 Build ROI masks in source space ¶
AnatomicalCoordinatesCCFv3MappedOnSourceImage has the same (H, W) shape as a
single raw frame, so any mask built from it can be applied directly to
OnePhotonSeriesCalcium.data[t] — no warping required.
We build two boolean masks:
- Named region — pixels whose Allen acronym equals
"VISp"(right hemisphere, selected by keeping pixels withz > CCF_MIDLINE_UM). - CCF bounding box — pixels whose
(x, z) = (AP, ML)fall inside a chosen rectangle in Allen CCF space.
# --- Source-space coordinate arrays (same shape as a raw frame) ---
aci_src = localization.anatomical_coordinates_images["AnatomicalCoordinatesCCFv3MappedOnSourceImage"]
region_src = np.asarray(aci_src.brain_region[:]) # Allen acronym per source pixel
ap_src = aci_src.x[:] # CCFv3 PIR: x = AP (µm)
ml_src = aci_src.z[:] # CCFv3 PIR: z = ML (µm)
H, W = region_src.shape
CCF_MIDLINE_UM = 5700 # approximate midline in Allen CCFv3 (z-axis)
# --- ROI 1: named Allen region (right hemisphere) ---
region_name = "VISp"
region_mask = (region_src == region_name) & (ml_src > CCF_MIDLINE_UM)
print(f"Region '{region_name}' (right hemisphere): {region_mask.sum()} pixels")
# --- ROI 2: CCF bounding box (AP × ML rectangle, right hemisphere) ---
ap_lo, ap_hi = 3000, 4500 # µm; smaller AP = more anterior in CCFv3 PIR
ml_lo, ml_hi = 5800, 7500 # µm; > midline = right hemisphere
bbox_mask = (
(ap_src >= ap_lo) & (ap_src <= ap_hi)
& (ml_src >= ml_lo) & (ml_src <= ml_hi)
& (region_src != "out-of-atlas")
)
print(f"CCF bbox AP∈[{ap_lo},{ap_hi}] µm, ML∈[{ml_lo},{ml_hi}] µm: {bbox_mask.sum()} pixels")
# --- Visualise both masks on the source image ---
fig, axes = plt.subplots(1, 2, figsize=(14, 6), dpi=100)
axes[0].imshow(source_img, cmap="gray")
axes[0].imshow(
np.ma.masked_where(~region_mask, region_mask.astype(float)),
cmap="autumn", alpha=0.5, interpolation="nearest",
)
axes[0].set_title(f"Named region mask — '{region_name}' (right hemi)\n{region_mask.sum()} pixels")
axes[0].axis("off")
axes[1].imshow(source_img, cmap="gray")
axes[1].imshow(
np.ma.masked_where(~bbox_mask, bbox_mask.astype(float)),
cmap="cool", alpha=0.5, interpolation="nearest",
)
axes[1].set_title(
f"CCF bounding-box mask\nAP [{ap_lo},{ap_hi}] µm × ML [{ml_lo},{ml_hi}] µm "
f"({bbox_mask.sum()} pixels)"
)
axes[1].axis("off")
plt.suptitle("ROI masks built in source (camera) space", fontsize=12)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[19], line 2 1 # --- Source-space coordinate arrays (same shape as a raw frame) --- ----> 2 aci_src = localization.anatomical_coordinates_images["AnatomicalCoordinatesCCFv3MappedOnSourceImage"] 3 region_src = np.asarray(aci_src.brain_region[:]) # Allen acronym per source pixel 4 ap_src = aci_src.x[:] # CCFv3 PIR: x = AP (µm) 5 ml_src = aci_src.z[:] # CCFv3 PIR: z = ML (µm) NameError: name 'localization' is not defined
5.2 Approach A — mask raw OnePhotonSeries directly ¶
Because the masks above live in source (camera) space, we can index the raw calcium frames directly. We read a short time window to keep streaming fast, then take the mean over the mask on every frame.
# --- Read a short window of the raw calcium series ---
ops = nwbfile.acquisition["OnePhotonSeriesCalcium"]
fps = nwbfile.imaging_planes["ImagingPlaneCalcium"].imaging_rate # 15 Hz
window_seconds = 30
n_frames = int(window_seconds * fps)
frames = ops.data[:n_frames] # (n_frames, H, W), uint8
timestamps = ops.timestamps[:n_frames]
print(f"Read {n_frames} frames × {H}×{W} = {frames.nbytes / 1e6:.1f} MB")
# --- Mean intensity inside each mask, per frame (vectorised) ---
region_trace_src = frames[:, region_mask].mean(axis=1)
bbox_trace_src = frames[:, bbox_mask].mean(axis=1)
# --- Plot ---
fig, ax = plt.subplots(figsize=(12, 4), dpi=120)
ax.plot(timestamps, region_trace_src, color="tab:orange", lw=1.2, label=f"{region_name} (right hemi)")
ax.plot(timestamps, bbox_trace_src, color="tab:cyan", lw=1.2,
label=f"CCF bbox AP[{ap_lo},{ap_hi}] × ML[{ml_lo},{ml_hi}] µm")
ax.set_xlabel("Time (s)")
ax.set_ylabel("Mean raw fluorescence (a.u., uint8)")
ax.set_title(f"Approach A — source-space masks on raw OnePhotonSeriesCalcium (first {window_seconds}s)")
ax.legend(loc="upper right", fontsize=9)
ax.set_frame_on(False)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[20], line 9 5 window_seconds = 30 6 n_frames = int(window_seconds * fps) 7 frames = ops.data[:n_frames] # (n_frames, H, W), uint8 8 timestamps = ops.timestamps[:n_frames] ----> 9 print(f"Read {n_frames} frames × {H}×{W} = {frames.nbytes / 1e6:.1f} MB") 10 11 # --- Mean intensity inside each mask, per frame (vectorised) --- 12 region_trace_src = frames[:, region_mask].mean(axis=1) NameError: name 'H' is not defined
5.3 Approach B — warp frames into registered space ¶
Equivalently, we can apply the AffineTransformation to each raw frame and build
the masks in registered (atlas) space using
AnatomicalCoordinatesImageCCFv3. skimage.transform.warp wants the
inverse map (output → input), so we pass M.inverse.
We process the window frame-by-frame to keep memory bounded (no need to materialise the full warped stack just to take a mean).
from skimage.transform import warp
# --- Build the SAME masks in registered space ---
aci_reg = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"]
region_reg = np.asarray(aci_reg.brain_region[:])
ap_reg = aci_reg.x[:]
ml_reg = aci_reg.z[:]
region_mask_reg = (region_reg == region_name) & (ml_reg > CCF_MIDLINE_UM)
bbox_mask_reg = (
(ap_reg >= ap_lo) & (ap_reg <= ap_hi)
& (ml_reg >= ml_lo) & (ml_reg <= ml_hi)
& (region_reg != "out-of-atlas")
)
# --- Warp each frame into registered space and take the mean over the mask ---
# M was defined in section 2 as SimilarityTransform(affine_matrix)
region_trace_reg = np.empty(n_frames, dtype=np.float32)
bbox_trace_reg = np.empty(n_frames, dtype=np.float32)
for i in range(n_frames):
warped_i = warp(
frames[i],
inverse_map=M,
output_shape=(H, W),
preserve_range=True,
order=1,
)
region_trace_reg[i] = warped_i[region_mask_reg].mean()
bbox_trace_reg[i] = warped_i[bbox_mask_reg].mean()
# --- Show one warped frame with the registered-space masks on top ---
warped_example = warp(
frames[0], inverse_map=M, output_shape=(H, W),
preserve_range=True, order=1,
)
fig, axes = plt.subplots(1, 2, figsize=(14, 6), dpi=100)
axes[0].imshow(warped_example, cmap="gray")
axes[0].imshow(
np.ma.masked_where(~region_mask_reg, region_mask_reg.astype(float)),
cmap="autumn", alpha=0.5, interpolation="nearest",
)
axes[0].set_title(f"Warped frame 0 — '{region_name}' mask (registered space)")
axes[0].axis("off")
axes[1].imshow(warped_example, cmap="gray")
axes[1].imshow(
np.ma.masked_where(~bbox_mask_reg, bbox_mask_reg.astype(float)),
cmap="cool", alpha=0.5, interpolation="nearest",
)
axes[1].set_title("Warped frame 0 — CCF bbox mask (registered space)")
axes[1].axis("off")
plt.tight_layout()
plt.show()
# --- Compare traces from the two approaches ---
fig, axes = plt.subplots(2, 1, figsize=(12, 7), dpi=120, sharex=True)
axes[0].plot(timestamps, region_trace_src, color="tab:orange", lw=1.2, label="A — source-space mask")
axes[0].plot(timestamps, region_trace_reg, color="tab:purple", lw=1.2, ls="--", label="B — warped frames")
axes[0].set_ylabel("Mean fluorescence (a.u.)")
axes[0].set_title(f"{region_name} (right hemi) — Approach A vs B")
axes[0].legend(loc="upper right", fontsize=9)
axes[0].set_frame_on(False)
axes[1].plot(timestamps, bbox_trace_src, color="tab:cyan", lw=1.2, label="A — source-space mask")
axes[1].plot(timestamps, bbox_trace_reg, color="tab:green", lw=1.2, ls="--", label="B — warped frames")
axes[1].set_xlabel("Time (s)")
axes[1].set_ylabel("Mean fluorescence (a.u.)")
axes[1].set_title(f"CCF bbox AP[{ap_lo},{ap_hi}] × ML[{ml_lo},{ml_hi}] µm — Approach A vs B")
axes[1].legend(loc="upper right", fontsize=9)
axes[1].set_frame_on(False)
plt.tight_layout()
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[21], line 4 1 from skimage.transform import warp 2 3 # --- Build the SAME masks in registered space --- ----> 4 aci_reg = localization.anatomical_coordinates_images["AnatomicalCoordinatesImageCCFv3"] 5 region_reg = np.asarray(aci_reg.brain_region[:]) 6 ap_reg = aci_reg.x[:] 7 ml_reg = aci_reg.z[:] NameError: name 'localization' is not defined