Skip to content

Class: Experiment

Felix Engelmann edited this page Feb 7, 2014 · 1 revision

Source Code: experiment.py


Every EyeScript script must create an Experiment object before running the session. The Experiment class is responsible for taking care of the global settings in an experiment (e.g. display settings, initializing the eyetracker, etc.).

An Experiment class object has the following attributes

  • theExperiment: Experiment object

An Experiment instance object has the following data attributes

  • params: Dictionary
  • eyedatafile: String
  • edffile: String
  • textdatafile: String
  • log: EventLog
  • trialNumber: Integer
  • recording: Boolean
  • screen: Screen
  • devices: List
  • response_collectors: List
  • streams: List
  • eventQueue: List

An Experiment instance object has the following methods

  • __init__ : Constructor
  • _vEggConfig
  • _trackerCreate
  • close
  • __getitem__
  • __setitem__
  • keys

An Experiment class object has the following classes

def __init__(self,**params)

The __init__ method initializes experiment's setting when an Experiment object is created. **params gives us the attribute value pairs that are provided at the time of object instantiation (:ref:`experimentinit`). Any attribute that is not specified is taken from :ref:`default`.:

::

from defaults import defaultParams unusedKeys = [str(key) for key in params.keys() if key not in defaultParams.keys()] if unusedKeys: raise "Experiment(): Experimental parameter(s) not recognized: %s"%(", ".join(unusedKeys)) self.params = defaultParams.copy() self.update(params)

We then create a directory for writing all the data files. If the data_directory attribute is not provided, the default value ("data") is taken from :ref:`default`.:

    if not os.path.isdir(self['data_directory']):
       os.mkdir(self['data_directory'])

This is followed by asking the subject for an ID (which is mandatory) [2]; additionally, we can get more information [8]-[15] about the subject's background. The user is prompted to enter this information at the start of a session [16]. From [20]-[30], we initialize some attributes necessary for file names, sessionsuffix, self['data_file_root_name'], self.eyedatafile, self.edffile, self.textdatafile. Both self['data_directory'] and self['data_filename_prefix'], if not specified at the time of object instantiation, will take the default values of `data` and `s` respectively. If the subject is satisfied with what (s)he has entered we break [36], else we ask all the information again.:

    while 1:
             subjectString = self['subject'] = raw_input("Enter subject ID (0 for no data logging): ").decode('437')
             if self['subject'].isdigit():
                 self['subject'] = int(self['subject'])
                 subjectString = "%03d"%self['subject']
             for attribute in self['session_info']:
                 longattr = attribute
                 if attribute == "study": longattr = "field of study"
                 if attribute == "gender": longattr = "gender (m/w)"
                 if attribute == "glasses": longattr = "glasses/lenses?"
                 if attribute == "alc24": longattr = "alcohol in last 24h? (y/n)"
                 if attribute == "hsleep": longattr = "hours of sleep last night"
                 if attribute == "nativelang": longattr = "mother tongue"
                 if attribute == "origin": longattr = "origin (Bundesland)"
                 if attribute == "time": longattr = "time (morning/noon/afternoon/evening)"          
                 self[attribute] = raw_input("Enter %s: "%longattr).decode('437')
                 if self[attribute].isdigit(): self[attribute] = int(self[attribute])
                 if self[attribute] == "": self[attribute] = "."

             sessionsuffix = 'session' in self['session_info'] and "_%s"%self['session'] or ""
             self['data_file_root_name'] = self['data_filename_prefix']+subjectString+sessionsuffix
             self.eyedatafile=os.path.join(self['data_directory'],"%s%sedf"%(
                 self['data_file_root_name'],os.extsep)
                 )
             self.edffile="%s%s%s%sedf"%(
                 self['edf_prefix'],subjectString,sessionsuffix[1:],os.extsep
                 )
             self.textdatafile=os.path.join(self['data_directory'],"%s%stxt"%(
                 self['data_file_root_name'],os.extsep)
                 )

             print "\nPlease verify the session info."
             for attribute in ['subject'] + self['session_info']: print "%s: %s"%(attribute,self[attribute])
             if self['subject'] > 0 and (os.path.isfile(self.eyedatafile) or os.path.isfile(self.textdatafile)):
                print "WARNING: data file already exists and will be overwritten unless the session info is changed."
             if raw_input("\nKeep the session info as is? (y/n): ")!="n": break

We instantiate an EventLog object (:ref:`class-eventlog`) by providing the attribute-values of self['session_info'] [1], and then adding the EyeScript_version to it [4]. Other attributes are initialized, self.trialNumber [6], self.recording [7], self.screen [10], self.devices [13], self.response_collectors [14], self.streams [15], self.eventQueue [19]. If/when mouse and keyboard devices are created, then mouse and keyboard events will be allowed [12]. Set up the keyboard so that we can (at least) handle the abort key combo during the experiment [17]. Finally, we show a screen while setting up the trail [20].:

    self.log = self.EventLog(**dict([(attribute,self[attribute]) for attribute in ['subject']+self['session_info']]))

    from EyeScript import __version__
    self.log.logAttributes(EyeScript_version = __version__)

    self.trialNumber = 0
    self.recording = False

    self._vEggConfig()
    self.screen = VisionEgg.Core.get_default_screen()  
    self._trackerCreate()
    pygame.event.set_allowed(None)
    self.devices = []
    self.response_collectors = []
    self.streams = []
    import devices
    setUpDevice(devices.KeyboardDevice) 
    from displays import TextDisplay
    self.eventQueue = []
    TextDisplay("Loading experiment...",duration=0,response_collectors=[]).run()

def _vEggConfig(self)

Configures VisionEgg. Called in __init__().

def _trackerCreate(self)

Configures the Eyelink eyetracker. Called in __init__().

def close(self)

Shuts down VisionEgg and writes the EventLog to a file (the EventLog object was created in __init__()). This is done by calling self.log.writeLog() (:ref:`class-eventlog`). The filename (self.textdatafile) was initialized in __init__(). close() is called by runSession() (:ref:`experiment-utility`) at the end of a session. runSession() in turn will be called within an experiment script to initiate a session (e.g., :ref:`sessionrun`).

def __getitem__(self, name); __setitem__(self, name, value); keys(self)

Needed in order to inherit dictionary funtionalities from DictMixin.


Utility methods: Experiment

def checkForResponse()

Check for subject responses and experimenter-initiated abort. This function is repeatedly called by the run method of display objects, to check for responses while the display is running. In most EyeScript scripts, it is sufficient to use the displays' run methods rather than directly calling checkForResponse. checkForResponse should be called (repeatedly) whenever the experiment does any waiting or looping that's not a display's run method (example: a loop that waits for the subject's gaze to fall on a critical region before playing a beep). Besides making sure any responses are logged accurately, checkForResponse is also necessary to check for experimenter-initiated aborts and to maintain contact with the operating system. Returns a list of ResponseCollector objects (if any) that received a response.

    events = getEvents()
    return [rc for rc in getExperiment().response_collectors if rc.respond(events)]

def updateEvents()

Called by getEvents() to update the experiment's eventQueue by calling poll() for each device associated with the experiment.

def getEvents()

Returns all the events since the last getEvents() call.

def getDevice(device_class)

Given a class, return the device object (:ref:`class-device`) from the experiment's list devices that matches that class, or None if the device hasn't been added yet

def setUpDevice(device_class)

Given a device class, adds a device of that class to the experiment's list of devices (if it's not already added).

def getExperiment()

Returns the last Experiment object (:ref:`class-experiment`) created, or None if none has been created yet.

def getTracker()

Returns an Eyelink object representing the eyetracker, or a stub object if the tracker isn't connected.

def getLog()

Returns the EventLog object (:ref:`class-eventlog`) for logging experimental data.

###def calibrateTracker(colors=None) Tells the eyetracker PC to go to the setup menu. The colors argument is a 2-tuple defining the foreground and background colors for the calibration display as RGB 3-tuples.

def runSession(callback)

Calls the given function, in addition to doing some logging and final cleanup. runSession returns the value of the argument function (possibly None). Called to initiate a session in an experiment (e.g. :ref:`sessionrun`); callback is the function defining what happens during a session. Calls close() (:ref:`class-experiment`) that writes the log data onto a file [], shows the final display screen [].

    from displays import TextDisplay
    closeDisplay = TextDisplay("Saving data...",duration=0,response_collectors=[])

    try:
       result=callback()
    finally:
       getExperiment().recording = False
       closeDisplay.run()
       getExperiment().close()
    return result

def formatMoney(amount)

Takes a money amount as a float, positive or negative, in dollars; returns the amount as a formatted string.