# 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).
NWB Widgets¶
NWB Widgets is a python package for automatic, interactive, performant exploration of data in NWB files. This notebook demonstrates how to use NWB Widgets to explore data, and how to stream data from the DANDI archive directly into NWB Widgets.
NWB Widgets uses the metadata of the NWB file to understand the contents and infer what visualizations make sense for this data. The code is exactly the same for visualizing each different NWB filea. We demonstrate this here with one calcium imaging NWB file and one with Neuropixel extracellular electrophysiology.
While this notebook can be run on a properly configured environment anywhere, it will be particularly easy to use and performant using the "NWBstream" environment deployed for free on DANDI Hub.
import pynwb
from pynwb import NWBHDF5IO
from nwbwidgets import nwb2widget
import requests
def _search_assets(url, filepath):
response = requests.request("GET", url, headers={"Accept": "application/json"}).json()
for asset in response["results"]:
if filepath == asset["path"]:
return asset["asset_id"]
if response.get("next", None):
return _search_assets(response["next"], filepath)
raise ValueError(f'path {filepath} not found in dandiset {dandiset_id}.')
def get_asset_id(dandiset_id, filepath):
url = f"https://api.dandiarchive.org/api/dandisets/{dandiset_id}/versions/draft/assets/"
return _search_assets(url, filepath)
def get_s3_url(dandiset_id, filepath):
"""Get the s3 location for any NWB file on DANDI"""
asset_id = get_asset_id(dandiset_id, filepath)
url = f"https://api.dandiarchive.org/api/dandisets/{dandiset_id}/versions/draft/assets/{asset_id}/download/"
s3_url = requests.request(url=url, method='head').url
if '?' in s3_url:
return s3_url[:s3_url.index('?')]
return s3_url
# calcium imaging, Giocomo Lab (1.4 GB)
dandiset_id, filepath = "000054", "sub-F2/sub-F2_ses-training-day1_behavior+ophys.nwb"
# neuropixel, Giocomo Lab (46 GB)
#dandiset_id, filepath = "000053", "sub-npI1/sub-npI1_ses-20190415_behavior+ecephys.nwb"
s3_path = get_s3_url(dandiset_id, filepath)
Note that these NWB files are quite large. In fact, we have chosen NWB files that contain raw data to demonstrate how data streaming can efficiently deal with these large files. Streaming works efficiently with NWB Widgets so that only the data necessary to create each view is read from DANDI. As a result, data transfer is minimized and data can be explored efficiently.
# stream data directly from DANDI (or any other S3 location) with remfile
import h5py
import remfile
# cache reads on disk so re-running cells doesn't re-fetch the same bytes
rem_file = remfile.File(s3_path, disk_cache=remfile.DiskCache("nwb-cache"))
h5py_file = h5py.File(rem_file, "r")
io = NWBHDF5IO(file=h5py_file, load_namespaces=True)
nwb = io.read()
nwb2widget(nwb)
/opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/spec/namespace.py:535: UserWarning: Ignoring cached namespace 'core' version 2.9.0 because version 2.7.0 is already loaded.
warn("Ignoring cached namespace '%s' version %s because version %s is already loaded."
Running NWBWidgets locally¶
You can also download NWB files and run NWB Widgets locally by passing the local path directly. Here we will demonstrate this with a smaller intracellular electrophysiology dataset.
# icephys and behavior, Svoboda Lab (44 MB)
import os
import tempfile
import requests
dandiset_id, filepath = "000005", "sub-anm236462/sub-anm236462_ses-20140210_behavior+icephys.nwb"
asset_id = get_asset_id(dandiset_id, filepath)
url = f"https://api.dandiarchive.org/api/dandisets/{dandiset_id}/versions/draft/assets/{asset_id}/download/"
local_path = os.path.join(tempfile.gettempdir(), os.path.basename(filepath))
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_path, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 20):
f.write(chunk)
print(f"downloaded to {local_path}")
downloaded to /tmp/sub-anm236462_ses-20140210_behavior+icephys.nwb
The file is now on the local filesystem, so we can open it by passing its path to NWBHDF5IO directly.
io = NWBHDF5IO(local_path, mode='r', load_namespaces=True)
nwb = io.read()
nwb2widget(nwb)
/opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/spec/namespace.py:535: UserWarning: Ignoring cached namespace 'hdmf-common' version 1.1.3 because version 1.8.0 is already loaded.
warn("Ignoring cached namespace '%s' version %s because version %s is already loaded."
/opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/hdmf/spec/namespace.py:535: UserWarning: Ignoring cached namespace 'core' version 2.2.2 because version 2.7.0 is already loaded.
warn("Ignoring cached namespace '%s' version %s because version %s is already loaded."
When running with local data, NWBWidgets still only reads the data that is necessary from disk.