Behavior Data

This tutorial will demonstrate the usage of the pynwb.behavior module for adding behavioral data to an NWBFile.

See also

You can learn more about the NWBFile format in the NWB File Basics tutorial.

The examples below follow this general workflow for adding behavior data to an NWBFile:

The following examples will reference variables that may not be defined within the block they are used in. For clarity, we define them here:

from datetime import datetime
from uuid import uuid4

import numpy as np
from dateutil.tz import tzlocal

from pynwb import NWBHDF5IO, NWBFile, TimeSeries
from pynwb.behavior import (
    BehavioralEpochs,
    BehavioralEvents,
    BehavioralTimeSeries,
    CompassDirection,
    EyeTracking,
    Position,
    PupilTracking,
    SpatialSeries,
)
from pynwb.epoch import TimeIntervals
from pynwb.misc import IntervalSeries

Create an NWB File

Create an NWBFile object with the required fields (session_description, identifier, session_start_time) and additional metadata.

nwbfile = NWBFile(
    session_description="my first synthetic recording",
    identifier=str(uuid4()),
    session_start_time=datetime.now(tzlocal()),
    experimenter=[
        "Baggins, Bilbo",
    ],
    lab="Bag End Laboratory",
    institution="University of Middle Earth at the Shire",
    experiment_description="I went on an adventure to reclaim vast treasures.",
    session_id="LONELYMTN001",
)

nwbfile

root (NWBFile)

session_description: my first synthetic recording
identifier: 6acea3c2-33b5-4f59-8bcd-25d8d8a7d6e5
session_start_time2024-02-21 21:51:17.146919+00:00
timestamps_reference_time2024-02-21 21:51:17.146919+00:00
file_create_date
02024-02-21 21:51:17.147267+00:00
experimenter
0: Baggins, Bilbo
epoch_tagsset()
experiment_description: I went on an adventure to reclaim vast treasures.
session_id: LONELYMTN001
lab: Bag End Laboratory
institution: University of Middle Earth at the Shire


SpatialSeries: Storing continuous spatial data

SpatialSeries is a subclass of TimeSeries that represents data in space, such as the spatial direction, e.g., of gaze or travel, or position of an animal over time.

Create data that corresponds to x, y position over time.

(50, 2)

In SpatialSeries data, the first dimension is always time (in seconds), the second dimension represents the x, y position (in meters).

Note

SpatialSeries data should be stored as one continuous stream, as it is acquired, not by trial as is often reshaped for analysis. Data can be trial-aligned on-the-fly using the trials table. See the Annotating Time Intervals tutorial for further information.

For position data reference_frame indicates the zero-position, e.g. the 0,0 point might be the bottom-left corner of an enclosure, as viewed from the tracking camera.

timestamps = np.linspace(0, 50) / 200

position_spatial_series = SpatialSeries(
    name="SpatialSeries",
    description="Position (x, y) in an open field.",
    data=position_data,
    timestamps=timestamps,
    reference_frame="(0,0) is bottom left corner",
)

position_spatial_series

SpatialSeries

resolution: -1.0
comments: no comments
description: Position (x, y) in an open field.
conversion: 1.0
offset: 0.0
unit: meters
data
[[ 0. 0. ]
[ 0.20408163 0.16326531]
[ 0.40816327 0.32653061]
[ 0.6122449 0.48979592]
[ 0.81632653 0.65306122]
[ 1.02040816 0.81632653]
[ 1.2244898 0.97959184]
[ 1.42857143 1.14285714]
[ 1.63265306 1.30612245]
[ 1.83673469 1.46938776]
[ 2.04081633 1.63265306]
[ 2.24489796 1.79591837]
[ 2.44897959 1.95918367]
[ 2.65306122 2.12244898]
[ 2.85714286 2.28571429]
[ 3.06122449 2.44897959]
[ 3.26530612 2.6122449 ]
[ 3.46938776 2.7755102 ]
[ 3.67346939 2.93877551]
[ 3.87755102 3.10204082]
[ 4.08163265 3.26530612]
[ 4.28571429 3.42857143]
[ 4.48979592 3.59183673]
[ 4.69387755 3.75510204]
[ 4.89795918 3.91836735]
[ 5.10204082 4.08163265]
[ 5.30612245 4.24489796]
[ 5.51020408 4.40816327]
[ 5.71428571 4.57142857]
[ 5.91836735 4.73469388]
[ 6.12244898 4.89795918]
[ 6.32653061 5.06122449]
[ 6.53061224 5.2244898 ]
[ 6.73469388 5.3877551 ]
[ 6.93877551 5.55102041]
[ 7.14285714 5.71428571]
[ 7.34693878 5.87755102]
[ 7.55102041 6.04081633]
[ 7.75510204 6.20408163]
[ 7.95918367 6.36734694]
[ 8.16326531 6.53061224]
[ 8.36734694 6.69387755]
[ 8.57142857 6.85714286]
[ 8.7755102 7.02040816]
[ 8.97959184 7.18367347]
[ 9.18367347 7.34693878]
[ 9.3877551 7.51020408]
[ 9.59183673 7.67346939]
[ 9.79591837 7.83673469]
[10. 8. ]]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1
reference_frame: (0,0) is bottom left corner


Position: Storing position measured over time

To help data analysis and visualization tools know that this SpatialSeries object represents the position of the subject, store the SpatialSeries object inside a Position object, which can hold one or more SpatialSeries objects.

position = Position(spatial_series=position_spatial_series)

See also

You can learn more about the SpatialSeries data type and Position interface in the Spatial Series and Position tutorial.

See also

You can learn more about best practices that can be applied to SpatialSeries at NWB Best Practices.

Create a Behavior Processing Module

Create a processing module called "behavior" for storing behavioral data in the NWBFile using the create_processing_module method, and then add the Position object to the processing module.

behavior_module = nwbfile.create_processing_module(
    name="behavior", description="Processed behavioral data"
)

behavior_module.add(position)

Position

spatial_series
SpatialSeries
resolution: -1.0
comments: no comments
description: Position (x, y) in an open field.
conversion: 1.0
offset: 0.0
unit: meters
data
[[ 0. 0. ]
[ 0.20408163 0.16326531]
[ 0.40816327 0.32653061]
[ 0.6122449 0.48979592]
[ 0.81632653 0.65306122]
[ 1.02040816 0.81632653]
[ 1.2244898 0.97959184]
[ 1.42857143 1.14285714]
[ 1.63265306 1.30612245]
[ 1.83673469 1.46938776]
[ 2.04081633 1.63265306]
[ 2.24489796 1.79591837]
[ 2.44897959 1.95918367]
[ 2.65306122 2.12244898]
[ 2.85714286 2.28571429]
[ 3.06122449 2.44897959]
[ 3.26530612 2.6122449 ]
[ 3.46938776 2.7755102 ]
[ 3.67346939 2.93877551]
[ 3.87755102 3.10204082]
[ 4.08163265 3.26530612]
[ 4.28571429 3.42857143]
[ 4.48979592 3.59183673]
[ 4.69387755 3.75510204]
[ 4.89795918 3.91836735]
[ 5.10204082 4.08163265]
[ 5.30612245 4.24489796]
[ 5.51020408 4.40816327]
[ 5.71428571 4.57142857]
[ 5.91836735 4.73469388]
[ 6.12244898 4.89795918]
[ 6.32653061 5.06122449]
[ 6.53061224 5.2244898 ]
[ 6.73469388 5.3877551 ]
[ 6.93877551 5.55102041]
[ 7.14285714 5.71428571]
[ 7.34693878 5.87755102]
[ 7.55102041 6.04081633]
[ 7.75510204 6.20408163]
[ 7.95918367 6.36734694]
[ 8.16326531 6.53061224]
[ 8.36734694 6.69387755]
[ 8.57142857 6.85714286]
[ 8.7755102 7.02040816]
[ 8.97959184 7.18367347]
[ 9.18367347 7.34693878]
[ 9.3877551 7.51020408]
[ 9.59183673 7.67346939]
[ 9.79591837 7.83673469]
[10. 8. ]]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1
reference_frame: (0,0) is bottom left corner


See also

You can read more about the basic concepts of processing modules in the Processing Modules tutorial.

CompassDirection: Storing view angle measured over time

Analogous to how position can be stored, we can create a SpatialSeries object for representing the view angle of the subject.

For direction data reference_frame indicates the zero-axes, for instance “straight-ahead” might be a specific pixel on the monitor, or some other point in space. The unit of measurement for the SpatialSeries object should be radians or degrees.

view_angle_data = np.linspace(0, 4, 50)

direction_spatial_series = SpatialSeries(
    name="SpatialSeries",
    description="View angle of the subject measured in radians.",
    data=view_angle_data,
    timestamps=timestamps,
    reference_frame="straight ahead",
    unit="radians",
)

direction = CompassDirection(
    spatial_series=direction_spatial_series, name="CompassDirection"
)

We can add a CompassDirection object to the behavior processing module the same way as we have added the position data:

behavior_module.add(direction)

CompassDirection

spatial_series
SpatialSeries
resolution: -1.0
comments: no comments
description: View angle of the subject measured in radians.
conversion: 1.0
offset: 0.0
unit: radians
data
[0. 0.08163265 0.16326531 0.24489796 0.32653061 0.40816327
0.48979592 0.57142857 0.65306122 0.73469388 0.81632653 0.89795918
0.97959184 1.06122449 1.14285714 1.2244898 1.30612245 1.3877551
1.46938776 1.55102041 1.63265306 1.71428571 1.79591837 1.87755102
1.95918367 2.04081633 2.12244898 2.20408163 2.28571429 2.36734694
2.44897959 2.53061224 2.6122449 2.69387755 2.7755102 2.85714286
2.93877551 3.02040816 3.10204082 3.18367347 3.26530612 3.34693878
3.42857143 3.51020408 3.59183673 3.67346939 3.75510204 3.83673469
3.91836735 4. ]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1
reference_frame: straight ahead


BehavioralTimeSeries: Storing continuous behavior data

BehavioralTimeSeries is an interface for storing continuous behavior data, such as the speed of a subject.

speed_data = np.linspace(0, 0.4, 50)

speed_time_series = TimeSeries(
    name="speed",
    data=speed_data,
    timestamps=timestamps,
    description="The speed of the subject measured over time.",
    unit="m/s",
)

behavioral_time_series = BehavioralTimeSeries(
    time_series=speed_time_series,
    name="BehavioralTimeSeries",
)

behavior_module.add(behavioral_time_series)

BehavioralTimeSeries

time_series
speed
resolution: -1.0
comments: no comments
description: The speed of the subject measured over time.
conversion: 1.0
offset: 0.0
unit: m/s
data
[0. 0.00816327 0.01632653 0.0244898 0.03265306 0.04081633
0.04897959 0.05714286 0.06530612 0.07346939 0.08163265 0.08979592
0.09795918 0.10612245 0.11428571 0.12244898 0.13061224 0.13877551
0.14693878 0.15510204 0.16326531 0.17142857 0.17959184 0.1877551
0.19591837 0.20408163 0.2122449 0.22040816 0.22857143 0.23673469
0.24489796 0.25306122 0.26122449 0.26938776 0.27755102 0.28571429
0.29387755 0.30204082 0.31020408 0.31836735 0.32653061 0.33469388
0.34285714 0.35102041 0.35918367 0.36734694 0.3755102 0.38367347
0.39183673 0.4 ]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1


BehavioralEvents: Storing behavioral events

BehavioralEvents is an interface for storing behavioral events. We can use it for storing the timing and amount of rewards (e.g. water amount) or lever press times.

reward_amount = [1.0, 1.5, 1.0, 1.5]
events_timestamps = [1.0, 2.0, 5.0, 6.0]

time_series = TimeSeries(
    name="lever_presses",
    data=reward_amount,
    timestamps=events_timestamps,
    description="The water amount the subject received as a reward.",
    unit="ml",
)

behavioral_events = BehavioralEvents(time_series=time_series, name="BehavioralEvents")

behavior_module.add(behavioral_events)

BehavioralEvents

time_series
lever_presses
resolution: -1.0
comments: no comments
description: The water amount the subject received as a reward.
conversion: 1.0
offset: 0.0
unit: ml
data
0: 1.0
1: 1.5
2: 1.0
3: 1.5
timestamps
0: 1.0
1: 2.0
2: 5.0
3: 6.0
timestamps_unit: seconds
interval: 1


Storing only the timestamps of the events is possible with the ndx-events NWB extension. You can also add labels associated with the events with this extension. You can find information about installation and example usage here.

See also

You can learn more about using extensions in the Extending NWB tutorial.

BehavioralEpochs: Storing intervals of behavior data

BehavioralEpochs is for storing intervals of behavior data. BehavioralEpochs uses IntervalSeries to represent behavioral epochs.

Create IntervalSeries object that represents the time intervals when the animal was running. IntervalSeries uses 1 to indicate the beginning of an interval and -1 to indicate the end.

run_intervals = IntervalSeries(
    name="running",
    description="Intervals when the animal was running.",
    data=[1, -1, 1, -1, 1, -1],
    timestamps=[0.5, 1.5, 3.5, 4.0, 7.0, 7.3],
)

behavioral_epochs = BehavioralEpochs(name="BehavioralEpochs")

behavioral_epochs.add_interval_series(run_intervals)

running (IntervalSeries)

resolution: -1.0
comments: no comments
description: Intervals when the animal was running.
conversion: 1.0
offset: 0.0
unit: n/a
data
0: 1
1: -1
2: 1
3: -1
4: 1
5: -1
timestamps
0: 0.5
1: 1.5
2: 3.5
3: 4.0
4: 7.0
5: 7.3
timestamps_unit: seconds
interval: 1


you can add more than one IntervalSeries to a BehavioralEpochs

sleep_intervals = IntervalSeries(
    name="sleeping",
    description="Intervals when the animal was sleeping.",
    data=[1, -1, 1, -1],
    timestamps=[15.0, 30.0, 60.0, 95.0],
)
behavioral_epochs.add_interval_series(sleep_intervals)

behavior_module.add(behavioral_epochs)

BehavioralEpochs

interval_series
running
resolution: -1.0
comments: no comments
description: Intervals when the animal was running.
conversion: 1.0
offset: 0.0
unit: n/a
data
0: 1
1: -1
2: 1
3: -1
4: 1
5: -1
timestamps
0: 0.5
1: 1.5
2: 3.5
3: 4.0
4: 7.0
5: 7.3
timestamps_unit: seconds
interval: 1
sleeping
resolution: -1.0
comments: no comments
description: Intervals when the animal was sleeping.
conversion: 1.0
offset: 0.0
unit: n/a
data
0: 1
1: -1
2: 1
3: -1
timestamps
0: 15.0
1: 30.0
2: 60.0
3: 95.0
timestamps_unit: seconds
interval: 1


Using TimeIntervals representing time intervals is often preferred over BehavioralEpochs and IntervalSeries. TimeIntervals is a subclass of DynamicTable which offers flexibility for tabular data by allowing the addition of optional columns which are not defined in the standard.

Create a TimeIntervals object that represents the time intervals when the animal was sleeping.

sleep_intervals = TimeIntervals(
    name="sleep_intervals",
    description="Intervals when the animal was sleeping.",
)

sleep_intervals.add_column(name="stage", description="The stage of sleep.")

sleep_intervals.add_row(start_time=0.3, stop_time=0.35, stage=1)
sleep_intervals.add_row(start_time=0.7, stop_time=0.9, stage=2)
sleep_intervals.add_row(start_time=1.3, stop_time=3.0, stage=3)

nwbfile.add_time_intervals(sleep_intervals)

sleep_intervals (TimeIntervals)

description: Intervals when the animal was sleeping.
table
start_time stop_time stage
id
0 0.3 0.35 1
1 0.7 0.90 2
2 1.3 3.00 3


PupilTracking: Storing continuous eye-tracking data of pupil size

PupilTracking is for storing eye-tracking data which represents pupil size. PupilTracking holds one or more TimeSeries objects that can represent different features such as the dilation of the pupil measured over time by a pupil tracking algorithm.

pupil_diameter = TimeSeries(
    name="pupil_diameter",
    description="Pupil diameter extracted from the video of the right eye.",
    data=np.linspace(0.001, 0.002, 50),
    timestamps=timestamps,
    unit="meters",
)

pupil_tracking = PupilTracking(time_series=pupil_diameter, name="PupilTracking")

behavior_module.add(pupil_tracking)

PupilTracking

time_series
pupil_diameter
resolution: -1.0
comments: no comments
description: Pupil diameter extracted from the video of the right eye.
conversion: 1.0
offset: 0.0
unit: meters
data
[0.001 0.00102041 0.00104082 0.00106122 0.00108163 0.00110204
0.00112245 0.00114286 0.00116327 0.00118367 0.00120408 0.00122449
0.0012449 0.00126531 0.00128571 0.00130612 0.00132653 0.00134694
0.00136735 0.00138776 0.00140816 0.00142857 0.00144898 0.00146939
0.0014898 0.0015102 0.00153061 0.00155102 0.00157143 0.00159184
0.00161224 0.00163265 0.00165306 0.00167347 0.00169388 0.00171429
0.00173469 0.0017551 0.00177551 0.00179592 0.00181633 0.00183673
0.00185714 0.00187755 0.00189796 0.00191837 0.00193878 0.00195918
0.00197959 0.002 ]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1


EyeTracking: Storing continuous eye-tracking data of gaze direction

EyeTracking is for storing eye-tracking data which represents direction of gaze as measured by an eye tracking algorithm. An EyeTracking object holds one or more SpatialSeries objects that represents the vertical and horizontal gaze positions extracted from a video.

right_eye_position = np.linspace(-20, 30, 50)

right_eye_positions = SpatialSeries(
    name="right_eye_position",
    description="The position of the right eye measured in degrees.",
    data=right_eye_position,
    timestamps=timestamps,
    reference_frame="bottom left",
    unit="degrees",
)

eye_tracking = EyeTracking(name="EyeTracking", spatial_series=right_eye_positions)

We can add another SpatialSeries representing the position of the left eye in degrees.

left_eye_position = np.linspace(-2, 20, 50)

left_eye_positions = SpatialSeries(
    name="left_eye_position",
    description="The position of the left eye measured in degrees.",
    data=left_eye_position,
    timestamps=timestamps,
    reference_frame="bottom left",
    unit="degrees",
)

eye_tracking.add_spatial_series(spatial_series=left_eye_positions)

behavior_module.add(eye_tracking)

EyeTracking

spatial_series
right_eye_position
resolution: -1.0
comments: no comments
description: The position of the right eye measured in degrees.
conversion: 1.0
offset: 0.0
unit: degrees
data
[-20. -18.97959184 -17.95918367 -16.93877551 -15.91836735
-14.89795918 -13.87755102 -12.85714286 -11.83673469 -10.81632653
-9.79591837 -8.7755102 -7.75510204 -6.73469388 -5.71428571
-4.69387755 -3.67346939 -2.65306122 -1.63265306 -0.6122449
0.40816327 1.42857143 2.44897959 3.46938776 4.48979592
5.51020408 6.53061224 7.55102041 8.57142857 9.59183673
10.6122449 11.63265306 12.65306122 13.67346939 14.69387755
15.71428571 16.73469388 17.75510204 18.7755102 19.79591837
20.81632653 21.83673469 22.85714286 23.87755102 24.89795918
25.91836735 26.93877551 27.95918367 28.97959184 30. ]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1
reference_frame: bottom left
left_eye_position
resolution: -1.0
comments: no comments
description: The position of the left eye measured in degrees.
conversion: 1.0
offset: 0.0
unit: degrees
data
[-2. -1.55102041 -1.10204082 -0.65306122 -0.20408163 0.24489796
0.69387755 1.14285714 1.59183673 2.04081633 2.48979592 2.93877551
3.3877551 3.83673469 4.28571429 4.73469388 5.18367347 5.63265306
6.08163265 6.53061224 6.97959184 7.42857143 7.87755102 8.32653061
8.7755102 9.2244898 9.67346939 10.12244898 10.57142857 11.02040816
11.46938776 11.91836735 12.36734694 12.81632653 13.26530612 13.71428571
14.16326531 14.6122449 15.06122449 15.51020408 15.95918367 16.40816327
16.85714286 17.30612245 17.75510204 18.20408163 18.65306122 19.10204082
19.55102041 20. ]
timestamps
[0. 0.00510204 0.01020408 0.01530612 0.02040816 0.0255102
0.03061224 0.03571429 0.04081633 0.04591837 0.05102041 0.05612245
0.06122449 0.06632653 0.07142857 0.07653061 0.08163265 0.08673469
0.09183673 0.09693878 0.10204082 0.10714286 0.1122449 0.11734694
0.12244898 0.12755102 0.13265306 0.1377551 0.14285714 0.14795918
0.15306122 0.15816327 0.16326531 0.16836735 0.17346939 0.17857143
0.18367347 0.18877551 0.19387755 0.19897959 0.20408163 0.20918367
0.21428571 0.21938776 0.2244898 0.22959184 0.23469388 0.23979592
0.24489796 0.25 ]
timestamps_unit: seconds
interval: 1
reference_frame: bottom left


Writing the behavior data to an NWB file

As demonstrated in the Writing an NWB file tutorial, we will use NWBHDF5IO to write the file.

with NWBHDF5IO("behavioral_tutorial.nwb", "w") as io:
    io.write(nwbfile)

Reading and accessing the behavior data

To read the NWB file we just wrote, use another NWBHDF5IO object, and use the read method to retrieve an NWBFile object.

We can access the behavior processing module by indexing nwbfile.processing with the name of the processing module "behavior". We can also inspect the objects hierarchy within this processing module with the .children attribute.

with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io:
    read_nwbfile = io.read()
    print(read_nwbfile.processing["behavior"].children)
(BehavioralEpochs pynwb.behavior.BehavioralEpochs at 0x140203625346064
Fields:
  interval_series: {
    running <class 'pynwb.misc.IntervalSeries'>,
    sleeping <class 'pynwb.misc.IntervalSeries'>
  }
, BehavioralEvents pynwb.behavior.BehavioralEvents at 0x140203624936912
Fields:
  time_series: {
    lever_presses <class 'pynwb.base.TimeSeries'>
  }
, BehavioralTimeSeries pynwb.behavior.BehavioralTimeSeries at 0x140203624151312
Fields:
  time_series: {
    speed <class 'pynwb.base.TimeSeries'>
  }
, CompassDirection pynwb.behavior.CompassDirection at 0x140203624464912
Fields:
  spatial_series: {
    SpatialSeries <class 'pynwb.behavior.SpatialSeries'>
  }
, EyeTracking pynwb.behavior.EyeTracking at 0x140203625337296
Fields:
  spatial_series: {
    left_eye_position <class 'pynwb.behavior.SpatialSeries'>,
    right_eye_position <class 'pynwb.behavior.SpatialSeries'>
  }
, Position pynwb.behavior.Position at 0x140203625644432
Fields:
  spatial_series: {
    SpatialSeries <class 'pynwb.behavior.SpatialSeries'>
  }
, PupilTracking pynwb.behavior.PupilTracking at 0x140203624883344
Fields:
  time_series: {
    pupil_diameter <class 'pynwb.base.TimeSeries'>
  }
)

For instance, we can access the SpatialSeries data by referencing the names of the objects in the hierarchy that contain it. We can access the Position object inside the behavior processing module by indexing it with the name of the Position object, "Position". Then, we can access the SpatialSeries object inside the Position object by indexing it with the name of the SpatialSeries object, "SpatialSeries".

with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io:
    read_nwbfile = io.read()
    print(read_nwbfile.processing["behavior"]["Position"]["SpatialSeries"])
SpatialSeries pynwb.behavior.SpatialSeries at 0x140203625863184
Fields:
  comments: no comments
  conversion: 1.0
  data: <HDF5 dataset "data": shape (50, 2), type "<f8">
  description: Position (x, y) in an open field.
  interval: 1
  offset: 0.0
  reference_frame: (0,0) is bottom left corner
  resolution: -1.0
  timestamps: <HDF5 dataset "timestamps": shape (50,), type "<f8">
  timestamps_unit: seconds
  unit: meters

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

with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io:
    read_nwbfile = io.read()
    print(read_nwbfile.processing["behavior"]["Position"]["SpatialSeries"].data[:])
[[ 0.          0.        ]
 [ 0.20408163  0.16326531]
 [ 0.40816327  0.32653061]
 [ 0.6122449   0.48979592]
 [ 0.81632653  0.65306122]
 [ 1.02040816  0.81632653]
 [ 1.2244898   0.97959184]
 [ 1.42857143  1.14285714]
 [ 1.63265306  1.30612245]
 [ 1.83673469  1.46938776]
 [ 2.04081633  1.63265306]
 [ 2.24489796  1.79591837]
 [ 2.44897959  1.95918367]
 [ 2.65306122  2.12244898]
 [ 2.85714286  2.28571429]
 [ 3.06122449  2.44897959]
 [ 3.26530612  2.6122449 ]
 [ 3.46938776  2.7755102 ]
 [ 3.67346939  2.93877551]
 [ 3.87755102  3.10204082]
 [ 4.08163265  3.26530612]
 [ 4.28571429  3.42857143]
 [ 4.48979592  3.59183673]
 [ 4.69387755  3.75510204]
 [ 4.89795918  3.91836735]
 [ 5.10204082  4.08163265]
 [ 5.30612245  4.24489796]
 [ 5.51020408  4.40816327]
 [ 5.71428571  4.57142857]
 [ 5.91836735  4.73469388]
 [ 6.12244898  4.89795918]
 [ 6.32653061  5.06122449]
 [ 6.53061224  5.2244898 ]
 [ 6.73469388  5.3877551 ]
 [ 6.93877551  5.55102041]
 [ 7.14285714  5.71428571]
 [ 7.34693878  5.87755102]
 [ 7.55102041  6.04081633]
 [ 7.75510204  6.20408163]
 [ 7.95918367  6.36734694]
 [ 8.16326531  6.53061224]
 [ 8.36734694  6.69387755]
 [ 8.57142857  6.85714286]
 [ 8.7755102   7.02040816]
 [ 8.97959184  7.18367347]
 [ 9.18367347  7.34693878]
 [ 9.3877551   7.51020408]
 [ 9.59183673  7.67346939]
 [ 9.79591837  7.83673469]
 [10.          8.        ]]

Alternatively, you can read only a portion of the data by indexing or slicing into the data attribute just like if you were indexing or slicing a numpy array.

with NWBHDF5IO("behavioral_tutorial.nwb", "r") as io:
    read_nwbfile = io.read()
    print(read_nwbfile.processing["behavior"]["Position"]["SpatialSeries"].data[:2])
[[0.         0.        ]
 [0.20408163 0.16326531]]

Gallery generated by Sphinx-Gallery