Skip to content

Commit

Permalink
builder: components avoid using variable names for initialisation
Browse files Browse the repository at this point in the history
This means they can use variables like 't' directly using 'set every frame'
  • Loading branch information
peircej committed Jul 26, 2011
1 parent 5016172 commit fe253ea
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 61 deletions.
40 changes: 32 additions & 8 deletions psychopy/app/builder/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Copyright (C) 2011 Jonathan Peirce
# Distributed under the terms of the GNU General Public License (GPL).

import os, glob, wx, Image
import os, glob, copy
import wx, Image
from os.path import *
import psychopy
def pilToBitmap(pil):
Expand All @@ -14,9 +15,9 @@ def pilToBitmap(pil):
return image.ConvertToBitmap()#wx.Image and wx.Bitmap are different

def getIcons(filename=None):
"""Creates wxBitmaps ``self.icon`` and ``self.iconAdd`` based on the the image.
"""Creates wxBitmaps ``self.icon`` and ``self.iconAdd`` based on the the image.
The latter has a plus sign added over the top.
png files work best, but anything that wx.Image can import should be fine
"""
if filename==None:
Expand All @@ -30,20 +31,20 @@ def getIcons(filename=None):
iconAdd = pilToBitmap(im)

return icon, iconAdd

def getComponents(folder=None):
"""Get a dictionary of available component objects for the Builder experiments.
If folder==None then the built-in components will be returned, otherwise
the components found in the folder provided will be returned.
"""
"""
if folder==None:
folder = dirname(__file__)
os.sys.path.append(folder)
components={}
#setup a default icon
if 'default' not in icons.keys():
icons['default']=getIcons(filename=None)
icons['default']=getIcons(filename=None)
#go through components in directory
if os.path.isdir(folder):
for file in glob.glob(os.path.join(folder, '*.py')):#must start with a letter
Expand All @@ -69,7 +70,7 @@ def getComponents(folder=None):
def getAllComponents(folderList=[]):
"""Get a dictionary of all available components, from the builtins as well
as all folders in the folderlist.
User-defined components will override built-ins with the same name.
"""
if type(folderList)!=list:
Expand All @@ -81,5 +82,28 @@ def getAllComponents(folderList=[]):
components[thisKey]=userComps[thisKey]
return components

def getInitVals(params):
"""Works out a suitable initial value for a parameter (e.g. to go into the
__init__ of a stimulus object, avoiding using a variable name if possible
"""
inits = copy.copy(params)
for name in params.keys():
if not hasattr(params[name], 'updates') or params[name].updates in ['constant',None,'None']:
continue #things that are constant don't need handling
elif name == 'pos': inits[name]=[0,0]
elif name in ['ori','sf','size','height','color','phase',
'volume']:
inits[name]="1.0"
elif name in ['image','mask']:
inits[name]="'sin'"
elif name=='texture resolution': inits[name]="128"
elif name == 'colorSpace': inits[name]="'rgb'"
elif name == 'font': inits[name]="'Arial'"
elif name == 'units': inits[name]="'norm'"
elif name == 'text': inits[name]="'nonsense'"
elif name == 'sound': inits[name]="'A'"
else:
print "I don't know the appropriate default value for a '%s' parameter" %name
return inits
tooltips = {}
icons={}
8 changes: 5 additions & 3 deletions psychopy/app/builder/components/aperture.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from _visual import * # to get the template visual component
from os import path
from psychopy.app.builder.components import getInitVals

__author__ = 'Jeremy Gray, Jon Peirce'
# March 2011; builder-component for Yuri Spitsyn's visual.Aperture class
Expand Down Expand Up @@ -42,10 +43,11 @@ def __init__(self, exp, parentName, name='aperture', units='norm',
del self.params['colorSpace']

def writeInitCode(self, buff):
inits = getInitVals(self.params)
#do writing of init
buff.writeIndented("%(name)s=visual.Aperture(win=win, name='%(name)s',\n" % (self.params))
buff.writeIndented(" size=%(size)s, pos=%(pos)s, units='pix')\n" % (self.params))
buff.writeIndented("%(name)s.disable() # is enabled by default\n" %(self.params))
buff.writeIndented("%(name)s=visual.Aperture(win=win, name='%(name)s',\n" % (inits))
buff.writeIndented(" size=%(size)s, pos=%(pos)s, units='pix')\n" % (inits))
buff.writeIndented("%(name)s.disable() # is enabled by default\n" %(inits))
def writeFrameCode(self, buff):
"""Only activate the aperture for the required frames
"""
Expand Down
2 changes: 1 addition & 1 deletion psychopy/app/builder/components/mouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self, exp, parentName, name='mouse',
self.params={}
self.order=[]
self.params['name']=Param(name, valType='code', allowedTypes=[],
hint="Even mice have names!")
hint="Even mice need names!")
self.params['startType']=Param(startType, valType='str',
allowedVals=['time (s)', 'frame N', 'condition'],
hint="How do you want to define your start point?")
Expand Down
21 changes: 16 additions & 5 deletions psychopy/app/builder/components/movie.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from _visual import * #to get the template visual component
from os import path
from psychopy.app.builder.components import getInitVals

thisFolder = path.abspath(path.dirname(__file__))#the absolute path to the folder containing this path
iconFile = path.join(thisFolder,'movie.png')
Expand Down Expand Up @@ -41,11 +42,21 @@ def __init__(self, exp, parentName, name='movie', movie='',
del self.params['color']
del self.params['colorSpace']
def writeInitCode(self,buff):
buff.writeIndented("%(name)s=visual.MovieStim(win=win, filename=%(movie)s, name='%(name)s',\n" %(self.params))
buff.writeIndented(" ori=%(ori)s, pos=%(pos)s" %(self.params))
if self.params['size'].val != '': buff.writeIndented(", size=%(size)s"%(self.params))
buff.writeIndented(")\n")

#if the movie is constant then load it once at beginning of script.
#if it changes each repeat then we should wait and creat the entire object at
#Routine start
if self.params['movie'].updates=='constant':
initVals = getInitVals(self.params)
buff.writeIndented("%(name)s=visual.MovieStim(win=win, filename=%(movie)s, name='%(name)s',\n" %(self.params))
buff.writeIndented(" ori=%(ori)s, pos=%(pos)s" %(self.params))
if self.params['size'].val != '': buff.writeIndented(", size=%(size)s"%(self.params))
buff.writeIndented(")\n")
def writeRoutineStartCode(self,buff):
if self.params['movie'].updates!='constant':
buff.writeIndented("%(name)s=visual.MovieStim(win=win, filename=%(movie)s, name='%(name)s',\n" %(self.params))
buff.writeIndented(" ori=%(ori)s, pos=%(pos)s" %(self.params))
if self.params['size'].val != '': buff.writeIndented(", size=%(size)s"%(self.params))
buff.writeIndented(")\n")
def writeFrameCode(self,buff):
"""Write the code that will be called every frame
"""
Expand Down
19 changes: 11 additions & 8 deletions psychopy/app/builder/components/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from _visual import * #to get the template visual component
from os import path
from psychopy.app.builder.components import getInitVals

thisFolder = path.abspath(path.dirname(__file__))#the absolute path to the folder containing this path
iconFile = path.join(thisFolder,'patch.png')
Expand Down Expand Up @@ -50,13 +51,15 @@ def __init__(self, exp, parentName, name='patch', image='sin', mask='None', sf='
hint="How should the image be interpolated if/when rescaled")

def writeInitCode(self,buff):
buff.writeIndented("%(name)s=visual.PatchStim(win=win, name='%(name)s',\n" %(self.params))
buff.writeIndented(" tex=%(image)s, mask=%(mask)s,\n" %(self.params))
buff.writeIndented(" ori=%(ori)s, pos=%(pos)s, size=%(size)s, sf=%(sf)s, phase=%(phase)s,\n" %(self.params) )
buff.writeIndented(" color=%(color)s, colorSpace=%(colorSpace)s,\n" %(self.params) )
buff.writeIndented(" texRes=%(texture resolution)s" %(self.params))# no newline - start optional parameters
if self.params['units'].val!='window units': buff.write(", units=%(units)s" %(self.params) )
if self.params['interpolate']=='linear': buff.write(", interpolate=True")
inits = getInitVals(self.params)#replaces variable params with defaults
buff.writeIndented("%(name)s=visual.PatchStim(win=win, name='%(name)s',\n" %(inits))
buff.writeIndented(" tex=%(image)s, mask=%(mask)s,\n" %(inits))
buff.writeIndented(" ori=%(ori)s, pos=%(pos)s, size=%(size)s, sf=%(sf)s, phase=%(phase)s,\n" %(inits) )
buff.writeIndented(" color=%(color)s, colorSpace=%(colorSpace)s,\n" %(inits) )
buff.writeIndented(" texRes=%(texture resolution)s" %(inits))# no newline - start optional parameters
if self.params['units'].val!='window units': buff.write(", units=%(units)s" %(inits) )
if self.params['interpolate']=='linear':
buff.write(", interpolate=True")
else: buff.write(", interpolate=False")
buff.write(")\n" %(self.params))#finish with newline
buff.write(")\n")#finish with newline

7 changes: 4 additions & 3 deletions psychopy/app/builder/components/sound.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from _base import *
from os import path
from psychopy.app.builder.components import getInitVals

thisFolder = path.abspath(path.dirname(__file__))#the absolute path to the folder containing this path
iconFile = path.join(thisFolder,'sound.png')
Expand Down Expand Up @@ -45,11 +46,11 @@ def __init__(self, exp, parentName, name='sound', sound='A',volume=1,
hint="The volume (in range 0 to 1)")

def writeInitCode(self,buff):
buff.writeIndented("#initialise %(name)s\n" %(self.params))
inits = getInitVals(self.params)#replaces variable params with sensible defaults
if self.params['stopType']=='duration (s)':
durationSetting="secs=%(stopVal)s" %self.paramss
buff.writeIndented("%s=sound.Sound(%(sound)s,%s)\n" %(self.params['name'], durationSetting))
buff.writeIndented("%(name)s.setVolume(%(volume)s)\n" %(self.params))
buff.writeIndented("%s=sound.Sound(%(sound)s,%s)\n" %(inits, durationSetting))
buff.writeIndented("%(name)s.setVolume(%(volume)s)\n" %(inits))
def writeFrameCode(self,buff):
"""Write the code that will be called every frame
"""
Expand Down
18 changes: 10 additions & 8 deletions psychopy/app/builder/components/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from _visual import * #to get the template visual component
from os import path
from psychopy.app.builder.components import getInitVals

thisFolder = path.abspath(path.dirname(__file__))#the absolute path to the folder containing this path
iconFile = path.join(thisFolder,'text.png')
Expand Down Expand Up @@ -44,12 +45,13 @@ def __init__(self, exp, parentName, name='text',
hint="Specifies the height of the letter (the width is then determined by the font)")
def writeInitCode(self,buff):
#do we need units code?
if self.params['units'].val=='window units': units=""
else: units="units=%(units)s, " %self.params
if self.params['units'].val=='window units': unitsStr=""
else: unitsStr="units=%(units)s, " %self.params
#do writing of init
text = unicode(self.params['text'])
buff.writeIndented("%(name)s=visual.TextStim(win=win, ori=%(ori)s, name='%(name)s',\n" %(self.params))
buff.writeIndented(" text=%s,\n" %text)
buff.writeIndented(" font=%(font)s,\n" %(self.params))
buff.writeIndented(" "+units+"pos=%(pos)s, height=%(letterHeight)s,\n" %(self.params))
buff.writeIndented(" color=%(color)s, colorSpace=%(colorSpace)s)\n" %(self.params))
text = setDefault
inits = getInitVals(self.params)#replaces variable params with sensible defaults
buff.writeIndented("%(name)s=visual.TextStim(win=win, ori=%(ori)s, name='%(name)s',\n" %(inits))
buff.writeIndented(" text=%(text)s,\n" %inits)
buff.writeIndented(" font=%(font)s,\n" %inits)
buff.writeIndented(" "+unitsStr+"pos=%(pos)s, height=%(letterHeight)s,\n" %(inits))
buff.writeIndented(" color=%(color)s, colorSpace=%(colorSpace)s)\n" %(inits))
31 changes: 6 additions & 25 deletions psychopy/app/builder/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,23 +757,17 @@ def writeInitCode(self,buff):
def writeMainCode(self,buff):
"""This defines the code for the frames of a single routine
"""

buff.writeIndentedLines("\n#update component parameters for each repeat\n")
#This is the beginning of the routine, before the loop starts
for event in self:
event.writeRoutineStartCode(buff)

#create the frame loop for this routine
buff.writeIndentedLines('\n#run %s\n' %(self.name))
buff.writeIndented('continueRoutine=True\n')
buff.writeIndented('t=0; %s.reset()\n' %(self._clockName))
buff.writeIndented('frameN=-1\n')

maxtime = self.getMaxTime()
if maxtime >= FOREVER:
maxtime = 'FOREVER' # defined in the script by import psychopy.constants
else:
maxtime = '%.4f' % maxtime
buff.writeIndentedLines("\n#update component parameters for each repeat\n")
#This is the beginning of the routine, before the loop starts
for event in self:
event.writeRoutineStartCode(buff)

buff.writeIndented('while continueRoutine:\n')
buff.setIndentLevel(1,True)

Expand All @@ -783,7 +777,7 @@ def writeMainCode(self,buff):
buff.writeIndented('frameN=frameN+1#number of completed frames (so 0 in first frame)\n')

#write the code for each component during frame
buff.writeIndentedLines('#update/draw components on each frame\n')
buff.writeIndentedLines('#update/draw components on each frame')
for event in self:
event.writeFrameCode(buff)

Expand Down Expand Up @@ -822,19 +816,6 @@ def getComponentFromName(self, name):
if comp.params['name']==name:
return comp
return None
def getMaxTime(self):
maxTime=0
times=[]
for event in self:
if 'startTime' not in event.params.keys(): continue
if event.params['duration'].val in ['-1', ''] \
or '$' in [event.params['startTime'].val[0], event.params['duration'].val[0]]:
maxTime=FOREVER
else:
exec("maxTime=%(startTime)s+%(duration)s" %(event.params))#convert params['duration'].val into numeric
times.append(maxTime)
maxTime=float(max(times))
return maxTime

class NameSpace():
"""class for managing variable names in builder-constructed experiments.
Expand Down

0 comments on commit fe253ea

Please sign in to comment.