Open In Colab

Installing requirements¶

The cell below installs every Python package needed to run this notebook, at fully pinned versions, using uv for fast resolution. In Colab the cell is collapsed by default — click the ▶ button to run it.

In [1]:
# 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).

Streaming and interacting with NWB data from DANDI¶

First, let's import a few classes. If you are not running this notebook on DANDI Hub, you will need to install these packages using pip or your favorite Python package manager. For example:

pip install dandi pynwb fsspec requests aiohttp matplotlib pynapple seaborn
In [2]:
from dandi.dandiapi import DandiAPIClient
import fsspec
from fsspec.implementations.cached import CachingFileSystem
import h5py
import matplotlib.pyplot as plt
import numpy as np
import pynwb

The data used in this tutorial were used in this publication: Sargolini, et al. "Conjunctive representation of position, direction, and velocity in entorhinal cortex." Science 312.5774 (2006): 758-762. The data can be found on the DANDI Archive in Dandiset 000582.

In [3]:
dandiset_id = "000582"
filepath = "sub-10073/sub-10073_ses-17010302_behavior+ecephys.nwb"
with DandiAPIClient() as client:
    asset = client.get_dandiset(dandiset_id, 'draft').get_asset_by_path(filepath)
    s3_url = asset.get_content_url(follow_redirects=1, strip_query=True)
In [4]:
s3_url
Out[4]:
'https://dandiarchive.s3.amazonaws.com/blobs/26a/22c/26a22c31-09bc-43a4-9187-edc7394ed12c'

There are multiple methods to stream NWB files. We currently recommend fsspec, but additional options are described in the pynwb streaming tutorial.

In [5]:
# create a virtual http filesystem with local caching
fs = CachingFileSystem(
    fs=fsspec.filesystem("http"),
    cache_storage="nwb-cache",  # local folder for the cache
)
In [6]:
# open the file using the S3 URL
f = fs.open(s3_url, "rb")
file = h5py.File(f)
io = pynwb.NWBHDF5IO(file=file)
nwbfile = io.read()

You can print the NWBFile object in a Jupyter notebook to get a simplified, interactive representation of the contents of the NWB file.

In [7]:
nwbfile
Out[7]:

root (NWBFile)

session_description: This session includes spike and position times for recorded cells from a Long Evans rat that was running in a 1 x 1 meter enclosure. The cells were recorded in the dorsocaudal 25% portion of the medial entorhinal cortex (MEC).Position is given for two LEDs to enable calculation of head direction.
identifier: 294b7de1-a624-44d8-b1a1-28028dd2cf0c
session_start_time1900-01-01 00:00:00+01:00
timestamps_reference_time1900-01-01 00:00:00+01:00
file_create_date
02023-09-16 15:50:09.775622+02:00
experimenter('Sargolini, Francesca',)
related_publications('https://doi.org/10.1126/science.1125572',)
acquisition
ElectricalSeries (ElectricalSeries)
starting_time: 0.0
rate: 4800.0
resolution: -1.0
comments: no comments
description: The EEG signals from one electrode amplified 8000-10000 times, lowpass-filtered at 500 Hz (single pole), and stored at 4800 Hz (16 bits/sample).
conversion: 1e-06
offset: 0.0
unit: volts
data
HDF5 dataset
Data typefloat64
Shape(2880000,)
Array size21.97 MiB
Chunk shape(5625,)
Compressiongzip
Compression opts4
Uncompressed size (bytes)23040000
Compressed size (bytes)14520596
Compression ratio1.5867117300143878
starting_time_unit: seconds
electrodes (DynamicTableRegion)
description: all electrodes
table (ElectrodesTable)
description: metadata about extracellular electrodes
columns
location
the location of channel within the subject e.g. brain region
group
a reference to the ElectrodeGroup this electrode is a part of
group_name
the name of the ElectrodeGroup this electrode is a part of
table
location group group_name
id
0 MEC ElectrodeGroup pynwb.ecephys.ElectrodeGroup at 0x139913864651040\nFields:\n description: The name of the ElectrodeGroup this electrode is a part of.\n device: EEG pynwb.device.Device at 0x139913864650032\nFields:\n description: The device used to record EEG signals.\n\n location: MEC\n ElectrodeGroup
keywords
HDF5 dataset
Data typeobject
Shape(3,)
Array size24.00 bytes
Chunk shapeNone
CompressionNone
Compression optsNone
Uncompressed size (bytes)24
Compressed size (bytes)48
Compression ratio0.5

['medial entorhinal cortex' 'spike times' 'position']
processing
behavior (ProcessingModule)
description: Processed behavioral data.
Position (Position)
SpatialSeriesLED1 (SpatialSeries)
resolution: -1.0
comments: no comments
description: Position (x, y) for the first tracking LED.
conversion: 0.01
offset: 0.0
unit: meters
data
HDF5 dataset
Data typefloat64
Shape(30000, 2)
Array size468.75 KiB
Chunk shape(1875, 1)
Compressiongzip
Compression opts4
Uncompressed size (bytes)480000
Compressed size (bytes)453899
Compression ratio1.0575039821634329
timestamps
HDF5 dataset
Data typefloat64
Shape(30000,)
Array size234.38 KiB
Chunk shape(1875,)
Compressiongzip
Compression opts4
Uncompressed size (bytes)240000
Compressed size (bytes)68370
Compression ratio3.5103115401491882
timestamps_unit: seconds
interval: 1
reference_frame: (0,0) is not known.
ecephys (ProcessingModule)
description: Processed electrical series data.
LFP (LFP)
ElectricalSeriesLFP (ElectricalSeries)
starting_time: 0.0
rate: 250.0
resolution: -1.0
comments: no comments
description: The EEG signals from one electrode stored at 250 Hz.
conversion: 1e-06
offset: 0.0
unit: volts
data
HDF5 dataset
Data typefloat64
Shape(150000,)
Array size1.14 MiB
Chunk shape(2344,)
Compressiongzip
Compression opts4
Uncompressed size (bytes)1200000
Compressed size (bytes)294856
Compression ratio4.069783216214017
starting_time_unit: seconds
electrodes (DynamicTableRegion)
description: all electrodes
table (ElectrodesTable)
description: metadata about extracellular electrodes
columns
location
the location of channel within the subject e.g. brain region
group
a reference to the ElectrodeGroup this electrode is a part of
group_name
the name of the ElectrodeGroup this electrode is a part of
table
location group group_name
id
0 MEC ElectrodeGroup pynwb.ecephys.ElectrodeGroup at 0x139913864651040\nFields:\n description: The name of the ElectrodeGroup this electrode is a part of.\n device: EEG pynwb.device.Device at 0x139913864650032\nFields:\n description: The device used to record EEG signals.\n\n location: MEC\n ElectrodeGroup
electrodes (ElectrodesTable)
description: metadata about extracellular electrodes
columns
location
the location of channel within the subject e.g. brain region
group
a reference to the ElectrodeGroup this electrode is a part of
group_name
the name of the ElectrodeGroup this electrode is a part of
table
location group group_name
id
0 MEC ElectrodeGroup pynwb.ecephys.ElectrodeGroup at 0x139913864651040\nFields:\n description: The name of the ElectrodeGroup this electrode is a part of.\n device: EEG pynwb.device.Device at 0x139913864650032\nFields:\n description: The device used to record EEG signals.\n\n location: MEC\n ElectrodeGroup
electrode_groups
ElectrodeGroup (ElectrodeGroup)
description: The name of the ElectrodeGroup this electrode is a part of.
location: MEC
device (Device)
description: The device used to record EEG signals.
devices
EEG (Device)
description: The device used to record EEG signals.
subject (Subject)
age: P3M/P5M
age__reference: birth
description: A Long Evans rat.
sex: M
species: Rattus norvegicus
subject_id: 10073
weight: 0.35/0.45
units (Units)
description: Autogenerated by NWBFile
waveform_unit: volts
columns
unit_name
The identifier of the cell, based on tetrode number and cell number.
spike_times
the spike times for each unit
histology
The layer of MEC of the grid cell.
hemisphere
Indicates which hemisphere the electrodes were inserted above MEC.
depth
Indicates the depth of the inserted electrodes in meters.
table
unit_name spike_times histology hemisphere depth
id
0 t1c1 [0.7903958333333333, 0.794, 0.8111666666666667, 0.8313541666666666, 0.9217708333333333, 1.0205208333333333, 1.3573020833333334, 1.6583229166666666, 1.6768645833333333, 2.7457708333333333, 4.008697916666667, 4.01678125, 4.402270833333334, 4.522583333333333, 4.527708333333333, 5.598760416666667, 5.61415625, 5.617927083333333, 5.68934375, 5.701510416666666, 5.714885416666666, 5.71740625, 5.723197916666667, 5.806802083333333, 5.8149375, 5.8207708333333334, 6.1641875, 6.201979166666667, 6.2260625, 6.2363125, 6.3546875, 6.363916666666666, 6.480145833333333, 6.48803125, 6.899927083333333, 6.992489583333334, 6.995885416666667, 7.033135416666667, 7.098052083333333, 7.10146875, 7.105677083333333, 7.245541666666667, 11.069739583333334, 11.499979166666666, 11.5111875, 11.522375, 11.6165, 11.702270833333333, 11.714625, 11.7245, 11.920979166666667, 11.983385416666666, 11.98634375, 11.995645833333333, 12.08903125, 12.105385416666667, 12.148697916666666, 12.157114583333334, 12.165864583333333, 13.123729166666667, 13.206645833333333, 13.224875, 13.232479166666666, 13.362927083333334, 13.40890625, 13.522697916666667, 13.530177083333333, 13.54115625, 13.623927083333333, 13.685302083333333, 13.738260416666666, 13.757302083333334, 13.812510416666667, 13.855427083333334, 13.971072916666667, 13.98659375, 13.992822916666666, 14.082979166666666, 14.162229166666666, 14.165541666666666, 14.394229166666667, 14.397375, 14.488708333333333, 14.492708333333333, 14.500604166666667, 14.547833333333333, 14.563979166666666, 14.5875, 14.590729166666666, 14.59375, 14.601708333333333, 14.608729166666667, 14.620083333333334, 14.647083333333333, 14.699260416666666, 14.70190625, 14.741635416666666, 14.801010416666667, 14.80403125, 14.88940625, ...] MEC LII 0.0024
1 t2c1 [1.0451354166666667, 1.7003854166666668, 2.3154375, 11.046822916666667, 14.239729166666667, 14.822927083333333, 14.837010416666667, 19.281322916666667, 19.585395833333333, 19.603958333333335, 19.719083333333334, 19.722625, 19.819458333333333, 19.822979166666666, 19.8256875, 19.829520833333333, 28.67203125, 29.932614583333333, 30.8508125, 30.951416666666667, 31.050583333333332, 31.106822916666665, 31.410760416666665, 36.44560416666667, 46.90858333333333, 47.34158333333333, 47.397375, 47.4190625, 47.47598958333333, 48.156, 59.66520833333333, 59.66970833333333, 59.78719791666666, 60.00934375, 60.12197916666667, 60.12890625, 60.458333333333336, 60.8745625, 61.55807291666667, 62.76680208333333, 62.94321875, 63.27045833333333, 63.4875, 64.47296875, 67.56085416666667, 67.57622916666666, 67.72179166666666, 67.72525, 67.80897916666666, 67.814625, 67.8276875, 67.91458333333334, 67.94144791666666, 67.95988541666667, 68.02155208333333, 68.13059375, 68.20140625, 68.33521875, 68.40710416666667, 68.57409375, 68.58878125, 68.681375, 68.70475, 68.75991666666667, 68.832625, 68.9400625, 68.94379166666667, 71.02867708333333, 71.25821875, 71.41845833333333, 72.28534375, 78.7965, 79.7308125, 79.76083333333334, 79.84297916666667, 79.91891666666666, 79.97095833333333, 80.08979166666667, 83.240875, 88.275625, 91.66017708333334, 91.67665625, 92.069125, 92.10191666666667, 92.56378125, 92.56932291666666, 92.57228125, 92.58971875, 92.59544791666667, 92.67121875, 92.67442708333333, 92.81330208333334, 92.84265625, 93.16694791666667, 93.28475, 93.47997916666667, 93.49264583333333, 93.51422916666667, 93.51847916666667, 93.52220833333334, ...] MEC LII 0.0024
2 t2c3 [0.18273958333333334, 0.5340729166666667, 0.5707291666666666, 0.7023333333333334, 0.7242604166666666, 0.7670520833333333, 0.88084375, 1.06084375, 1.1815, 1.2828333333333333, 1.2922916666666666, 1.4162291666666667, 1.5238333333333334, 1.5430416666666666, 1.5909479166666667, 1.6242291666666666, 1.6451041666666666, 1.7132604166666667, 3.0415729166666665, 5.295635416666666, 5.516947916666667, 6.2452604166666665, 6.336885416666667, 6.6401666666666666, 7.0116875, 7.089395833333334, 7.20128125, 8.1189375, 8.1546875, 8.251333333333333, 8.605614583333333, 10.502302083333333, 10.848864583333333, 10.931302083333334, 11.852802083333334, 11.86840625, 11.877864583333333, 11.963645833333333, 13.12328125, 13.53028125, 13.688145833333333, 13.751333333333333, 14.159802083333334, 16.810760416666668, 16.91994791666667, 17.323583333333332, 17.454822916666668, 19.2395, 19.306625, 19.73028125, 21.200885416666665, 21.439739583333335, 22.102395833333333, 22.926447916666667, 23.722489583333335, 23.85609375, 25.524104166666667, 25.860020833333333, 26.32103125, 26.6210625, 26.66503125, 26.753708333333332, 26.846958333333333, 26.8845, 26.959229166666667, 27.08540625, 27.1913125, 27.271979166666668, 27.31240625, 27.537260416666665, 27.791447916666666, 27.805697916666666, 27.817010416666665, 27.90071875, 27.917572916666668, 28.02446875, 28.13378125, 28.15521875, 28.32228125, 28.363958333333333, 28.38533333333333, 28.608604166666666, 28.6311875, 29.11065625, 30.226875, 33.932625, 34.056666666666665, 34.590354166666664, 36.890760416666666, 38.448458333333335, 38.4585, 38.78067708333333, 39.00878125, 39.022072916666666, 39.23472916666667, 39.24640625, 39.25477083333333, 39.60910416666667, 40.26836458333333, 40.29759375, ...] MEC LII 0.0024
3 t3c1 [1.0358229166666666, 1.04803125, 1.6964270833333333, 1.7780416666666667, 1.7842083333333334, 1.8619166666666667, 1.8659375, 1.879125, 1.8885416666666666, 1.9763333333333333, 2.0486666666666666, 2.1341875, 2.1698541666666666, 2.2325416666666666, 2.245875, 2.251375, 2.2590625, 2.2775833333333333, 2.282395833333333, 2.2996041666666667, 2.3334375, 2.3404375, 2.3472708333333334, 2.3584375, 2.380541666666667, 2.3935104166666665, 2.40184375, 2.4201979166666665, 2.44096875, 2.45184375, 2.4599270833333335, 2.4681770833333334, 2.4746770833333334, 2.4855729166666665, 2.5209479166666666, 2.55503125, 2.5716979166666665, 2.5834895833333333, 2.591552083333333, 2.6127604166666667, 2.6709895833333333, 2.88928125, 3.134916666666667, 3.2006875, 3.3154375, 3.4335625, 4.24340625, 4.2707395833333335, 4.34684375, 14.862104166666667, 15.2978125, 15.543479166666666, 16.012020833333334, 16.19559375, 16.322864583333335, 16.855166666666666, 16.8641875, 19.730333333333334, 19.756604166666666, 19.76535416666667, 19.8773125, 19.9308125, 20.047833333333333, 20.227822916666668, 20.318989583333334, 20.336260416666665, 20.47409375, 20.584364583333333, 20.78321875, 20.79134375, 20.810072916666666, 20.824833333333334, 20.8931875, 20.906208333333332, 20.918354166666667, 20.9286875, 21.020104166666666, 21.109541666666665, 21.1209375, 21.129208333333334, 21.139520833333332, 28.955604166666667, 28.969427083333333, 29.12302083333333, 29.227, 29.93634375, 30.745760416666666, 30.862416666666668, 33.691541666666666, 33.70033333333333, 33.70483333333333, 45.592125, 48.75952083333333, 52.425875, 52.44083333333333, 53.031697916666666, 53.03701041666667, 57.72391666666667, 57.736291666666666, 57.74427083333333, ...] MEC LII 0.0024

... and 4 more row(s).

experiment_description: The sample includes conjunctive cells and head direction cells from layers III and V of medial entorhinal cortex and have been published in Sargolini et al. (Science, 2006).
session_id: 17010302
lab: Moser
institution: Centre for the Biology of Memory, Norwegian University of Science and Technology

Access nwbfile.subject to get information about the subject used in this experiment, including their age, sex, species, and ID. Age uses the ISO 8601 standard for time durations - P3M corresponds to 3 months old, and P3M/P5M means the subject was between 3-5 months old.

In [8]:
nwbfile.subject
Out[8]:

subject (Subject)

age: P3M/P5M
age__reference: birth
description: A Long Evans rat.
sex: M
species: Rattus norvegicus
subject_id: 10073
weight: 0.35/0.45

Now let's access the position of the animal, which is stored in a SpatialSeries object at this particular path within the NWB file.

In [9]:
position = nwbfile.processing["behavior"]["Position"]["SpatialSeriesLED1"]
position
Out[9]:

SpatialSeriesLED1 (SpatialSeries)

resolution: -1.0
comments: no comments
description: Position (x, y) for the first tracking LED.
conversion: 0.01
offset: 0.0
unit: meters
data
HDF5 dataset
Data typefloat64
Shape(30000, 2)
Array size468.75 KiB
Chunk shape(1875, 1)
Compressiongzip
Compression opts4
Uncompressed size (bytes)480000
Compressed size (bytes)453899
Compression ratio1.0575039821634329
timestamps
HDF5 dataset
Data typefloat64
Shape(30000,)
Array size234.38 KiB
Chunk shape(1875,)
Compressiongzip
Compression opts4
Uncompressed size (bytes)240000
Compressed size (bytes)68370
Compression ratio3.5103115401491882
timestamps_unit: seconds
interval: 1
reference_frame: (0,0) is not known.

Lazy loading of datasets¶

Data arrays are read passively from the NWB file. Accessing the data attribute of the SpatialSeries object does not read the data values, but presents an h5py.Dataset object that can be indexed to read data. You can use the [:] operator to read the entire data array into memory.

In [10]:
position.data
Out[10]:
<HDF5 dataset "data": shape (30000, 2), type "<f8">
In [11]:
pos_data = position.data[:]
pos_data
Out[11]:
array([[-0.4427946 , 17.10393108],
       [-0.4427946 , 17.10393108],
       [ 1.26778258, 16.85956291],
       ...,
       [ 2.00088708,  6.84046804],
       [ 2.00088708,  6.84046804],
       [ 0.77904624,  4.64115453]])

Slicing datasets¶

Especially with very large datasets, it is often preferable to read only a portion of the data. To do this, index or slice into the data attribute just like if you were indexing or slicing a numpy array.

Let's get the X coordinates of the subject for all timestamps and get the timestamps.

In [12]:
x = position.data[:,0]
x
Out[12]:
array([-0.4427946 , -0.4427946 ,  1.26778258, ...,  2.00088708,
        2.00088708,  0.77904624])
In [13]:
ts = position.timestamps[:]
ts
Out[13]:
array([0.0000e+00, 2.0000e-02, 4.0000e-02, ..., 5.9994e+02, 5.9996e+02,
       5.9998e+02])

Now let's use those values to plot the X position of the subject over time. All times in NWB are stored in seconds relative to the session start time.

In [14]:
plt.plot(ts, x)
plt.xlabel("Time (seconds)")
plt.ylabel("X coordinate of the subject");
No description has been provided for this image

We can also slice in the time dimension. Let's plot the (x, y) position of the subject for the first 100 time points.

In [15]:
time_indices = slice(0, 100)
fig, ax = plt.subplots()
ax.scatter(position.data[time_indices,0], position.data[time_indices,1], c=position.timestamps[time_indices])
ax.plot(position.data[time_indices,0], position.data[time_indices,1], color='k', zorder=0)
ax.set(xlabel="X coordinate", ylabel="Y coordinate")
Out[15]:
[Text(0.5, 0, 'X coordinate'), Text(0, 0.5, 'Y coordinate')]
No description has been provided for this image

Access single unit data¶

Data and metadata about sorted single units are stored in a Units object. It stores metadata about each single unit in a tabular form, where each row represents a unit with spike times and additional metadata.

In [16]:
nwbfile.units
Out[16]:

units (Units)

description: Autogenerated by NWBFile
waveform_unit: volts
columns
unit_name
The identifier of the cell, based on tetrode number and cell number.
spike_times
the spike times for each unit
histology
The layer of MEC of the grid cell.
hemisphere
Indicates which hemisphere the electrodes were inserted above MEC.
depth
Indicates the depth of the inserted electrodes in meters.
table
unit_name spike_times histology hemisphere depth
id
0 t1c1 [0.7903958333333333, 0.794, 0.8111666666666667, 0.8313541666666666, 0.9217708333333333, 1.0205208333333333, 1.3573020833333334, 1.6583229166666666, 1.6768645833333333, 2.7457708333333333, 4.008697916666667, 4.01678125, 4.402270833333334, 4.522583333333333, 4.527708333333333, 5.598760416666667, 5.61415625, 5.617927083333333, 5.68934375, 5.701510416666666, 5.714885416666666, 5.71740625, 5.723197916666667, 5.806802083333333, 5.8149375, 5.8207708333333334, 6.1641875, 6.201979166666667, 6.2260625, 6.2363125, 6.3546875, 6.363916666666666, 6.480145833333333, 6.48803125, 6.899927083333333, 6.992489583333334, 6.995885416666667, 7.033135416666667, 7.098052083333333, 7.10146875, 7.105677083333333, 7.245541666666667, 11.069739583333334, 11.499979166666666, 11.5111875, 11.522375, 11.6165, 11.702270833333333, 11.714625, 11.7245, 11.920979166666667, 11.983385416666666, 11.98634375, 11.995645833333333, 12.08903125, 12.105385416666667, 12.148697916666666, 12.157114583333334, 12.165864583333333, 13.123729166666667, 13.206645833333333, 13.224875, 13.232479166666666, 13.362927083333334, 13.40890625, 13.522697916666667, 13.530177083333333, 13.54115625, 13.623927083333333, 13.685302083333333, 13.738260416666666, 13.757302083333334, 13.812510416666667, 13.855427083333334, 13.971072916666667, 13.98659375, 13.992822916666666, 14.082979166666666, 14.162229166666666, 14.165541666666666, 14.394229166666667, 14.397375, 14.488708333333333, 14.492708333333333, 14.500604166666667, 14.547833333333333, 14.563979166666666, 14.5875, 14.590729166666666, 14.59375, 14.601708333333333, 14.608729166666667, 14.620083333333334, 14.647083333333333, 14.699260416666666, 14.70190625, 14.741635416666666, 14.801010416666667, 14.80403125, 14.88940625, ...] MEC LII 0.0024
1 t2c1 [1.0451354166666667, 1.7003854166666668, 2.3154375, 11.046822916666667, 14.239729166666667, 14.822927083333333, 14.837010416666667, 19.281322916666667, 19.585395833333333, 19.603958333333335, 19.719083333333334, 19.722625, 19.819458333333333, 19.822979166666666, 19.8256875, 19.829520833333333, 28.67203125, 29.932614583333333, 30.8508125, 30.951416666666667, 31.050583333333332, 31.106822916666665, 31.410760416666665, 36.44560416666667, 46.90858333333333, 47.34158333333333, 47.397375, 47.4190625, 47.47598958333333, 48.156, 59.66520833333333, 59.66970833333333, 59.78719791666666, 60.00934375, 60.12197916666667, 60.12890625, 60.458333333333336, 60.8745625, 61.55807291666667, 62.76680208333333, 62.94321875, 63.27045833333333, 63.4875, 64.47296875, 67.56085416666667, 67.57622916666666, 67.72179166666666, 67.72525, 67.80897916666666, 67.814625, 67.8276875, 67.91458333333334, 67.94144791666666, 67.95988541666667, 68.02155208333333, 68.13059375, 68.20140625, 68.33521875, 68.40710416666667, 68.57409375, 68.58878125, 68.681375, 68.70475, 68.75991666666667, 68.832625, 68.9400625, 68.94379166666667, 71.02867708333333, 71.25821875, 71.41845833333333, 72.28534375, 78.7965, 79.7308125, 79.76083333333334, 79.84297916666667, 79.91891666666666, 79.97095833333333, 80.08979166666667, 83.240875, 88.275625, 91.66017708333334, 91.67665625, 92.069125, 92.10191666666667, 92.56378125, 92.56932291666666, 92.57228125, 92.58971875, 92.59544791666667, 92.67121875, 92.67442708333333, 92.81330208333334, 92.84265625, 93.16694791666667, 93.28475, 93.47997916666667, 93.49264583333333, 93.51422916666667, 93.51847916666667, 93.52220833333334, ...] MEC LII 0.0024
2 t2c3 [0.18273958333333334, 0.5340729166666667, 0.5707291666666666, 0.7023333333333334, 0.7242604166666666, 0.7670520833333333, 0.88084375, 1.06084375, 1.1815, 1.2828333333333333, 1.2922916666666666, 1.4162291666666667, 1.5238333333333334, 1.5430416666666666, 1.5909479166666667, 1.6242291666666666, 1.6451041666666666, 1.7132604166666667, 3.0415729166666665, 5.295635416666666, 5.516947916666667, 6.2452604166666665, 6.336885416666667, 6.6401666666666666, 7.0116875, 7.089395833333334, 7.20128125, 8.1189375, 8.1546875, 8.251333333333333, 8.605614583333333, 10.502302083333333, 10.848864583333333, 10.931302083333334, 11.852802083333334, 11.86840625, 11.877864583333333, 11.963645833333333, 13.12328125, 13.53028125, 13.688145833333333, 13.751333333333333, 14.159802083333334, 16.810760416666668, 16.91994791666667, 17.323583333333332, 17.454822916666668, 19.2395, 19.306625, 19.73028125, 21.200885416666665, 21.439739583333335, 22.102395833333333, 22.926447916666667, 23.722489583333335, 23.85609375, 25.524104166666667, 25.860020833333333, 26.32103125, 26.6210625, 26.66503125, 26.753708333333332, 26.846958333333333, 26.8845, 26.959229166666667, 27.08540625, 27.1913125, 27.271979166666668, 27.31240625, 27.537260416666665, 27.791447916666666, 27.805697916666666, 27.817010416666665, 27.90071875, 27.917572916666668, 28.02446875, 28.13378125, 28.15521875, 28.32228125, 28.363958333333333, 28.38533333333333, 28.608604166666666, 28.6311875, 29.11065625, 30.226875, 33.932625, 34.056666666666665, 34.590354166666664, 36.890760416666666, 38.448458333333335, 38.4585, 38.78067708333333, 39.00878125, 39.022072916666666, 39.23472916666667, 39.24640625, 39.25477083333333, 39.60910416666667, 40.26836458333333, 40.29759375, ...] MEC LII 0.0024
3 t3c1 [1.0358229166666666, 1.04803125, 1.6964270833333333, 1.7780416666666667, 1.7842083333333334, 1.8619166666666667, 1.8659375, 1.879125, 1.8885416666666666, 1.9763333333333333, 2.0486666666666666, 2.1341875, 2.1698541666666666, 2.2325416666666666, 2.245875, 2.251375, 2.2590625, 2.2775833333333333, 2.282395833333333, 2.2996041666666667, 2.3334375, 2.3404375, 2.3472708333333334, 2.3584375, 2.380541666666667, 2.3935104166666665, 2.40184375, 2.4201979166666665, 2.44096875, 2.45184375, 2.4599270833333335, 2.4681770833333334, 2.4746770833333334, 2.4855729166666665, 2.5209479166666666, 2.55503125, 2.5716979166666665, 2.5834895833333333, 2.591552083333333, 2.6127604166666667, 2.6709895833333333, 2.88928125, 3.134916666666667, 3.2006875, 3.3154375, 3.4335625, 4.24340625, 4.2707395833333335, 4.34684375, 14.862104166666667, 15.2978125, 15.543479166666666, 16.012020833333334, 16.19559375, 16.322864583333335, 16.855166666666666, 16.8641875, 19.730333333333334, 19.756604166666666, 19.76535416666667, 19.8773125, 19.9308125, 20.047833333333333, 20.227822916666668, 20.318989583333334, 20.336260416666665, 20.47409375, 20.584364583333333, 20.78321875, 20.79134375, 20.810072916666666, 20.824833333333334, 20.8931875, 20.906208333333332, 20.918354166666667, 20.9286875, 21.020104166666666, 21.109541666666665, 21.1209375, 21.129208333333334, 21.139520833333332, 28.955604166666667, 28.969427083333333, 29.12302083333333, 29.227, 29.93634375, 30.745760416666666, 30.862416666666668, 33.691541666666666, 33.70033333333333, 33.70483333333333, 45.592125, 48.75952083333333, 52.425875, 52.44083333333333, 53.031697916666666, 53.03701041666667, 57.72391666666667, 57.736291666666666, 57.74427083333333, ...] MEC LII 0.0024

... and 4 more row(s).

We can view the single unit data as a pandas DataFrame.

In [17]:
units_df = nwbfile.units.to_dataframe()
units_df
Out[17]:
unit_name spike_times histology hemisphere depth
id
0 t1c1 [0.7903958333333333, 0.794, 0.8111666666666667... MEC LII 0.0024
1 t2c1 [1.0451354166666667, 1.7003854166666668, 2.315... MEC LII 0.0024
2 t2c3 [0.18273958333333334, 0.5340729166666667, 0.57... MEC LII 0.0024
3 t3c1 [1.0358229166666666, 1.04803125, 1.69642708333... MEC LII 0.0024
4 t3c2 [2.43025, 2.4398333333333335, 3.17965625, 3.39... MEC LII 0.0024
5 t3c3 [2.1157708333333334, 2.425427083333333, 3.3630... MEC LII 0.0024
6 t3c4 [0.07945833333333334, 2.244947916666667, 3.173... MEC LII 0.0024
7 t4c1 [2.4301666666666666, 2.439770833333333, 3.1795... MEC LII 0.0024

To access the spike times of the first single unit, index this pandas dataframe with the column name, “spike_times”, and the row index, 0. All times in NWB are stored in seconds relative to the session start time.

In [18]:
units_df["spike_times"][0]
Out[18]:
array([  0.79039583,   0.794     ,   0.81116667, ..., 595.28703125,
       595.53125   , 599.68578125])

We can use these spike times to generate raster plots of single unit activity over time.

In [19]:
fig, ax = plt.subplots()
for i, st in enumerate(units_df['spike_times']):
    ax.plot(st, np.ones_like(st) + i, '|', markersize=20)
    ax.set(xlabel='Time (s)', ylabel='Unit number')
No description has been provided for this image

We can also inspect the columns of the Units table for useful metadata such as descriptions of the values of each column.

In [20]:
nwbfile.units["depth"].description
Out[20]:
'Indicates the depth of the inserted electrodes in meters.'

Using Pynapple for data analysis¶

Pynapple is a light-weight python library for neurophysiological data analysis that accepts NWB files as input.

Let's import pynapple and seaborn, set some seaborn plotting parameters, and load the streamed NWB file into Pynapple by creating a nap.NWBFile object using the pynwb.NWBFile object that we created earlier from io.read().

In [21]:
import pynapple as nap
import seaborn as sns

custom_params = {"axes.spines.right": False, "axes.spines.top": False}
sns.set_theme(style="ticks", palette="colorblind", font_scale=1.5, rc=custom_params)

nwb = nap.NWBFile(nwbfile)

nwb
Out[21]:
17010302
┍━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━┑
│ Keys                │ Type     │
┝━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━┥
│ units               │ TsGroup  │
│ ElectricalSeriesLFP │ Tsd      │
│ SpatialSeriesLED1   │ TsdFrame │
│ ElectricalSeries    │ Tsd      │
┕━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━┙

We can load the sorted units as a pynapple TsGroup for inspection.

In [22]:
units = nwb["units"]
units
Out[22]:
  Index     rate  unit_name    histology    hemisphere      depth
-------  -------  -----------  -----------  ------------  -------
      0  2.93217  t1c1         MEC LII                          0
      1  1.50193  t2c1         MEC LII                          0
      2  2.57878  t2c3         MEC LII                          0
      3  1.13186  t3c1         MEC LII                          0
      4  1.29356  t3c2         MEC LII                          0
      5  1.35857  t3c3         MEC LII                          0
      6  2.8855   t3c4         MEC LII                          0
      7  1.46525  t4c1         MEC LII                          0

We can also load the position data, which is a pynapple TsdFrame.

In [23]:
position = nwb["SpatialSeriesLED1"]
position
Out[23]:
Time (s)                     x         y
-------------------  ---------  --------
0.0                  -0.442795  17.1039
0.01999999999998181  -0.442795  17.1039
0.03999999999996362   1.26778   16.8596
0.05999999999994543   1.26778   16.8596
0.08000000000004093  -0.198426  17.1039
0.10000000000002274  -0.198426  17.1039
0.12000000000000455   1.02341   18.5701
...
599.86                2.97836    4.39679
599.88                2.97836    4.39679
599.9                 2.24526    4.88552
599.92                2.24526    4.88552
599.9399999999999     2.00089    6.84047
599.9599999999999     2.00089    6.84047
599.9799999999999     0.779046   4.64115
dtype: float64, shape: (30000, 2)

Next, let's compute the 2d tuning curves and plot them.

In [24]:
tc, binsxy = nap.compute_2d_tuning_curves(units, position, 20)

extent = (
    np.min(position["x"]),
    np.max(position["x"]),
    np.min(position["y"]),
    np.max(position["y"]),
)

plt.figure(figsize=(15, 7))
for i in tc.keys():
    plt.subplot(2, 4, i + 1)
    plt.imshow(tc[i], origin="lower", extent=extent, aspect="auto")
    plt.title("Unit {}".format(i))
plt.tight_layout()
plt.show()
/opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/pynapple/process/tuning_curves.py:665: FutureWarning: compute_2d_tuning_curves is deprecated and will be removed in a future version;use compute_tuning_curves instead.
  return func(**kwargs)
No description has been provided for this image

Finally, let's plot the spikes of unit 1, which has a nice grid. Let's use the function value_from to assign to each spike the closest position in time.

In [25]:
plt.figure(figsize=(15, 6))
plt.subplot(121)
plt.imshow(tc[1], origin="lower", extent=extent, aspect="auto")
plt.xlabel("x")
plt.ylabel("y")

plt.subplot(122)
plt.plot(position["y"], position["x"], color="grey")
spk_pos = units[1].value_from(position)
plt.plot(spk_pos["y"], spk_pos["x"], "o", color="red", markersize=5, alpha=0.5)
plt.xlabel("x")
plt.ylabel("y")
plt.tight_layout()
plt.show()
No description has been provided for this image

It is good practice to close any open file and IO objects when you are done working with them so that they can be modified by other processes.

In [26]:
io.close()
file.close()
f.close()
In [ ]: