Saving timestamps

Hi, I am just starting to use psychopy to present visual stimuli for during extracellular recordings in rats. We sync the recording with stimuli through a parallel port. However to ensure that the syncing is good I want to read out time information from psychopy i.e. stimuli onset time, stimuli duration etc.

I can not find this information saved in the output files (psydat, csv), do I have to manually retrieve timestamps in the code and save these post hoc in order to retrieve this information?

Is it possible to define time output in the workflow of the builder?

Did you look at the log file? If you’re writing code yourself you can create one using the code in this module:
http://www.psychopy.org/api/logging.html
When you create a log file of the approriate level, certain events within PsychoPy, like a stimulus changing its image, or position, or having its autoDraw value toggled, will show up automatically

There’s a demo on logging options too.

ok, so I should just extract each timestamp from the log file which have New trial in it’s line? In the builder we define the stimulus as .5 sec blank screen, and 2.5 sec with gratings, is this info saved somehow in the log also?

Yes it is. Maybe you could take a look?

Sorry not to be clear, I am looking at it but can not seem to find this info.

Sharing a screen shot where start time and duration is defined and a corresponding log file

6.4691 	EXP 	Created window1 = Window(allowGUI=False, allowStencil=False, autoLog=True, bitsMode=UNKNOWN, blendMode='avg', color=array([ 0.,  0.,  0.]), colorSpace='rgb', fullscr=UNKNOWN, gamma=None, lms=UNKNOWN, monitor=<psychopy.monitors.calibTools.Monitor object at 0x7f8d959c8a50>, multiSample=False, name='window1', numSamples=2, pos=[0, 0], screen=1, size=array([1920, 1080]), stereo=False, units='deg', useFBO=True, useRetina=False, viewOri=0.0, viewPos=None, viewScale=None, waitBlanking=True, winType='pyglet')
6.4692 	EXP 	window1: recordFrameIntervals = False
6.6343 	EXP 	window1: recordFrameIntervals = True
6.8182 	EXP 	window1: recordFrameIntervals = False
6.8791 	EXP 	Created grating = GratingStim(autoDraw=False, autoLog=True, color=array([ 1.,  1.,  1.]), colorSpace='rgb', contrast=1.0, depth=0.0, interpolate=True, mask=u'gauss', maskParams=None, name='grating', opacity=1.0, ori=1.0, phase=array([ 1.,  1.]), pos=array([ 0.5,  0.5]), rgbPedestal=array([ 0.,  0.,  0.]), sf=array([ 1.,  1.]), size=array([ 800.,  800.]), tex=u'sin', texRes=512, units='deg', win=Window(...))
6.8829 	EXP 	Imported Book1.xlsx as conditions, 8 conditions, 3 params
6.8832 	EXP 	Created sequence: random, trialTypes=8, nReps=5, seed=None
6.8834 	EXP 	New trial (rep=0, index=0): {u'tf': 1, u'sf': 0.080000000000000002, u'ori': 360}
6.8918 	EXP 	grating: sf = array([ 0.04,  0.  ])
7.4020 	EXP 	grating: autoDraw = True
9.3852 	EXP 	New trial (rep=0, index=1): {u'tf': 1, u'sf': 0.080000000000000002, u'ori': 180}
9.4009 	EXP 	grating: autoDraw = False
9.4009 	EXP 	grating: sf = array([ 0.04,  0.  ])
9.9176 	EXP 	grating: autoDraw = True
11.8851 	EXP 	New trial (rep=0, index=2): {u'tf': 11, u'sf': 0.080000000000000002, u'ori': 90}
11.9008 	EXP 	grating: autoDraw = False
11.9008 	EXP 	grating: sf = array([ 0.04,  0.  ])
12.4173 	EXP 	grating: autoDraw = True

Not sure how I can extract duration and shift from the log file here?

Correction, I can see how I get the values from the timestamps, but I guess I expected the parameters to be saved explicitly. I mean, if I want to assert that the timestamps follow the definition of the stimulus I would like to extract the parameters as set by the user.

The number on the left is the time in seconds. When autoDraw for your stimulus becomes true/false it means your stimulus started/stopped being presented. You’d need to subtract them to get duration

Log files don’t know your intention. They just steam the events that occur

If you want to save some specific time period within a trial then you’d need to do that with code (or a code component in builder) and save it to the csv file using trials.addData()

Ok, I get it. Thank you for your help.

In the future, may I suggest that you parse the complete parameter set to json or yaml or something similar such that it is easier to load and you always have all parameters belonging to one stimulus available. The log file is easy to parse for the user, however such a parser will be very sensitive to changes in your source code etc. Also, save output data (maybe even with parsed timestamp data from the log) with something different than pickle, as it requires psychopy to be installed, one example could be numpy savez.

I don’t understand what you mean by “parse the complete parameter set to json or yaml or something similar”. Do you mean we do this instead of log files? The log file format is a pretty standard format. It’s just a tab-delimitted file that is readably by anything.

But that isn’t what we usually expect people to use for data analysis. The main data file format that we expect people to use for analysis is the csv file. That’s why I suggested using trials.addData() so that you won’t need to bother with log files or pickled data.

I meant that it would be nice to have all parameters that you set in the GUI available in some file format, but now I realize that you can find these parameters in the .psyexp file which is in xml, that’s exactly what I wanted :slight_smile:

Absolutely, I recognize your answer here. However, I would say timestamps are quite basic and should be saved by default in the output file (csv). One problem how I see it with trials.addData() in our lab at least is that most users want to set the stimulation paradigm with the GUI. Therefore if our parser of the csv file expects time data added by trials.addData() we would have to modify the output script every time someone is changing the stimulation paradigm in the GUI. I thus ended up writing a parser for the log file to retrieve time data.

1 Like

It sounds like you need to learn about Code Components as well. You should very rarely (if ever) need to alter a script compiled from the Builder. Always add snippets of code in using Code Components instead.