PyHab Class (base)

This is the base class that is used to actually run PyHab studies. There is an extension of this base class for preferential looking paradigms, see Preferential Looking

class PyHab.PyHabClass.PyHab(settingsDict, testMode=False)

PyHab looking time coding + stimulus control system

Jonathan Kominsky, 2016-2018

Keyboard coding: A = ready, B = coder 1 on, L = coder 2 on, R = abort trial, Y = end experiment (for fussouts)

Between-trials: R = redo previous trial, J = jump to test trial, I = insert additional habituation trial (hab only)

Throughout this script, win2 is the coder display, win is the stimulus presentation window. dataMatrix is the primary data storage for the summary data file. It is a list of dicts, each dict corresponds to a trial.

Anything called “verbose” is part of the verbose data file. There are up to four such structures: On (for gaze-on events) Off (for gaze-off events) On2 and Off2 (for the optional secondary coder) Each coder’s on and off are recorded in a separate dict with trial, gaze on/off, start, end, and duration.

SetupWindow()

Sets up the stimulus presentation and coder windows, loads all the stimuli, then starts the experiment with doExperiment()

Returns:
Return type:
TrackerCalibrateValidate()

Function that controls the eye-tracker calibration and validation in eye-tracking modes. In principle this can be run mid-experiment, but it will be disruptive

Returns:
Return type:
abortTrial(onArray, offArray, trial, ttype, onArray2, offArray2, stimName='', habTrialNo=0, habCrit=0.0)

Only happens when the ‘abort’ button is pressed during a trial. Creates a “bad trial” entry out of any data recorded for the trial so far, to be saved later.

Parameters:
  • onArray (list of dicts {trial, trialType, startTime, endTime, duration}) – Gaze-on events for coder 1
  • offArray (list of dicts {trial, trialType, startTime, endTime, duration}) – Gaze-off events for coder 1
  • trial (int) – trial number
  • ttype (string) – trial type
  • onArray2 (list of dicts) – Gaze-on events for (optional) coder 2
  • offArray2 (list of dicts) – Gaze-off events for (optional) coder 2
  • stimName (string) – If presenting stimuli, name of the stim file
  • habTrialNo (int) – Tracking if this is a habituation trial and if so what number
  • habCrit (float) – Habituation criterion, if it’s been set
Returns:

Return type:

attnGetter(trialType, cutoff=False, onmin=0.0, midTrial=False)

Plays either a default attention-getter animation or a user-defined one. Separate settings for audio w/shape and video file attention-getters.

Parameters:
  • trialType (string) – Current trial type
  • cutoff (bool) – Cut off AG immediately on gaze-on? Defaut False
  • onmin (float) – Delay in listening for gaze-on to immediately end AG. Default 0
  • midTrial (bool) – Is this a mid-trial attention-getter? Default False
Returns:

Return type:

avgObsAgree(timewarp, timewarp2)

Computes average observer agreement as agreement in each trial, divided by number of trials.

Parameters:
  • timewarp (list) – List of every individual frame’s gaze-on/gaze-off code for coder A
  • timewarp2 (list) – As above for coder B
Returns:

average observer agreement or N/A if no valid data

Return type:

float

blockExpander(blockInfo, prefixes, hab=False, habNum=0, insert=-1, baseStart=-1)

A method for constructing actualTrialOrder while dealing with recursive blocks. Can create incredibly long trial codes, but ensures that all information is accurately preserved. Works for both hab blocks and other things.

For hab blocks, we can take advantage of the fact that hab cannot appear inside any other block. It will always be the top-level block, and so we can adjust the prefix once and it will carry through.

The trial naming preserves hierarchy in a block.trial or block.subblock.trial form. Hab blocks are designated by a ‘*’ before the first ‘.’, and the last trial in a hab block is marked with ‘^’, which is needed to trip checkStop.

Because hab blocks cannot be embedded in other blocks, the top-level block is always the one with the hab settings.

Parameters:
  • blockInfo (dict) – The data of the block object, including trialList and hab info.
  • prefixes (str) – A recursively growing stack of prefixes. If block A has B and block B has C, then an instance of A will be A.B.C in self.actualTrialOrder. This keeps track of the A.B. part.
  • hab (bool) – Are we dealing with a habituation trial expansion?
  • habNum (int) – If we are dealing with a habituation trial expansion, what hab iteration of it are we on?
  • insert (int) – An int specifying where in actualTrialOrder to put a trial. Needed to generalize this function for insertHab
  • baseStart (int) – Marks the index where the top-level block started in actualTrialOrder.
Returns:

Return type:

checkStop(blockName)

After a hab trial, checks the habitution criteria and returns ‘true’ if any of them are met. Also responsible for setting the habituation criteria according to settings. Prior to any criteria being set, self.HabCrit is 0, and self.habSetWhen is -1.

Uses a sort of parallel data structure that just tracks hab-relevant gaze totals. As a bonus, this means it now works for both single-target and preferential looking designs (and HPP designs) with no modification.

To support multiple hab blocks, this needs to take the block name as an argument, to only look at that block’s hab settings. That means each block with habituation turned on can only be used once, but you can have more than one block

Parameters:blockName (str) – The name of the block associated with the hab trial, required to look up its particular settings.
Returns:True if hab criteria have been met, False otherwise
Return type:bool
cohensKappa(timewarp, timewarp2)

Computes Cohen’s Kappa

Parameters:
  • timewarp (list) – List of every individual frame’s gaze-on/gaze-off code for coder A
  • timewarp2 (list) – As above for coder B
Returns:

Kappa

Return type:

float

dataRec(onArray, offArray, trial, type, onArray2, offArray2, stimName='', habTrialNo=0, habCrit=0.0)

Records the data for a trial that ended normally.

Parameters:
  • onArray (list of dicts {trial, trialType, startTime, endTime, duration}) – Gaze-on events for coder 1
  • offArray (list of dicts {trial, trialType, startTime, endTime, duration}) – Gaze-off events for coder 1
  • trial (int) – trial number
  • type (string) – trial type
  • onArray2 (list) – Gaze-on events for (optional) coder 2
  • offArray2 (list) – Gaze-off events for (optional) coder 2
  • stimName (string) – If presenting stimuli, name of the stim file
  • habTrialNo (int) – If part of a hab block, what hab trial it was part of.
  • habCrit (double) – If part of a hab block, the current habituation criterion.
Returns:

Return type:

dispAnimationStim(trialType, dispAnim, screen='C')

Placeholder function for displaying an animation. Requires some code customization to use. Create an experiment then go into its copy of PyHabClass and modify it to have different animation routines based on dispAnim. Note that the objects for the animations need to be created in SetupWindow.

You can feel free to use self.frameCount[screen] to regulate your animations and reset is as needed. A demo animation is written below but never referenced.

Parameters:
  • trialType (str) – the current trial type
  • dispAnim (str) – Name of the animation to display
  • screen (str) – Which screen to display on (matters for HPP)
Returns:

int specifying animation in progress (0), paused on last frame (1), or ending and looping (2)

Return type:

int

dispAudioStim(trialType, dispAudio)

For playing audio stimuli. A little more complicated than most because it needs to track whether the audio is playing or not. Audio plays separately from main thread.

Parameters:dispAudio (sound.Sound object) – the stimuli as a sound.Sound object
Returns:an int specifying whether the audio is in progress (0), we are in an ISI (1), or the audio is looping (2)
Return type:int
dispCoderWindow(trialType=-1)

Draws the coder window, according to trial type and blinding settings.

Parameters:trialType (int or string) – -1 = black (betwen trials). 0 = ready state. Otherwise irrelevant.
Returns:
Return type:
dispImageStim(dispImage, screen='C')

Very simple. Draws still-image stimuli and flips window

Parameters:
  • dispImage (visual.ImageStim object) – the visual.ImageStim object
  • screen (str) – For HPP, which screen the image is to appear on
Returns:

constant, 1

Return type:

int

dispMovieStim(trialType, dispMovie, screen='C')

Draws movie stimuli to the stimulus display, including movie-based attention-getters.

Parameters:
  • trialType (int or str) – 0 for paused, otherwise a string
  • dispMovie (moviestim3 object) – The moviestim3 object for the stimuli
  • screen (str) – The screen on which the movie should display. Only relevant for HPP.
Returns:

an int specifying whether the movie is in progress (0), paused on its last frame (1), or ending and looping (2)

Return type:

int

dispTrial(trialType, dispMovie=False)

Draws each frame of the trial. For stimPres, returns a movie-status value for determining when the movie has ended

Parameters:
  • trialType (string) – Current trial type
  • dispMovie (bool or dict) – A dictionary containing both the stimulus type and the object with the stimulus file(s) (if applicable)
Returns:

1 or 0. 1 = end of movie for trials that end on that.

Return type:

int

doExperiment()

The primary control function and main trial loop.

Returns:
Return type:
doTrial(number, ttype, disMovie)

Control function for individual trials, to be called by doExperiment Returns a status value (int) that tells doExperiment what to do next

self.playThrough registers the end-trial crieria 0 = standard “cumulative on-time >= MinOn and consecutive off-time >= MaxOff” 1 = “OnOnly”, only requires that cumulative on-time > MinOn 2 = “None”, plays to max duration no matter what. 3 = “Either/or”, as standard but with “or” instead of “and”. Whichever comes first.

Parameters:
  • number (int) – Trial number
  • ttype (string) – Trial type - the full expanded one with block hierarchy and hab trial info included.
  • disMovie (dictionary) – A dictionary as follows {‘stim’:[psychopy object for stimulus presentation], ‘stimType’:[movie,image,audio, pair]}
Returns:

int, 0 = proceed to next trial, 1 = hab crit met, 2 = end experiment, 3 = trial aborted

Return type:

endExperiment()

End experiment, save all data, calculate reliability if needed, close up shop. Displays “saving data” and end-of-experiment screen.

Returns:
Return type:
flashCoderWindow(rep=False)

Flash the background of the coder window to alert the experimenter they need to initiate the next trial. .2 seconds of white and black, flashed twice. Can lengthen gap between trial but listens for ‘A’ on every flip.

Returns:
Return type:
insertHab(tn, block, hn=-1)

Literally insert a new hab trial or meta-trial into actualTrialOrder, get the right movie, etc.

Parameters:
  • tn (int) – trial number to insert the trial
  • hn – HabCount number to insert the hab trial. By default, whatever the current habcount is. However, there

are edge cases when recovering from “redo” trials when we want to throw in a hab trial further down the line. :type hn: int :param block: The habituation block the trial is being added to :type block: str :return: [disMovie, trialType], the former being the movie file to play if relevant, and the latter being the new trial type :rtype: list

isInt()

silly little function for validating a very narrow usage of “cond” field

Returns:Bool: if arbitrary argument t is an int, true.
Return type:
jumpToTest(tn, block, met=False)

Jumps out of a hab block into whatever the first trial after the current hab block.

Parameters:
  • tn (int) – current trial number when the function is called
  • block (str) – Block the habituation belongs to. Find end of block, done, because hab blocks can’t be embedded and each one can only occur in the flow once.
  • met (bool) – A boolean for whether this is because of J (False) or whether this is a genuine hab-criterion-met
Returns:

[disMovie, trialType] as insertHab, the former being the movie file to play if relevant, and the latter being the new trial type

Return type:

list

loadStim(stim, screen='C')

A general function for loading stimuli that can be called repeatedly.

TODO: Windows audio bug when loading an audio file before a movie file means that we should change load order for everything to movie first.

Parameters:
  • stim (str) – stimulus name, key for stimList dict
  • screen (str) – Screen to load stimuli to, doesn’t matter except for HPP, defaults to center
Returns:

a dictionary with type and stimulus object

Return type:

dict

lookKeysPressed()

A simple boolean function to allow for more modularity with preferential looking Basically, allows you to set an arbitrary set of keys to start a trial once the attngetter has played. In this case, only B (coder A on) is sufficient.

This function can become the eye-tracker interface, basically. It will listen for the eye-tracker input.

Todo: Can we implement a debug mode that simulates key-presses for some amount of time?

Returns:True if the B key is pressed, False otherwise.
Return type:bool
lookScreenKeyPressed(screen=['C'])

A function that primarily exists for HPP, because of the need to distinguish between any key being pressed and the key corresponding to the HPP screen in question being pressed

Parameters:screen (list of strings) – List of screens for next stim.
Returns:for non-HPP versions, the value of lookKeysPressed.
Return type:bool
pearsonR(verboseMatrix, verboseMatrix2)

Computes Pearson’s R

Parameters:
  • verboseMatrix (dict) – Verbose data, coder A
  • verboseMatrix2 (dict) – Verboase data, coder B
Returns:

Pearson’s R

Return type:

float

printCurrentData()

A function which prints the current data to the output window, made into its own function to facilitate having working versions for PL and HPP studies as well. Only called when stimulus presentation is off.

Returns:
Return type:
redoSetup(tn, autoAdv, blockName, blockRedo=False, fromAbort=False)

Lays the groundwork for redoTrial, including correcting the trial order, selecting the right stim, etc.

Parameters:
  • tn (int) – Trial number (trialNum), to be redone (or in the process of being aborted)
  • autoAdv (list) – The current auto-advance trial type list (different on first trial for Reasons)
  • blockName (str) – Pulls topBlockName from doExperiment to deal with redoing block and habituations.
  • blockRedo (bool) – A special type of redo reserved for blocks, that rewinds to the start of the top-level block.
  • fromAbort (bool) – A bool for blockRedos, to see if this is coming off a redo, which requires an extra check.
Returns:

list, [disMovie, trialNum], the former being the movie file to play if relevant, and the latter being the new trial number

Return type:

redoTrial(trialNum)

Allows you to redo a trial after it has ended. Similar to abort trial, but under the assumption that the data has already been recorded and needs to be replaced.

This function only handles the data part. The actual re-assignment of the trial is done elsewhere.

Parameters:trialNum (int) – Trial number to redo
Returns:
Return type:
reliability(verboseMatrix, verboseMatrix2)

Calculates reliability statistics. Constructed originally by Florin Gheorgiu for PyHab, modified by Jonathan Kominsky.

Parameters:
  • verboseMatrix (list) – A 2-dimensional list with the content of the verbose data file for coder 1
  • verboseMatrix2 (list) – A 2-dimensional list with the content of the verbose data file for coder 2
Returns:

A dict of four stats in float form (weighted % agreement, average observer agreement, Cohen’s Kappa, and Pearson’s R)

Return type:

dict

run(testMode=[])

Startup function. Presents subject information dialog to researcher, reads and follows settings and condition files. Now with a testing mode to allow us to skip the dialog and ensure the actualTrialOrder structure is being put together properly in unit testing.

Also expands habituation blocks appropriately and tags trials with habituation iteration number as well as the symbol for the end of a hab block (^)

Parameters:testMode (list) – Optional and primarily only used for unit testing. Will not launch the window and start the experiment. Contains all the info that would appear in the subject info dialog.
Returns:
Return type:
saveBlockFile()

A function that create a block-level summary file and saves it. Copies the primary data matrix (only good trials) and loops over it, compressing all blocks. Does not work for habs, which follow their own rules.

Returns:A condensed copy of dataMatrix with all blocks of the relevant types condensed to one line.
Return type:list
saveHabFile()

Creates a habituation summary data file, which has one line per hab trial, and only looks at parts of the hab trial that were included in calcHabOver. This is notably easier in some ways because the hab trials are already tagged in dataMatrix

Returns:A condensed copy of dataMatrix with all hab trials condensed only to those that were used to compute habituation.
Return type:list
wPA(timewarp, timewarp2)

Calculates weighted percentage agreement, computed as number of agreement frames over total frames.

Parameters:
  • timewarp (list) – List of every individual frame’s gaze-on/gaze-off code for coder A
  • timewarp2 (list) – As above for coder B
Returns:

Weighted Percentage Agreement

Return type:

float