Metadata#
Metadata can be added to TsGroup
, IntervalSet
, and TsdFrame
objects at initialization or after an object has been created.
TsGroup
metadata is information associated with each Ts/Tsd object, such as brain region or unit type.IntervalSet
metadata is information associated with each interval, such as a trial label or stimulus condition.TsdFrame
metadata is information associated with each column, such as a channel or position.
Adding metadata at initialization#
At initialization, metadata can be passed via a dictionary or pandas DataFrame using the keyword argument metadata
. The metadata name is taken from the dictionary key or DataFrame column, and it can be set to any string name with a couple class-specific exceptions.
Class-specific exceptions
If column names are supplied to
TsdFrame
, metadata cannot overlap with those names.The
rate
attribute forTsGroup
is stored with the metadata and cannot be overwritten.
The length of the metadata must match the length of the object it describes (see class examples below for more detail).
Show code cell content
import numpy as np
import pandas as pd
import pynapple as nap
# input parameters for TsGroup
group = {
1: nap.Ts(t=np.sort(np.random.uniform(0, 100, 10))),
2: nap.Ts(t=np.sort(np.random.uniform(0, 100, 20))),
3: nap.Ts(t=np.sort(np.random.uniform(0, 100, 30))),
}
# input parameters for IntervalSet
starts = [0,10,20]
ends = [5,15,25]
# input parameters for TsdFrame
t = np.arange(5)
d = np.ones((5,3))
columns = ["a", "b", "c"]
TsGroup
#
Metadata added to TsGroup
must match the number of Ts
/Tsd
objects, or the length of its index
property.
metadata = {"region": ["pfc", "ofc", "hpc"]}
tsgroup = nap.TsGroup(group, metadata=metadata)
print(tsgroup)
Index rate region
------- ------- --------
1 0.10584 pfc
2 0.21167 ofc
3 0.31751 hpc
When initializing with a DataFrame, the index must align with the input dictionary keys (only when a dictionary is used to create the TsGroup
).
metadata = pd.DataFrame(
index=group.keys(),
data=["pfc", "ofc", "hpc"],
columns=["region"]
)
tsgroup = nap.TsGroup(group, metadata=metadata)
print(tsgroup)
Index rate region
------- ------- --------
1 0.10584 pfc
2 0.21167 ofc
3 0.31751 hpc
IntervalSet
#
Metadata added to IntervalSet
must match the number of intervals, or the length of its index
property.
metadata = {
"reward": [1, 0, 1],
"choice": ["left", "right", "left"],
}
intervalset = nap.IntervalSet(starts, ends, metadata=metadata)
print(intervalset)
index start end reward choice
0 0 5 1 left
1 10 15 0 right
2 20 25 1 left
shape: (3, 2), time unit: sec.
Metadata can be initialized as a DataFrame using the metadata argument, or it can be inferred when initializing an IntervalSet
with a DataFrame.
df = pd.DataFrame(
data=[[0, 5, 1, "left"], [10, 15, 0, "right"], [20, 25, 1, "left"]],
columns=["start", "end", "reward", "choice"]
)
intervalset = nap.IntervalSet(df)
print(intervalset)
index start end reward choice
0 0 5 1 left
1 10 15 0 right
2 20 25 1 left
shape: (3, 2), time unit: sec.
TsdFrame
#
Metadata added to TsdFrame
must match the number of data columns, or the length of its columns
property.
metadata = {
"color": ["red", "blue", "green"],
"position": [10,20,30]
}
tsdframe = nap.TsdFrame(d=d, t=t, columns=["a", "b", "c"], metadata=metadata)
print(tsdframe)
Time (s) a b c
---------- -------- -------- --------
0.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0
2.0 1.0 1.0 1.0
3.0 1.0 1.0 1.0
4.0 1.0 1.0 1.0
Metadata
-------- -------- -------- --------
color red blue green
position 10 20 30
dtype: float64, shape: (5, 3)
When initializing with a DataFrame, the DataFrame index must match the TsdFrame
columns.
metadata = pd.DataFrame(
index=["a", "b", "c"],
data=[["red", 10], ["blue", 20], ["green", 30]],
columns=["color", "position"],
)
tsdframe = nap.TsdFrame(d=d, t=t, columns=["a", "b", "c"], metadata=metadata)
print(tsdframe)
Time (s) a b c
---------- -------- -------- --------
0.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0
2.0 1.0 1.0 1.0
3.0 1.0 1.0 1.0
4.0 1.0 1.0 1.0
Metadata
-------- -------- -------- --------
color red blue green
position 10 20 30
dtype: float64, shape: (5, 3)
Adding metadata after initialization#
After creation, metadata can be added using the class method set_info()
. Additionally, single metadata fields can be added as a dictionary-like key or as an attribute, with a few noted exceptions outlined below.
Note
The remaining metadata examples will be shown on a TsGroup
object; however, all examples can be directly applied to IntervalSet
and TsdFrame
objects.
set_info
#
Metadata can be passed as a dictionary or pandas DataFrame as the first positional argument, or metadata can be passed as name-value keyword arguments.
tsgroup.set_info(unit_type=["multi", "single", "single"])
print(tsgroup)
Index rate region unit_type
------- ------- -------- -----------
1 0.10584 pfc multi
2 0.21167 ofc single
3 0.31751 hpc single
Using dictionary-like keys (square brackets)#
Most metadata names can set as a dictionary-like key (i.e. using square brackets). The only exceptions are for IntervalSet
, where the names “start” and “end” are reserved for class properties.
tsgroup["depth"] = [0, 1, 2]
print(tsgroup)
Index rate region unit_type depth
------- ------- -------- ----------- -------
1 0.10584 pfc multi 0
2 0.21167 ofc single 1
3 0.31751 hpc single 2
Using attribute assignment#
If the metadata name is unique from other class attributes and methods, and it is formatted properly (i.e. only alpha-numeric characters and underscores), it can be set as an attribute (i.e. using a .
followed by the metadata name).
tsgroup.label=["MUA", "good", "good"]
print(tsgroup)
Index rate region unit_type depth label
------- ------- -------- ----------- ------- -------
1 0.10584 pfc multi 0 MUA
2 0.21167 ofc single 1 good
3 0.31751 hpc single 2 good
Accessing metadata#
Metadata is stored as a pandas DataFrame, which can be previewed using the metadata
attribute.
print(tsgroup.metadata)
rate region unit_type depth label
1 0.105837 pfc multi 0 MUA
2 0.211673 ofc single 1 good
3 0.317510 hpc single 2 good
Single metadata columns (or lists of columns) can be retrieved using the get_info()
class method:
print(tsgroup.get_info("region"))
1 pfc
2 ofc
3 hpc
Name: region, dtype: object
Similarly, metadata can be accessed using key indexing (i.e. square brakets)
print(tsgroup["region"])
1 pfc
2 ofc
3 hpc
Name: region, dtype: object
Note
Metadata names must be strings. Key indexing with an integer will produce different behavior based on object type.
Finally, metadata that can be set as an attribute can also be accessed as an attribute.
print(tsgroup.region)
1 pfc
2 ofc
3 hpc
Name: region, dtype: object
Overwriting metadata#
User-set metadata is mutable and can be overwritten.
print(tsgroup, "\n")
tsgroup.set_info(region=["A", "B", "C"])
print(tsgroup)
Index rate region unit_type depth label
------- ------- -------- ----------- ------- -------
1 0.10584 pfc multi 0 MUA
2 0.21167 ofc single 1 good
3 0.31751 hpc single 2 good
Index rate region unit_type depth label
------- ------- -------- ----------- ------- -------
1 0.10584 A multi 0 MUA
2 0.21167 B single 1 good
3 0.31751 C single 2 good
Allowed data types#
As long as the length of the metadata container matches the length of the object (number of columns for TsdFrame
and number of indices for IntervalSet
and TsGroup
), elements of the metadata can be any data type.
tsgroup.coords = [[1,0],[0,1],[1,1]]
print(tsgroup.coords)
1 [1, 0]
2 [0, 1]
3 [1, 1]
Name: coords, dtype: object
Using metadata to slice objects#
Metadata can be used to slice or filter objects based on metadata values.
print(tsgroup[tsgroup.label == "good"])
Index rate region unit_type depth label coords ...
------- ------- -------- ----------- ------- ------- -------- -----
2 0.21167 B single 1 good [0, 1] ...
3 0.31751 C single 2 good [1, 1] ...