Skip to content

Note

Click here to download the full example code

IO Tutorial

This notebook is designed to demonstrate the pynapple IO. It is build around the specifications of the BIDS standard for sharing datasets. The key ideas are summarized as follow :


First let's import the necessary packages.

mkdocs_gallery_thumbnail_path = '_static/treeview.png'

import numpy as np
import pynapple as nap
import os
import requests, math
import tqdm
import zipfile

Here we download a small example dataset.

project_path = "MyProject"


if project_path not in os.listdir("."):
  r = requests.get(f"https://osf.io/a9n6r/download", stream=True)
  block_size = 1024*1024
  with open(project_path+".zip", 'wb') as f:
    for data in tqdm.tqdm(r.iter_content(block_size), unit='MB', unit_scale=True,
      total=math.ceil(int(r.headers.get('content-length', 0))//block_size)):
      f.write(data)

  with zipfile.ZipFile(project_path+".zip", 'r') as zip_ref:
    zip_ref.extractall(".")

Out:

  0%|          | 0.00/5.00 [00:00<?, ?MB/s]
6.00MB [00:00, 65.8MB/s]                   

Let's load the project with nap.load_folder.

project = nap.load_folder(project_path)

print(project)

Out:

/mnt/home/gviejo/mambaforge/envs/pynapple/lib/python3.11/site-packages/hdmf/utils.py:668: UserWarning: Ignoring cached namespace 'core' version 2.6.0-alpha because version 2.7.0 is already loaded.
  return func(args[0], **pargs)
📂 MyProject
└── 📂 sub-A2929

The pynapple IO Folders class offers a convenient way of visualizing and navigating a folder based dataset. To visualize the whole hierarchy of Folders, you can call the view property or the expand function.

project.view

Out:

📂 MyProject
└── 📂 sub-A2929
    └── 📂 A2929-200711
        ├── 📂 derivatives
        │   ├── spikes.npz      |        TsGroup
        │   ├── sleep_ep.npz    |        IntervalSet
        │   ├── position.npz    |        TsdFrame
        │   └── wake_ep.npz     |        IntervalSet
        └── 📂 pynapplenwb
            └── A2929-200711    |        NWB file

Here it shows all the subjects (in this case only A2929), all the sessions and all of the derivatives folders. It shows as well all the NPZ files that contains a pynapple object and the NWB files.

The object project behaves like a nested dictionary. It is then easy to loop and navigate through a hierarchy of folders when doing analyses. In this case, we are gonna take only the session A2929-200711.

session = project["sub-A2929"]["A2929-200711"]

print(session)

Out:

📂 A2929-200711
├── 📂 derivatives
└── 📂 pynapplenwb

I can expand to see what the folders contains.

print(session.expand())

Out:

📂 A2929-200711
├── 📂 derivatives
│   ├── spikes.npz      |        TsGroup
│   ├── sleep_ep.npz    |        IntervalSet
│   ├── position.npz    |        TsdFrame
│   └── wake_ep.npz     |        IntervalSet
└── 📂 pynapplenwb
    └── A2929-200711    |        NWB file
None

Loading files

By default, pynapple save objects as NPZ. It is a convenient way to save all the properties of an object such as the time support. The pynapple IO offers an easy way to load any NPZ files that matches the structures defined for a pynapple object.

spikes = session["derivatives"]["spikes"]
position = session["derivatives"]["position"]
wake_ep = session["derivatives"]["wake_ep"]
sleep_ep = session["derivatives"]["sleep_ep"]

Objects are only loaded when they are called.

print(session["derivatives"]["spikes"])

Out:

Index    rate     location    group
-------  -------  ----------  -------
0        7.30333  adn         0
1        5.7325   adn         0
2        8.11917  adn         0
3        6.67833  adn         0
...      ...      ...         ...
11       3.30833  ca1         1
12       1.09417  ca1         1
13       1.27917  ca1         1
14       1.32333  ca1         1

Metadata

A good practice for sharing datasets is to write as many metainformation as possible. Following BIDS specifications, any data files should be accompagned by a JSON sidecar file.

import os

for f in os.listdir(session["derivatives"].path):
    print(f)

Out:

wake_ep.json
spikes.npz
sleep_ep.npz
spikes.json
position.npz
wake_ep.npz

To read the metainformation associated with a file, you can use the functions doc, info or metadata :

session["derivatives"].doc("spikes")


session["derivatives"].doc("position")

Out:

╭─ MyProject/sub-A2929/A2929-200711/derivatives/spikes.npz ─╮
│ time : 2024-04-29 14:38:34.962905                         │
│ info :                                                    │
╰───────────────────────────────────────────────────────────╯
╭─ MyProject/sub-A2929/A2929-200711/derivatives/position.npz ─╮
│ No metadata                                                 │
╰─────────────────────────────────────────────────────────────╯

Saving a pynapple object

In this case, we define a new Tsd and a new IntervalSet that we would like to save in the session folder.

tsd = position["x"] + 1
epoch = nap.IntervalSet(start=np.array([0, 3]), end=np.array([1, 6]))

session.save("x_plus_1", tsd, description="Random position")
session.save("stimulus-fish", epoch, description="Fish pictures to V1")

We can visualize the newly saved objects.

session.expand()

Out:

📂 A2929-200711
├── 📂 derivatives
│   ├── spikes.npz      |        TsGroup
│   ├── sleep_ep.npz    |        IntervalSet
│   ├── position.npz    |        TsdFrame
│   └── wake_ep.npz     |        IntervalSet
├── 📂 pynapplenwb
│   └── A2929-200711    |        NWB file
├── x_plus_1.npz    |        Tsd
└── stimulus-fish.npz       |        IntervalSet
session.doc("stimulus-fish")

Out:

╭─ MyProject/sub-A2929/A2929-200711/stimulus-fish.npz ─╮
│ time : 2024-09-27 15:14:54.678729                    │
│ info : Fish pictures to V1                           │
╰──────────────────────────────────────────────────────╯
session["x_plus_1"]

Out:

Time (s)
----------  --------
670.6407    0.957143
670.649     0.956137
670.65735   0.955147
670.66565   0.954213
...
1199.96995  1.01097
1199.97825  1.01079
1199.9866   1.01066
1199.99495  1.01062
dtype: float64, shape: (63527,)

Total running time of the script: ( 0 minutes 6.008 seconds)

Download Python source code: tutorial_pynapple_io.py

Download Jupyter notebook: tutorial_pynapple_io.ipynb

Gallery generated by mkdocs-gallery