Accessing BCI Data#

This tutorial will go over how to load the BCI data and access its contents.

Import required packages#

The BCI data is packaged in NWB format with a Zarr backend. To access the data, use NWBZarrIO from hdmf-zarr. nwb2widget creates an interactive GUI with the NWB file, which is useful for exploring the file contents and looking at basic plots.

from hdmf_zarr import NWBZarrIO
from nwbwidgets import nwb2widget
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

Load the data#

Let’s load the data for one recording session using NWBZarrIO.

# Set filename 
nwb_path = '/data/single-plane-ophys_731015_2025-01-10_18-06-31_processed_2025-08-03_20-39-09/single-plane-ophys_731015_2025-01-10_18-06-31_behavior_nwb' 

# Assign file to an NWBZarrIO object 
io = NWBZarrIO(nwb_path, 'r')
# Read the file 
nwbfile = io.read()

nwb2widget is useful for exploring the NWB file structure and contents. The widget can also generate basic plots, like the neural activity timeseries traces.

nwb2widget(nwbfile) 

Image Segmentation Table#

During processing, a segmentation algorithm (e.g. Suite2p or Cellpose) is applied to the raw fluorescence data to extract ROIs for detected neurons. The extracted ROIs are accessible in the form of image masks, a HxW sparse array with non-zero values where the ROI is masked out in the imaging plane. The detected ROIs are run through a soma/dendrite classifier to confirm if the ROI masks fit certain features of a soma or dendrite. The image masks and outputs of the soma/dendrite classifier are stored in the image_segmentation table in the processing container.

Column

Description

is_soma

==1 if ROI classified as soma, ==0 if not

soma_probability

if >0.5 classified as soma

is_dendrite

==1 if ROI classified as dendrite, ==0 if not

dendrite_probability

if >0.5 classified as dendrite

image_mask

HxW sparse array defining image masks

If you want to work with neural activity from somas, use only ROIs that pass the is_soma classification.

image_segmentation = nwbfile.processing["processed"].data_interfaces["image_segmentation"].plane_segmentations["roi_table"].to_dataframe()
image_segmentation.head()
is_soma soma_probability is_dendrite dendrite_probability image_mask
id
0 1 0.886588 0 0.000000e+00 [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,...
1 0 0.000000 0 8.818507e-05 [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,...
2 1 0.999333 0 0.000000e+00 [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,...
3 0 0.220683 0 0.000000e+00 [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,...
4 0 0.000644 0 5.960464e-08 [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,...

Cell activity traces#

After the ROIs are extracted, the change in fluorescence over a baseline (dF/F) is calculated for each ROI. The dF/F is accessible as shown below.

The shape of dff is number of frames x number of rois.

dff = nwbfile.processing["processed"].data_interfaces["dff"].roi_response_series["dff"].data
print('dff shape (nframes, nrois):',np.shape(dff))
dff shape (nframes, nrois): (220344, 1214)

We can find the frame rate for these experiments:

frame_rate = nwbfile.imaging_planes["processed"].imaging_rate
print('Frame Rate:', frame_rate)
Frame Rate: 58.2634

Epoch Table#

The epoch table contains the start and stop times/frames for each stimulus epoch. You can use the epoch table with the dff array to pull and compare neural activity across different stimulus epochs.

Column

Description

stimulus_name

descriptive name of the epoch

start_frame

epoch start(frames)

stop_frame

epoch end (frames)

start_time

epoch start (sec)

stop_time

epoch end (sec)

epoch_table = nwbfile.intervals["epochs"].to_dataframe()
epoch_table
stimulus_name start_frame stop_frame start_time stop_time
id
0 spont 0 2399 0.000000 41.175077
1 photostim 2400 43793 41.192241 751.638250
2 spont_01 43794 49519 751.655413 849.916071
3 BCI 49520 89755 849.933234 1540.503987
4 photostim_post 89756 220343 1540.521150 3781.842460

Session structure is variable!

The epoch order and structure is variable across sessions. Sometimes the spontaneous epoch occurs before photostimulation and sometimes there are repeats of the same epoch type. Check the epoch table before working with the session data.

Photostimulation Table#

During the “photostim” epochs, single neurons were optogenetically activated using 2p photostimulation to probe the functional connectivity in the network.

The PhotostimTrials table (stimulus>PhotostimTrials) contains information about the photostimulation trials.

Column

Description

start_time

stimulus start (s)

stop_time

stimulus end (s)

start_frame

stimulus start (frame)

stop_frame

stimulus end (frame)

tiff_file

data source file name

stimulus_name

stimulus name

laser_x

x coordinate of stimulated neuron (pixels)

laser_y

y coordinate of stimulated neuron (pixels)

power

stimulus intensity (mW)

duration

trial duration (s)

stimulus_function

stimulus template

group_index

number identifier for stimulated neuron(s)

closest_roi

index in dff that corresponds to the photostimulated neuron

photostim = nwbfile.stimulus["PhotostimTrials"].to_dataframe()
photostim.head()
start_time stop_time start_frame stop_frame tiff_file stimulus_name laser_x laser_y power duration stimulus_function group_index closest_roi
id
0 41.192241 42.307864 2400 2465 before_exp_slm_00001.tif photostim 336.5 189.5 4 0.082 scanimage.mroi.stimulusfunctions.logspiral 27 631
1 42.325027 43.492141 2466 2534 before_exp_slm_00002.tif photostim 53.5 60.5 4 0.082 scanimage.mroi.stimulusfunctions.logspiral 50 66
2 43.509304 44.624927 2535 2600 before_exp_slm_00003.tif photostim 236.5 28.5 4 0.082 scanimage.mroi.stimulusfunctions.logspiral 6 99
3 44.642091 45.757714 2601 2666 before_exp_slm_00004.tif photostim 370.5 24.5 4 0.082 scanimage.mroi.stimulusfunctions.logspiral 32 113
4 45.774878 46.890501 2667 2732 before_exp_slm_00005.tif photostim 454.5 58.5 4 0.082 scanimage.mroi.stimulusfunctions.logspiral 31 1028

BCI Behavior Table#

During the “BCI” epochs, the mouse engaged in an optical brain-computer-interface task in which the activity of a single neuron (conditioned neuron) in the imaging plane is used to control the movement of a reward lickport towards the mouse’s face (zaber_steps_times). Once the lickport crosses a spatial threshold (threshold_crossing_times), a reward is delivered. The mouse has 10s to complete the trial before the lickport returns to its start position. After the reward is delivered, the mouse can consume the reward at any timepoint (reward_time).

*Important notes - zaber_steps_times that occurred after the threshold_crossing_time in the data were misreported due to a technical bug. After reaching the threshold, the lickport still tried to move but did not actually move. Additionally, the hit column unreliably reports the hit rate, so disregard this information.

Information about each BCI behavior trial can be found in the intervals > trials table.

Column

Description

start_time

trial start (sec)

stop_time

trial end (sec)

go_cue

time of auditory go cue relative to start time (sec)

hit*

boolean of whether trial was hit

lick_l

lick times (sec)

reward_time

reward delivery time (sec)

threshold_crossing_times

time when reward port crossed position threshold (sec)

zaber_steps_times

times when lickport moved

tiff_file

data source file

start_frame

trial start (frame)

stop_frame

trial end (frame)

conditioned_neuron_x

coordinate for conditioned neuron (pixels)

conditioned_neuron_y

coordinate for conditioned neuron (pixels)

closest_roi

index in dff that corresponds to the conditioned neuron

bci = nwbfile.stimulus["Trials"].to_dataframe()
bci.head()
start_time stop_time go_cue hit lick_L reward_time threshold_crossing_times zaber_step_times tiff_file start_frame stop_frame conditioned_neuron_x conditioned_neuron_y closest_roi
id
0 849.933234 864.247538 0.2359 True [5.2544, 5.4253, 5.5753, 5.682, 5.793, 5.93950... 5.2544 5.1198 [3.6918, 4.5068, 4.7348, 4.8018, 4.8368, 4.868... neuron46_00001.tif 49520 50354 56.5 112.5 38
1 864.264701 878.046939 0.2359 True [6.526000000000001, 6.6604, 6.7766, 6.9938, 7.... 6.5260 6.4260 [0.5134000000000001, 0.6654, 1.1373, 1.4703000... neuron46_00002.tif 50355 51158 56.5 112.5 38
2 878.064102 884.672024 0.2359 True [1.0756, 1.1934, 1.3018, 1.4094, 1.5212, 1.641... 1.0756 0.8314 [0.2868, 0.3497, 0.4128, 0.4757, 0.5298, 0.572... neuron46_00003.tif 51159 51544 56.5 112.5 38
3 884.689187 889.786727 0.2359 True [1.7614, 1.9537, 2.0812, 2.3348, 2.4525, 2.563... 1.9537 1.8503 [0.7273000000000001, 0.8013, 0.862300000000000... neuron46_00004.tif 51545 51842 56.5 112.5 38
4 889.803891 894.935757 0.2359 True [1.8142, 1.9819, 2.142, 2.4023000000000003, 2.... 1.9819 1.9437 [0.2868, 0.3557, 0.4288, 0.4937, 0.7277, 0.817... neuron46_00005.tif 51843 52142 56.5 112.5 38