from psychopy import visual from psychopy_ext import exp from collections import OrderedDict import scripts.computer as computer PATHS = exp.set_paths('trivial', computer) class Exp1(exp.Experiment): """ Instructions (in reST format) ============================= Press **spacebar** to start. **Hit 'j'** to advance to the next trial, *Left-Shift + Esc* to exit. """ def __init__(self, name='exp', info=OrderedDict([('subjid', 'quick_'), ('session', 1), ]), rp=None, actions='run' ): super(Exp1, self).__init__(name=name, info=info, rp=rp, actions=actions, paths=PATHS, computer=computer) # user-defined parameters self.ntrials = 8 self.stimsize = 2 # in deg def create_stimuli(self): """Define your stimuli here, store them in self.s """ self.create_fixation() self.s = {} self.s['fix']= self.fixation self.s['stim'] = visual.GratingStim(self.win, mask='gauss', size=self.stimsize) def create_trial(self): """Define trial composition """ self.trial = [exp.Event(self, dur=.200, # in seconds display=[self.s['stim'], self.s['fix']], func=self.idle_event), exp.Event(self, dur=0, display=self.s['fix'], func=self.wait_until_response) ] def create_exp_plan(self): """Put together trials """ exp_plan = [] for trialno in range(self.ntrials): exp_plan.append(OrderedDict([ ('trialno', trialno), ('onset', ''), # empty ones will be filled up ('dur', ''), # during runtime ('corr_resp', 1), ('subj_resp', ''), ('accuracy', ''), ('rt', ''), ])) self.exp_plan = exp_plan if __name__ == "__main__": Exp1(rp={'no_output':True, 'debug':True}).run() def myfunc(): print 'stuff' class Output(object): def __init__(self): print 'init' def run(self): print 'run' class Output(object): def __init__(self): print 'init' def run(self): print 'run' Output() class Output(object): def __init__(self): print 'init' def go(self): print 'go' def run(self): print 'run' class Child(Output): def run(self): print 'child' Child().run() import numpy.random as rnd # for random number generators from psychopy import visual from psychopy_ext import exp from collections import OrderedDict import computer PATHS = exp.set_paths('.', computer) # '.' means that the root directory for saving outout is here PATHS['images'] = 'images' class ChangeDet(exp.Experiment): """ Change Detection Experiment =========================== In this experiment you will see photographs flickering with a tiny detail in them changing. Your task is to detect where the change is occuring. To make it harder, there are bubbles randomly covering the part of the photos. Hit **spacebar to begin**. When you detect a change, hit **spacebar** again. """ def __init__(self, name='exp', info=OrderedDict([('exp_name', 'Change Detection'), ('subjid', 'cd_'), ('gender', ('male', 'female')), ('age', 18), ('left-handed', False) ]), rp=None, actions='run', order='sequential' ): super(ChangeDet, self).__init__(name=name, info=info, rp=rp, actions=actions, paths=PATHS, computer=computer) # user-defined parameters self.imlist = ['1','2','3','4','5','6'] # image names without the suffixes self.asfx = 'a.jpg' # suffix for the first image self.bsfx = 'b.jpg' # suffix for the second image self.scrsize = (900, 600) # screen size in px self.stimsize = (9, 6) # stimulus size in degrees visual angle self.timelimit = 30 # sec self.n_bubbles = 40 self.changetime = .500 #sec self.computer.valid_responses = {'space': 1} self.trial_instr = ('Press spacebar to start the trial.\n\n' 'Hit spacebar again when you detect a change.') def create_win(self, *args, **kwargs): super(ChangeDet, self).create_win(size=self.scrsize, units='deg', *args, **kwargs) def create_stimuli(self): """Define your stimuli here, store them in self.s """ self.s = {} self.s['bitmap1'] = visual.ImageStim(self.win, size=self.stimsize) self.s['bitmap2'] = visual.ImageStim(self.win, size=self.stimsize) self.s['bubble'] = visual.Circle(self.win, fillColor='black', lineColor='black') def create_trial(self): """Define trial composition """ self.trial = [exp.Event(self, dur=self.timelimit, # in seconds display=[self.s['bitmap1'], self.s['bitmap2'], self.s['bubble']], func=self.show_stim) ] def create_exp_plan(self): """Put together trials """ # Check if all images exist for im in self.imlist: if (not os.path.exists(os.path.join(self.paths['images'], im+self.asfx)) or not os.path.exists(os.path.join(self.paths['images'], im+self.bsfx))): raise Exception('Image files not found in image folder: ' + str(im)) # Randomize the image order rnd.shuffle(self.imlist) # Create the orientations list: half upright, half inverted orilist = [0,1]*(len(self.imlist)/2) # Randomize the orientation order rnd.shuffle(orilist) exp_plan = [] for im, ori in zip(self.imlist, orilist): exp_plan.append(OrderedDict([ ('im', im), ('ori', ori), ('onset', ''), # empty ones will be filled up ('dur', ''), # during runtime ('corr_resp', 1), ('subj_resp', ''), ('accuracy', ''), ('rt', ''), ])) self.exp_plan = exp_plan def before_trial(self): """Set up stimuli prior to a trial """ im_fname = os.path.join(self.paths['images'], self.this_trial['im']) self.s['bitmap1'].setImage(im_fname + self.asfx) self.s['bitmap1'].setOri(self.this_trial['ori']) self.s['bitmap2'].setImage(im_fname + self.bsfx) self.s['bitmap2'].setOri(self.this_trial['ori']) self.bitmap = self.s['bitmap1'] if self.thisTrialN > 0: # no need for instructions for the first trial self.show_text(text=self.trial_instr, wait=0) def show_stim(self, *args, **kwargs): """Control stimuli during the trial """ # Empty the keypresses list event.clearEvents() keys = [] change_clock = core.Clock() # Start the trial # Stop trial if spacebar or escape has been pressed, or if 30s have passed while len(keys) == 0 and self.trial_clock.getTime() < self.this_event.dur: # Switch the image if self.bitmap == self.s['bitmap1']: self.bitmap = self.s['bitmap2'] else: self.bitmap = self.s['bitmap1'] self.bitmap.draw() # Draw bubbles of increasing radius at random positions for radius in range(self.n_bubbles): self.s['bubble'].setRadius(radius/100.) self.s['bubble'].setPos(((rnd.random()-.5) * self.stimsize[0], (rnd.random()-.5) * self.stimsize[1] )) self.s['bubble'].draw() # Show the new screen we've drawn self.win.flip() # For the duration of 'changetime', # Listen for a spacebar or escape press change_clock.reset() while change_clock.getTime() <= self.changetime: keys = self.last_keypress(keyList=self.computer.valid_responses.keys(), timeStamped=self.trial_clock) if len(keys) > 0: print keys break return keys %load scripts/changedet.py import os import numpy.random as rnd # for random number generators from psychopy import visual, core, event from psychopy_ext import exp from collections import OrderedDict import scripts.computer as computer PATHS = exp.set_paths('change_detection', computer) PATHS['images'] = '../Part2/images/' class ChangeDet(exp.Experiment): """ Change Detection Experiment =========================== In this experiment you will see photographs flickering with a tiny detail in them changing. Your task is to detect where the change is occuring. To make it harder, there are bubbles randomly covering the part of the photos. Hit **spacebar to begin**. When you detect a change, hit **spacebar** again. """ def __init__(self, name='exp', info=OrderedDict([('exp_name', 'Change Detection'), ('subjid', 'cd_'), ('gender', ('male', 'female')), ('age', 18), ('left-handed', False) ]), rp=None, actions='run', order='sequential' ): super(ChangeDet, self).__init__(name=name, info=info, rp=rp, actions=actions, paths=PATHS, computer=computer) # user-defined parameters self.imlist = ['1','2','3','4','5','6'] # image names without the suffixes self.asfx = 'a.jpg' # suffix for the first image self.bsfx = 'b.jpg' # suffix for the second image self.scrsize = (900, 600) # screen size in px self.stimsize = (9, 6) # stimulus size in degrees visual angle self.timelimit = 30 # sec self.n_bubbles = 40 self.changetime = .500 #sec self.computer.valid_responses = {'space': 1} self.trial_instr = ('Press spacebar to start the trial.\n\n' 'Hit spacebar again when you detect a change.') def create_win(self, *args, **kwargs): super(ChangeDet, self).create_win(size=self.scrsize, units='deg', *args, **kwargs) def create_stimuli(self): """Define your stimuli here, store them in self.s """ self.s = {} self.s['bitmap1'] = visual.ImageStim(self.win, size=self.stimsize) self.s['bitmap2'] = visual.ImageStim(self.win, size=self.stimsize) self.s['bubble'] = visual.Circle(self.win, fillColor='black', lineColor='black') def create_trial(self): """Define trial composition """ self.trial = [exp.Event(self, dur=self.timelimit, # in seconds display=[self.s['bitmap1'], self.s['bitmap2']], func=self.show_stim) ] def create_exp_plan(self): """Put together trials """ # Check if all images exist for im in self.imlist: if (not os.path.exists(os.path.join(self.paths['images'], im+self.asfx)) or not os.path.exists(os.path.join(self.paths['images'], im+self.bsfx))): raise Exception('Image files not found in image folder: ' + str(im)) # Randomize the image order rnd.shuffle(self.imlist) # Create the orientations list: half upright, half inverted orilist = [0,180]*(len(self.imlist)/2) # Randomize the orientation order rnd.shuffle(orilist) exp_plan = [] for trialno, (im, ori) in enumerate(zip(self.imlist, orilist)): exp_plan.append(OrderedDict([ ('im', im), ('ori', ori), ('onset', ''), # empty ones will be filled up ('dur', ''), # during runtime ('corr_resp', 1), ('subj_resp', ''), ('accuracy', ''), ('rt', ''), ])) self.exp_plan = exp_plan def before_trial(self): """Set up stimuli prior to a trial """ im_fname = os.path.join(self.paths['images'], self.this_trial['im']) self.s['bitmap1'].setImage(im_fname + self.asfx) self.s['bitmap1'].setOri(self.this_trial['ori']) self.s['bitmap2'].setImage(im_fname + self.bsfx) self.s['bitmap2'].setOri(self.this_trial['ori']) self.bitmap = self.s['bitmap1'] if self.thisTrialN > 0: # no need for instructions for the first trial self.show_text(text=self.trial_instr, wait=0) def show_stim(self, *args, **kwargs): """Control stimuli during the trial """ # Empty the keypresses list event.clearEvents() keys = [] change_clock = core.Clock() # Start the trial # Stop trial if spacebar or escape has been pressed, or if 30s have passed while len(keys) == 0 and self.trial_clock.getTime() < self.this_event.dur: # Switch the image if self.bitmap == self.s['bitmap1']: self.bitmap = self.s['bitmap2'] else: self.bitmap = self.s['bitmap1'] self.bitmap.draw() # Draw bubbles of increasing radius at random positions for radius in range(self.n_bubbles): self.s['bubble'].setRadius(radius/100.) self.s['bubble'].setPos(((rnd.random()-.5) * self.stimsize[0], (rnd.random()-.5) * self.stimsize[1] )) self.s['bubble'].draw() # Show the new screen we've drawn self.win.flip() # For the duration of 'changetime', # Listen for a spacebar or escape press change_clock.reset() while change_clock.getTime() <= self.changetime: keys = self.last_keypress(keyList=self.computer.valid_responses.keys(), timeStamped=self.trial_clock) if len(keys) > 0: print keys break return keys if __name__ == "__main__": ChangeDet(rp={'no_output':True, 'debug':True}).run() import pandas # get data from de-Wit, Kubilius et al. (2013); will take some time path = 'https://bitbucket.org/qbilius/df/raw/aed0ac3eba09d1d688e87816069f5b05e127519e/data/controls2_%02d.csv' data = [pandas.read_csv(path % i) for i in range(1,13)] df = pandas.concat(data, ignore_index=True) df from psychopy_ext import stats rt = stats.aggregate(df, values='RT', cols='context') rt df = df[df.context != 'Fixation'] rt = stats.aggregate(df, values='RT', cols='context') rt rt = stats.aggregate(df, values='RT', cols='context', yerr='subjID') rt rt = stats.aggregate(df, values='RT', cols=['pos', 'context']) rt acc = stats.accuracy(df, values='accuracy', cols='context', yerr='subjID', correct='Correct', incorrect='Incorrect') acc %matplotlib inline from psychopy_ext import plot plt = plot.Plot() plt.plot(acc, kind='bar') plt.show() plt = plot.Plot() plt.plot(acc, kind='bean') plt.show() rt = stats.aggregate(df, values='RT', cols='context', subplots='pos', yerr='subjID') plt = plot.Plot() plt.plot(rt, kind='bean') plt.show() class TwoTasks(exp.Experiment): def __init__(self, ...): self.tasks = [Train, Test] class Train(exp.Task): def __init__(self, parent): ... class Test(exp.Task): def __init__(self, parent): ... %load run.py #! /usr/bin/env python from psychopy_ext import ui __author__ = "Jonas Kubilius" __version__ = "0.1" exp_choices = [ ui.Choices('scripts.trivial', name='Quick demo'), ui.Choices('scripts.changedet', name='Change Detection Experiment') ] # bring up the graphic user interface or interpret command line inputs # usually you can skip the size parameter ui.Control(exp_choices, title='Demo Project', size=(560,550)) %run run.py %run run.py changedet exp run --subjid subj_01 --debug --n %run run.py changedet exp run --d --n --unittest # first get the data from de-Wit, Kubilius et al., (2013) again import pandas path = 'https://bitbucket.org/qbilius/df/raw/aed0ac3eba09d1d688e87816069f5b05e127519e/data/controls2_%02d.csv' data = [pandas.read_csv(path % i) for i in range(1,13)] df = pandas.concat(data, ignore_index=True) df.to_csv('data.csv') # save to a file # now open the Analyzer GUI from psychopy_ext import analyzer analyzer.run() import glob from scipy import misc from psychopy_ext import models import matplotlib.pyplot as plt # read images from the Change Detection experiment ims = glob.glob('../Part2/images/*.jpg') ims = [misc.imread(im) for im in ims] # crop and resize them to (128, 128) ims = [misc.imresize(im[:,im.shape[0]], (128, 128)) for im in ims] hmax = models.HMAX() hmax.compare(ims) from IPython.display import SVG, display from psychopy import visual, event from psychopy_ext import exp win = visual.Window(size=(400,400)) stim1 = visual.Circle(win) stim2 = visual.TextStim(win, "Ceci n'est pas un cercle!", height=.1) # write to svg svg = exp.SVG(win, filename='stimuli.svg') svg.write(stim1) svg.write(stim2) svg.svgfile.save() display(SVG('stimuli.svg')) # optional: show stimuli on the screen too stim1.draw() stim2.draw() win.flip() event.waitKeys() win.close()