Demo entry 6363391

Process PsychoPy Log Files

   

Submitted by anonymous on May 13, 2017 at 06:52
Language: Python. Code size: 7.2 kB.

# Used to process PsychoPy logfiles to generate onset times, durations, and accuracy. Firat Soylu 2017 - University of Alabama
import csv
import re
import os
import fnmatch

combLogf = [] #will include all logfiles


for filename in os.listdir("log-files"): #takes all logfiles calculates corrected time values, inserts subject info and combines all logfiles
	logFile = list(csv.reader(open('log-files/' + filename,'rU'), delimiter='\t', dialect=csv.excel_tab))
	i = 0
	expBeginRow = 'empty'
	expBeginTime = 'empty'
	for row in logFile: #Find the point when experiment starts
		if row[1]=='DATA ' and row[2].startswith('Keypress: quoteleft') and expBeginTime == 'empty':
			expBeginTime=row[0]
			# print (expBeginTime)
			expBeginRow = i
		i = i + 1

	for k in range(expBeginRow): #delete everything above the point when experiment starts
		logFile.pop(0)

	for row in logFile:
		subtractedTime = float(row[0]) - float(expBeginTime) #this is the time value that will be used for onsets. 
		row.insert(1,subtractedTime)
		row.insert(0,filename[0:2])

	#print(logFile[0])

	for row in logFile:
		combLogf.append(row)

outputFile = open('allLogfiles.output','wt')
#outputFile = open('processed.output','wt')
writer = csv.writer(outputFile, delimiter="\t", dialect='excel')
for row in combLogf:
	writer.writerow(row)


# Now start going through each row to get the 'Subject','Condition','Stimulus','State','Response','Accuracy','Duration' info
i = 0
dataSheet = []
dataSheet.append(['Subject','Diff','Oper','Prob','probAns','corrResp','Keyp1','Response','Accuracy','onset1','onset2','rt1','rt2'])

for row in combLogf:
	keyp1 = 'empty'
	response = 'empty'
	accuracy = 'na'
	rt1 = 'empty'
	rt2 = 'empty'
	onset1 = 'empty'
	onset2 = 'empty'

	if row[4].startswith('New trial (rep=') and row[4].find('probAns') != -1:
		rowData = row[4].split(',')
		#print(rowData)
		subj = row[0]
		#diff = rowData[3].split('\'')[1] #the logfiles for the fingersense study marks all trials as easy addition. if it wasn't so this would have worked.
		#oper = rowData[4].split('\'')[1] #the logfiles for the fingersense study marks all trials as easy addition. if it wasn't so this would have worked.
		prob = rowData[5].split('\'')[3]
		probAns  =  rowData[2].split('\'')[3]
		corrResp = rowData[1].split('\'')[2][2]


		if prob.find('-') != -1:
			oper = "subtraction"
			if int(prob.split('-')[0]) < 6: #for subtraction if the first operand is bigger than 5 than hard, otherwise easy
				diff = 'easy'
			elif int(prob.split('-')[0]) > 5:
				diff = 'hard'
			else:
				print("error: prob info")
				break

		elif prob.find('+') != -1:
			oper = "addition"
			if int(probAns.split('=')[1]) < 11: #for addition if the sum is less than 11 than easy, otherwise hard
				diff = 'easy'
			elif int(probAns.split('=')[1]) > 10:
				diff = 'hard'
			else:
				print("error: probAns info")
				break
		else:
			print("error: no operation info")
			break

		
		k = i + 1 #start from the beginning of the current trial and go down to find the stimuli and key presses	
		while not combLogf[k][4].startswith('New trial ('):
			if combLogf[k][4].startswith('text: text = u'):
				if onset1 != 'empty':
					print ('error onset1 already set')
					break
				onset1 = round(combLogf[k][2],4)
			elif combLogf[k][4].startswith('text_2: text = u'):
				if onset2 != 'empty':
					print ('error onset2 already set')
					break
				onset2 = round(combLogf[k][2],4)


			if combLogf[k][4].startswith('Keypress:') and keyp1 == 'empty' and onset1 != 'empty' and onset2 == 'empty' and rt1 == 'empty' and combLogf[k][4].find('quoteleft') == -1:
					keyp1 = combLogf[k][4].split(':')[1][1:]
					rt1 = round(combLogf[k][2] - onset1,4)
			elif combLogf[k][4].startswith('Keypress:') and onset2 != 'empty' and rt2 == 'empty'and combLogf[k][4].find('quoteleft') == -1:
					response = combLogf[k][4].split(':')[1][1:]
					rt2 = round(combLogf[k][2] - onset2,4)
			k = k + 1


		if keyp1 == 'empty' and rt1 == 'empty': #this means the participant did not click on a button to skip to the response, but responded to validation
			keyp1 = "skipped" #did the participant click on a button to skip the problem? 
			rt1 = round(onset2 - onset1, 4)

		if keyp1 in ['1','4']:
			keyp1 = '2'
		elif keyp1 in ['6','8']:
			keyp1 = '7'

		if response in ['1','4']:
			response = '2'
		elif response in ['6','8']:
			response = '7'


		if response != 'empty': #calculate accuracy
			if response == corrResp:
				accuracy = 1
			else:
				accuracy = 0
		else: #no response
			response = "noResp"
			accuracy = " "
			rt2 = " "


		# print(subj,diff,oper,prob,probAns,corrResp,keyp1,response,accuracy,onset1,onset2,rt1,rt2)
		if keyp1 not in ['escape','lshift','space'] and response not in ['escape','lshift','space']: #the question terminates at the end of the block
			dataSheet.append([subj,diff,oper,prob,probAns,corrResp,keyp1,response,accuracy,onset1,onset2,rt1,rt2])

	i = i + 1;

outputFile = open('processedData.output','wt')
writer = csv.writer(outputFile, delimiter="\t", dialect='excel')
for row in dataSheet:
	writer.writerow(row)



#This part creates the vector files (.txt later to be converted to .mat) to input the onset and duration information for all conditions (multiple conditions in Level1)
#################

name_dic1 = dict(zip(('add','sub','fix'),(0,1,2,3,4)))
name_dic2 = dict(zip((0,1,2,3,4),('add','sub','fix')))

fixations = list(csv.reader(open('fixations.txt','rU'), delimiter='\t', dialect=csv.excel_tab)) #fixation values are stored in fixations.txt

def condmatch(trialstring):
	condno = name_dic1.get(trialstring)
	return condno

def writetrial(defj, defoutputf, deffilename): #this is used to create the output file, later to be used by SPM
    global name_dic2
    defname = name_dic2.get(defj)
    outputf.write('names{'+str(defj+1)+'} = \'' + defname+'\'; \nonsets{'+str(defj+1)+'} = ['+ " ".join(onsets[defj])+']; \
    \ndurations{'+str(defj+1)+'} = [' + " ".join(durations[defj]) + '];\n\n')

onsets = [[],[],[]]
durations = [[],[],[]]
skippers = (2, 6, 8, 11, 12, 23, 24, 25, 30, 31, 33, 35) #these subjects did not click to pass the question, their durations will be set to 4sec

dataSheet.pop(0) #get rid of the labels on the top of the sheet
i = 0
while i < len(dataSheet):
	row = dataSheet[i] #so that i don't have to write dataSheet[i] everytime 
	subj = row[0]

	if row[8] == 1: #if the repsonse is correct, otherwise don't include 
		cond = row[2][0:3]  #name of operation
		print(cond)
		
		onsets[condmatch(cond)].append(str(row[9]))
		durations[condmatch(cond)].append(str(row[11]))
		

	if i==0 or (i!=0 and i != len(dataSheet) - 1 and subj!=dataSheet[i+1][0]) or i == len(dataSheet) - 1: #end of current subject. get fixation value, write stuff in the file & continue with the new subj
		for fixRow in fixations:
			if fixRow[0] == subj:
				onsets[2] = [fixRow[1]]
				durations[2] = [fixRow[2]]

		outputf = open('vector_files/m/vector_'+subj+'.m','w')
		outputf.write('names = cell(1,3); \nonsets = cell(1,3); \ndurations = cell(1,3);\n\n')

		for j in range(0,3):
	 	   	writetrial(j, outputf, filename)
		outputf.close()

		onsets = [[],[],[]]
		durations = [[],[],[]]

	i += 1

This snippet took 0.02 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).