-
Notifications
You must be signed in to change notification settings - Fork 8
/
write_ttls_events.py
178 lines (156 loc) · 7.57 KB
/
write_ttls_events.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
"""
Example script that demonstrates how to write an EventsTable with a CategoricalVectorData and associated MeaningsTable
to store raw TTL pulses received by the acquisition system and processed stimulus presentation events.
"""
from datetime import datetime
from pynwb import NWBHDF5IO
from ndx_events import (
EventsTable,
CategoricalVectorData,
MeaningsTable,
NdxEventsNWBFile,
)
nwbfile = NdxEventsNWBFile(
session_description="session description",
identifier="cool_experiment_001",
session_start_time=datetime.now().astimezone(),
)
# In this experiment, TTL pulses were sent by the stimulus computer
# to signal important time markers during the experiment/trial,
# when the stimulus was placed on the screen and removed from the screen,
# when the question appeared, and the responses of the subject.
# ref: https://www.nature.com/articles/s41597-020-0415-9, DANDI:000004
# We will first create an EventsTable to store the raw TTL pulses received by the acquisition system.
# Storing the raw TTL pulses is not necessary, but it can be useful for debugging and understanding the experiment.
# The data curator could
# Before doing so, we will create a CategoricalVectorData column for the possible integer values for the TTL pulse
# and associate it with a MeaningsTable that describes the meaning of each value.
pulse_value_meanings_table = MeaningsTable(
name="pulse_value_meanings", description="The meanings of each integer value for a TTL pulse."
)
pulse_value_meanings_table.add_row(value=55, meaning="Start of experiment")
pulse_value_meanings_table.add_row(value=1, meaning="Stimulus onset")
pulse_value_meanings_table.add_row(value=2, meaning="Stimulus offset")
pulse_value_meanings_table.add_row(value=3, meaning="Question screen onset")
yes_animal_response_description = (
"During the learning phase, subjects are instructed to respond to the following "
"question: 'Is this an animal?' in each trial. The response is 'Yes, this is an animal'."
)
no_animal_response_description = (
"During the learning phase, subjects are instructed to respond to the following "
"question: 'Is this an animal?' in each trial. The response is 'No, this is not an animal'."
)
pulse_value_meanings_table.add_row(value=20, meaning=yes_animal_response_description)
pulse_value_meanings_table.add_row(value=21, meaning=no_animal_response_description)
new_confident_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'New, confident'."
)
new_probably_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'New, probably'."
)
new_guess_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'New, guess'."
)
old_guess_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'Old, guess'."
)
old_probably_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'Old, probably'."
)
old_confident_response_description = (
"During the recognition phase, subjects are instructed to respond to the following "
"question: 'Have you seen this image before?' in each trial. The response is 'Old, confident'."
)
pulse_value_meanings_table.add_row(value=31, meaning=new_confident_response_description)
pulse_value_meanings_table.add_row(value=32, meaning=new_probably_response_description)
pulse_value_meanings_table.add_row(value=33, meaning=new_guess_response_description)
pulse_value_meanings_table.add_row(value=34, meaning=old_guess_response_description)
pulse_value_meanings_table.add_row(value=35, meaning=old_probably_response_description)
pulse_value_meanings_table.add_row(value=36, meaning=old_confident_response_description)
pulse_value_meanings_table.add_row(value=6, meaning="End of trial")
pulse_value_meanings_table.add_row(value=66, meaning="End of experiment")
pulse_value_column = CategoricalVectorData(
name="pulse_value", description="Integer value of the TTL pulse", meanings=pulse_value_meanings_table
)
ttl_events_table = EventsTable(
name="ttl_events",
description="TTL events",
columns=[pulse_value_column],
meanings_tables=[pulse_value_meanings_table],
)
ttl_events_table.add_row(
timestamp=6820.092244,
pulse_value=55,
)
ttl_events_table.add_row(
timestamp=6821.208244,
pulse_value=1,
)
ttl_events_table.add_row(
timestamp=6822.210644,
pulse_value=2,
)
ttl_events_table.add_row(
timestamp=6822.711364,
pulse_value=3,
)
ttl_events_table.add_row(
timestamp=6825.934244,
pulse_value=31,
)
ttl_events_table.timestamp.resolution = 1 / 50000.0 # specify the resolution of the timestamps (optional)
# The data curator may want to create an EventsTable to store more processed information than the TTLs table
# e.g., converting stimulus onset and offset into a single stimulus event with metadata.
# This may be redundant with information in the trials table if the task is
# structured into trials.
stimulus_category_meanings_table = MeaningsTable(
name="stimulus_category_meanings", description="The meanings of each stimulus category"
)
stimulus_category_meanings_table.add_row(value="smallAnimal", meaning="An image of a small animal was presented.")
stimulus_category_meanings_table.add_row(value="largeAnimal", meaning="An image of a large animal was presented.")
stimulus_category_column = CategoricalVectorData(
name="stimulus_category", description="The category of the stimulus", meanings=stimulus_category_meanings_table
)
stimulus_presentation_table = EventsTable(
name="stimulus_presentations",
description="Metadata about stimulus presentations",
columns=[stimulus_category_column],
meanings_tables=[stimulus_category_meanings_table],
)
stimulus_presentation_table.add_column(
name="stimulus_image_index", description="Frame index of the stimulus image in the StimulusPresentation object"
) # this is an integer.
# One could make this a CategoricalVectorData column if there are a limited number of stimulus images and one
# wants to describe each one
stimulus_presentation_table.add_row(
timestamp=6821.208244,
duration=1.0024, # this comes from the stimulus onset and offset TTLs
stimulus_category="smallAnimal",
stimulus_image_index=0,
)
stimulus_presentation_table.add_row(
timestamp=6825.208244,
duration=0.99484,
stimulus_category="phones",
stimulus_image_index=1,
)
stimulus_presentation_table.timestamp.resolution = 1 / 50000.0 # specify the resolution of the timestamps (optional)
stimulus_presentation_table.duration.resolution = 1 / 50000.0 # specify the resolution of the durations (optional)
nwbfile.add_events_table(ttl_events_table)
nwbfile.add_events_table(stimulus_presentation_table)
print(nwbfile.get_all_events())
# Write NWB file.
filename = "test_events.nwb"
with NWBHDF5IO(filename, "w") as io:
io.write(nwbfile)
# Read NWB file and check its contents.
with NWBHDF5IO(filename, "r", load_namespaces=True) as io:
read_nwbfile = io.read()
print(read_nwbfile)
print(read_nwbfile.events["ttl_events"].to_dataframe())
print(read_nwbfile.events["stimulus_presentations"].to_dataframe())