Hi Guy,
I took a look at the code you shared (spike_tools/mwk_ultra.py
).
It looks like the assignment of times to each stimulus presentation is handled well. Both stimulus_presented_df['time']
and correct_fixation_df['time']
are set to the value of photodiode_on
. This variable contains the times (on the Intan clock) of the peaks in the photodiode signal, which is the most robust measure of actual stimulus presentation time.
Also, most of the usage of stimulus_presented
is fine, since it’s just determining a general ordering of stimulus presentations (i.e. the order of a given stimulus in its trial) and isn’t concerned with specific stimulus identity or the real-world time of the presentation.
To get the relevant #stimDisplayUpdate
(SDU) events for specific stimulus identification, you need to extract events where an image was presented. Here’s some Python code to do this:
with MWKFile(filename) as fp:
sdu_events = []
file_paths = []
file_hashes = []
for e in fp.get_events_iter(codes=['#stimDisplayUpdate']):
for d in e.data:
if d.get('type') == 'image':
sdu_events.append(e)
file_paths.append(d['filename'])
file_hashes.append(d['file_hash'])
break
The number of SDU events extracted this way should equal the number of stimulus_presented
events whose value is not -1. More specifically, borrowing some code from the section “Extract stimulus presentation order and fixation information”:
stimulus_presented_df = data[data.name == 'stimulus_presented'].reset_index(drop=True)
correct_fixation_df = data[data.name == 'correct_fixation'].reset_index(drop=True)
stimulus_presented_df = stimulus_presented_df[:len(correct_fixation_df)] # If you have one extra stimulus event but not fixation, use this
assert len(stimulus_presented_df) == len(correct_fixation_df)
# Drop `empty` data (i.e. -1) before the experiment actually began and after it had already ended
correct_fixation_df = correct_fixation_df[stimulus_presented_df.data != -1].reset_index(drop=True)
stimulus_presented_df = stimulus_presented_df[stimulus_presented_df.data != -1].reset_index(drop=True)
sdu_events = sdu_events[:len(correct_fixation_df)]
assert len(sdu_events) == len(stimulus_presented_df)
One area where I think it would be better to use SDU instead of stimulus_presented
is in the “Get eye data” section. Since the point there is to find the eye data coincident with the stimulus presentation, SDU’s more accurate timestamp makes it the better choice.
Finally, in the “Save output” section, I think it would be easiest to save file_paths
and file_hashes
, rather than the raw SDU events. There’s really no reason to save stimulus_presented
, except perhaps as a redundant means of image identification.
I hope that helps!
Cheers,
Chris