Skip to content

Commit b54ba1b

Browse files
bendichteroruebel
andauthored
add docs for editing NWB files (#1836)
* add docs for editing NWB files * rmv unnecessary imports * fixing formatting * minor edits * remove python code that is not rendering * improve editing tutorial * fixing up tutorial * Update docs/gallery/advanced_io/plot_editing.py Co-authored-by: Oliver Ruebel <oruebel@users.noreply.github.com> * using pynwb where possible * improve the editing tutorial and have it cross-reference with the add_remove_containers tutorial * add note formatting * refactoring * Update docs/gallery/general/add_remove_containers.py * Update docs/gallery/advanced_io/plot_editing.py Co-authored-by: Oliver Ruebel <oruebel@users.noreply.github.com> * Update docs/gallery/advanced_io/plot_editing.py Co-authored-by: Oliver Ruebel <oruebel@users.noreply.github.com> * Update docs/gallery/advanced_io/plot_editing.py Co-authored-by: Oliver Ruebel <oruebel@users.noreply.github.com> * flake8 --------- Co-authored-by: Oliver Ruebel <oruebel@users.noreply.github.com>
1 parent c40df49 commit b54ba1b

2 files changed

Lines changed: 166 additions & 23 deletions

File tree

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
"""
2+
.. _editing:
3+
4+
Editing NWB files
5+
=================
6+
7+
This tutorial demonstrates how to edit NWB files in-place to make small changes to
8+
existing containers. To add or remove containers from an NWB file, see
9+
:ref:`modifying_data`. How and whether it is possible to edit an NWB file depends on the
10+
storage backend and the type of edit.
11+
12+
.. warning::
13+
14+
Manually editing an existing NWB file can make the file invalid if you are not
15+
careful. We highly recommend making a copy before editing and running a validation
16+
check on the file after editing it. See :ref:`validating`.
17+
18+
19+
Editing datasets
20+
----------------
21+
When reading an HDF5 NWB file, PyNWB exposes :py:class:`h5py.Dataset` objects, which can
22+
be edited in place. For this to work, you must open the file in read/write mode
23+
(``"r+"`` or ``"a"``).
24+
25+
First, let's create an NWB file with data:
26+
"""
27+
from pynwb import NWBHDF5IO, NWBFile, TimeSeries
28+
from datetime import datetime
29+
from dateutil.tz import tzlocal
30+
import numpy as np
31+
32+
nwbfile = NWBFile(
33+
session_description="my first synthetic recording",
34+
identifier="EXAMPLE_ID",
35+
session_start_time=datetime.now(tzlocal()),
36+
session_id="LONELYMTN",
37+
)
38+
39+
nwbfile.add_acquisition(
40+
TimeSeries(
41+
name="synthetic_timeseries",
42+
description="Random values",
43+
data=np.random.randn(100, 100),
44+
unit="m",
45+
rate=10e3,
46+
)
47+
)
48+
49+
with NWBHDF5IO("test_edit.nwb", "w") as io:
50+
io.write(nwbfile)
51+
52+
##############################################
53+
# Now, let's edit the values of the dataset
54+
55+
with NWBHDF5IO("test_edit.nwb", "r+") as io:
56+
nwbfile = io.read()
57+
nwbfile.acquisition["synthetic_timeseries"].data[:10] = 0.0
58+
59+
60+
##############################################
61+
# You can edit the attributes of that dataset through the ``attrs`` attribute:
62+
63+
with NWBHDF5IO("test_edit.nwb", "r+") as io:
64+
nwbfile = io.read()
65+
nwbfile.acquisition["synthetic_timeseries"].data.attrs["unit"] = "volts"
66+
67+
##############################################
68+
# Changing the shape of dataset
69+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
70+
# Whether it is possible to change the shape of a dataset depends on how the dataset was
71+
# created. If the dataset was created with a flexible shape, then it is possible to
72+
# change in-place. Creating a dataset with a flexible shape is done by specifying the
73+
# ``maxshape`` argument of the :py:class:`~hdmf.backends.hdf5.h5_utils.H5DataIO` class
74+
# constructor. Using a ``None`` value for a component of the ``maxshape`` tuple allows
75+
# the size of the corresponding dimension to grow, such that is can be be reset arbitrarily long
76+
# in that dimension. Chunking is required for datasets with flexible shapes. Setting ``maxshape``,
77+
# hence, automatically sets chunking to ``True``, if not specified.
78+
#
79+
# First, let's create an NWB file with a dataset with a flexible shape:
80+
81+
from hdmf.backends.hdf5.h5_utils import H5DataIO
82+
83+
nwbfile = NWBFile(
84+
session_description="my first synthetic recording",
85+
identifier="EXAMPLE_ID",
86+
session_start_time=datetime.now(tzlocal()),
87+
session_id="LONELYMTN",
88+
)
89+
90+
data_io = H5DataIO(data=np.random.randn(100, 100), maxshape=(None, 100))
91+
92+
nwbfile.add_acquisition(
93+
TimeSeries(
94+
name="synthetic_timeseries",
95+
description="Random values",
96+
data=data_io,
97+
unit="m",
98+
rate=10e3,
99+
)
100+
)
101+
102+
with NWBHDF5IO("test_edit2.nwb", "w") as io:
103+
io.write(nwbfile)
104+
105+
##############################################
106+
# The ``None``value in the first component of ``maxshape`` means that the
107+
# the first dimension of the dataset is unlimited. By setting the second dimension
108+
# of ``maxshape`` to ``100``, that dimension is fixed to be no larger than ``100``.
109+
# If you do not specify a``maxshape``, then the shape of the dataset will be fixed
110+
# to the shape that the dataset was created with. Here, you can change the shape of
111+
# the first dimension of this dataset.
112+
113+
114+
with NWBHDF5IO("test_edit2.nwb", "r+") as io:
115+
nwbfile = io.read()
116+
nwbfile.acquisition["synthetic_timeseries"].data.resize((200, 100))
117+
118+
##############################################
119+
# This will change the shape of the dataset in-place. If you try to change the shape of
120+
# a dataset with a fixed shape, you will get an error.
121+
#
122+
# .. note::
123+
# There are several types of dataset edits that cannot be done in-place: changing the
124+
# shape of a dataset with a fixed shape, or changing the datatype, compression,
125+
# chunking, max-shape, or fill-value of a dataset. For any of these, we recommend using
126+
# the :py:class:`pynwb.NWBHDF5IO.export` method to export the data to a new file. See
127+
# :ref:`modifying_data` for more information.
128+
#
129+
# Editing groups
130+
# --------------
131+
# Editing of groups is not yet supported in PyNWB.
132+
# To edit the attributes of a group, open the file and edit it using :py:mod:`h5py`:
133+
134+
import h5py
135+
136+
with h5py.File("test_edit.nwb", "r+") as f:
137+
f["acquisition"]["synthetic_timeseries"].attrs["description"] = "Random values in volts"
138+
139+
##############################################
140+
# .. warning::
141+
# Be careful not to edit values that will bring the file out of compliance with the
142+
# NWB specification.
143+
#
144+
# Renaming groups and datasets
145+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146+
# Rename groups and datasets in-place using the :py:meth:`~h5py.Group.move` method. For example, to rename
147+
# the ``"synthetic_timeseries"`` group:
148+
149+
with h5py.File("test_edit.nwb", "r+") as f:
150+
f["acquisition"].move("synthetic_timeseries", "synthetic_timeseries_renamed")
151+
152+
##############################################
153+
# You can use this same technique to move a group or dataset to a different location in
154+
# the file. For example, to move the ``"synthetic_timeseries_renamed"`` group to the
155+
# ``"analysis"`` group:
156+
157+
with h5py.File("test_edit.nwb", "r+") as f:
158+
f["acquisition"].move(
159+
"synthetic_timeseries_renamed",
160+
"/analysis/synthetic_timeseries_renamed",
161+
)

docs/gallery/general/add_remove_containers.py

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -70,31 +70,13 @@
7070
# file path, and it is not possible to remove objects from an NWB file. You can use the
7171
# :py:meth:`NWBHDF5IO.export <pynwb.NWBHDF5IO.export>` method, detailed below, to modify an NWB file in these ways.
7272
#
73-
# .. warning::
74-
#
75-
# NWB datasets that have been written to disk are read as :py:class:`h5py.Dataset <h5py.Dataset>` objects.
76-
# Directly modifying the data in these :py:class:`h5py.Dataset <h5py.Dataset>` objects immediately
77-
# modifies the data on disk
78-
# (the :py:meth:`NWBHDF5IO.write <pynwb.NWBHDF5IO.write>` method does not need to be called and the
79-
# :py:class:`~pynwb.NWBHDF5IO` instance does not need to be closed). Directly modifying datasets in this way
80-
# can lead to files that do not validate or cannot be opened, so exercise caution when using this method.
81-
# Note: only chunked datasets or datasets with ``maxshape`` set can be resized.
82-
# See the `h5py chunked storage documentation <https://docs.h5py.org/en/stable/high/dataset.html#chunked-storage>`_
83-
# for more details.
84-
85-
###############################################################################
86-
# .. note::
87-
#
88-
# It is not possible to modify the attributes (fields) of an NWB container in memory.
89-
90-
###############################################################################
9173
# Exporting a written NWB file to a new file path
92-
# ---------------------------------------------------
74+
# -----------------------------------------------
9375
# Use the :py:meth:`NWBHDF5IO.export <pynwb.NWBHDF5IO.export>` method to read data from an existing NWB file,
9476
# modify the data, and write the modified data to a new file path. Modifications to the data can be additions or
9577
# removals of objects, such as :py:class:`~pynwb.base.TimeSeries` objects. This is especially useful if you
96-
# have raw data and processed data in the same NWB file and you want to create a new NWB file with all of the
97-
# contents of the original file except for the raw data for sharing with collaborators.
78+
# have raw data and processed data in the same NWB file and you want to create a new NWB file with all the contents of
79+
# the original file except for the raw data for sharing with collaborators.
9880
#
9981
# To remove existing containers, use the :py:class:`~hdmf.utils.LabelledDict.pop` method on any
10082
# :py:class:`~hdmf.utils.LabelledDict` object, such as ``NWBFile.acquisition``, ``NWBFile.processing``,
@@ -200,7 +182,7 @@
200182
export_io.export(src_io=read_io, nwbfile=read_nwbfile)
201183

202184
###############################################################################
203-
# More information about export
204-
# ---------------------------------
205185
# For more information about the export functionality, see :ref:`export`
206186
# and the PyNWB documentation for :py:meth:`NWBHDF5IO.export <pynwb.NWBHDF5IO.export>`.
187+
#
188+
# For more information about editing a file in place, see :ref:`editing`.

0 commit comments

Comments
 (0)