I have written code which presents movies using movieStim3 and a slider scale using Slider simultaneously. The code currently stores and writes out to a file the position of the marker on the scale every second as well as the timestamp. To do this, I start a clock at the start of the video and store a timestamp every time a rating is stored. However, I think it would be better to timestamp each rating with the current frame. Does anyone know of a way to do this?
Here is my code currently:
from psychopy import visual
from psychopy import gui, data, core,event
import csv
import time
from time import localtime, strftime, gmtime
from datetime import datetime
import os.path
# Kill switch for Psychopy3
#event.globalKeys.clear() # clear global keys
esc_key= 'escape' # create global key for escape
# define function to quit programme
def quit():
print ('User exited')
win.close()
core.quit()
# call globalKeys so that whenever user presses escape, quit function called
event.globalKeys.add(key=esc_key, func=quit)
# User should set cwd to the experiment directory
os.chdir('\\\\storage.its.york.ac.uk\\pshome\\blam500\\Downloads\\movie_study_0.5')
# User should set directory for output files to be stored
save_path= '\\\\storage.its.york.ac.uk\\pshome\\blam500\\Downloads\\movie_study_0.5\\output'
# instructions for the task can be updated here
instructions = """You will be presented with several videos.
\nThese videos will contain dangerous behaviour, strong language, disturbing images,threat and violence.If you find these types of videos distressing ,please do not participate and let the experimenter know.
\nIf at any point, you become distressed and would like to stop the task, please inform the experimenter.
You will not be penalised for withdrawing from the study.
\nPlease continuously rate how frightening you feel the video is moment-to-moment using the wheel of the mouse.
\nPress Enter to begin."""
# Create a dictionary to store information from the dialogue box
inputbox = {'expdate': datetime.now().strftime('%Y%m%d_%H%M'),'part_number':'','videoCondition':''}
# Create dialogue box
# user enters participant number + video condition (i.e. the Header of the column of video lists in the film csvFile)
dlg=gui.DlgFromDict(inputbox, title = 'Input participation info',
fixed='expdate',
order=['expdate', 'part_number','videoCondition'])
# If the user doesn't press ok, the programme will quit and inform user.
if not dlg.OK:
print ("User exited")
core.quit()
# Store participant number, video condition and experiment date provided by user as variables for later use
part_number = inputbox['part_number']
videoCondition = inputbox['videoCondition']
expdate = inputbox['expdate']
# create filename based on user input
filename = '{}_{}_{}_{}.csv'.format(part_number, expdate, videoCondition,'continuous')
# update filename to include absolute path so that it is stored in output directory
completeName = os.path.join(save_path, filename)
# open file for writing
outputfile = open(completeName, "w")
# Create list of headers for output csv file
fieldnames = ['videoName','Timestamp', 'Rating']
# create variable which calls DictWriter to write to outputfile and specifies fieldnames
writer = csv.DictWriter(outputfile, fieldnames)
# writes headers using fieldnames as specified above when creating writer variable
writer.writeheader()
#function to present break and end screen
def break_end(video_name, participant_number, last=0):
# Present break screen at the end of each set of questions
if last==0:
stim.setText("""You are welcome to take a break if you need to.
\nPress enter when you are ready to continue.""")
stim.draw()
win.flip()
# Wait for user to press Return to continue
key = event.waitKeys(keyList=(['return']), timeStamped = True)
else:
# Presents end screen at the end of task
stim.setText("""You have reached the end of the experiment.
\nPlease let the experimenter know you have finished.
\nThank you for your participation.""")
stim.draw()
win.flip()
# Waits for user to press escape to exit experiment
key = event.waitKeys(keyList=(['return']), timeStamped = True)
# Create white window for stimuli to be presented on throughout task
win = visual.Window(size=[1024, 768], color=[1,1,1,], monitor="testMonitor", fullscr= True, allowGUI = False)
# Create text stimuli to be updated for start screen, break and end
stim = visual.TextStim(win, "", color = [-1,-1,-1], wrapWidth = 1300, units = "pix", height=40)
# Use trialhandler to sequentially present films listed in filmlist csv file
filmDict = data.TrialHandler(nReps = 1, method = 'sequential', trialList = data.importConditions('references\\filmList.csv'), name = 'filmList')
# Create sliding scale to take continuous rating of uncertainty while movie plays
slidingscale = visual.Slider(win, ticks = [0,100], labels = ['certain', 'uncertain'], pos = (0.0, -0.7), granularity = 0)
# Name mouse to be able to use for continuous rating below
mouse = event.Mouse()
# Update text to include instructions for task
stim.setText(instructions)
# draw text stimuli
stim.draw()
# flip window to show text
win.flip()
# Wait for user to press Return to continue
key = event.waitKeys(keyList=(['return']), timeStamped = True)
# Loop through each film stored in filmDict created above using trialhandler
for film in filmDict:
# Store video name in thisRunDict to write to outputfile
thisRunDict= {'videoName': film[videoCondition] }
# present movie using moviestim3
mov = visual.MovieStim3 (win, film[videoCondition], size=(640, 500), flipVert=False, flipHoriz=False, loop=False) #TO DO: fix size of video
# create a clock at the start of movie presentation
clock = core.Clock()
clock.reset()
# set position of marker to middle of slider at the start of each video
slidingscale.markerPos = 50
# create variable to use in loop to record rating every n seconds
rtscaleframe = 0
# While moving is playing, present slidingscale and record marker position and timestamp in outputfile
while mov.status != visual.FINISHED:
slidingscale.markerPos += mouse.getWheelRel()[1]
slidingscale.draw()
mov.draw()
win.flip()
# Run every 1 sec
if rtscaleframe % 60
== 0:
rating = slidingscale.markerPos # store marker position
thisRunDict['Rating'] = str(rating) # store rating in thisRunDict to write to outputfile
thisRunDict['Timestamp'] = str(clock.getTime()) # store Timestamp of video to write to outputfile
# write responses and timings stored in thisRunDict to outputfile
writer.writerows([thisRunDict])
rtscaleframe += 1 # needed to collect rating every 1 sec
# If statement to either present break screen or end screen
nextTrial = filmDict.getFutureTrial(n=1) #fixes error for end screen
if nextTrial is None or nextTrial[videoCondition] != None:
break_end(film[videoCondition], part_number)
else:
break_end(film[videoCondition], part_number,1)
outputfile.flush()