Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Supported by

eye tribe output and opensesame

Hello! I am new to the OpenSesame and eye tribe world and truly impressed with the amazing things that you can do! i come from Tobii + Eprime background. Recently, I tested the eye tribe with a simple PpenSesame task. Everything works out nicely. I have some issues in understanding the best way to code the output (attached an example). For my research, i am mainly interested in fixation duration and count. I thought that maybe I could write some functions in excel to name each of my two AOIs, but advised that this is prone to mistakes and it is not convenient, especially when the design gets more complex. Do you recommend other ways to clean up the data?
Thank you in advance!


  • Hi Andrea,

    Good to see you on the forum! This is probably a common situation, so here's a script that does essentially what you want:

    • It reduces the data from a format where every row corresponds to a sample to a format where every row corresponds to a fixation
    • It also checks for each fixation whether it matches one of the ROIs that's specified at the top of the file, and, if so, labels it.

    This script uses DataMatrix, which is a simplified way to work with this kinds of tabular data. (I designed it essentially for OpenSesame and my own analyses.) The basic usage is explained in this notebook:

    DataMatrix is not a default part of Python, but you can install through pip install python-datamatrix.


    from datamatrix import io, DataMatrix
    from datamatrix import operations as ops
    INPUTFILE = 'test.tsv'
    OUTPUTFILE = 'summary.csv'
    ROIS = {
        'ROI-A' : {
                'x1' : 400,
                'y1' : 400,
                'x2' : 800,
                'y2' : 800
        'ROI-B' : {
                'x1' : -800,
                'y1' : 200,
                'x2' : -400,
                'y2' : 400
    # Read in the data
    dm = io.readtxt(INPUTFILE, delimiter='\t')
    # Create a new column, fixnr, that labels each sample with
    # a fixation number, or -1 if it's not part of a fixation
    dm.fixnr = -1
    # Now loop through all samples, and start labeling the fixations
    fixnr = -1
    for rownr, row in enumerate(dm):
        # Ignore whatever is not a fixation
        if row.fix == 'FALSE':
        # Increase the fixation number if we encounter a new fixation
        if rownr == 0 or dm[rownr-1].fix == 'FALSE':
            fixnr += 1
        # Label the sample as belonging to a fixation
        row.fixnr = fixnr
    # Remove everything that's not a fixation
    dm = dm.fix == 'TRUE'
    # Create a new datamatrix that we're going to use for the summary data.
    # That is, we're going to reduce the data from samples to fixations.
    summarydm = DataMatrix(length=fixnr)
    summarydm.stime = -1
    summarydm.dur = -1
    summarydm.x = -1
    summarydm.y = -1
    summarydm.psize = -1
    summarydm.fixnr = -1
    summarydm.roi = ''
    # Loop through all fixations (by splitting the full datamatrix based on the dm.fixnr column)
    # and store the summarized info in summarydm
    for summaryrow, (fixnr, fixdm) in zip(summarydm, ops.split(dm.fixnr)):
        summaryrow.stime = fixdm.time[0]
        summaryrow.dur = fixdm.time[-1] - fixdm.time[0]
        summaryrow.x = fixdm.rawx.median
        summaryrow.y = fixdm.rawy.median
        summaryrow.psize = fixdm.psize.median
        summaryrow.fixnr = fixnr
        # Loop through all ROIs, and see if the x,y coordinates fall within the ROI boundaries
        for roi, coor in ROIS.items():
            if summaryrow.x >= coor['x1'] and summaryrow.x <= coor['x2'] \
                    and summaryrow.y >= coor['y1'] and summaryrow.y <= coor['y2']:
                summaryrow.roi = roi
    # Save the summary as a csv file
    io.writetxt(summarydm, OUTPUTFILE)

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.

  • Dear Sebastiaan, many many thanks that was very useful! i do not have much experience with Python (yet) so I am still struggling with installing packages in the shell. Once I ll solve this I will try out the code above! Thank you again for your help!

  • You could even run this from within OpenSesame, by putting the code in an inline_script, selecting it, and clicking the 'Run selected text' button at the top-right. Not necessarily the most convenient in the long run. But possible.

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.

  • edited January 24

    Hi Sebastiaan, your script seems to be very helpful, thank you a lot for providing it...I'm trying to do this my self since days without success (not the greatest programmer...) Unfortunately, I only get the headers in the output file and I have no real clue what is going on :( I cannot attach one of my output tsv here because they are too big. I get no error message, only warnings:
    C:\Users\schischi\Anaconda3\lib\site-packages\datamatrix\ UserWarning: Some rows miss column rawx
    warnings.warn(safe_str(msg), *args)

    And this for every column...I would be grateful for any help or suggestions!
    Thank you,

    Edit: here is dropbox link to one of my file

  • Sorry, I was just incredibly stupid...I tried nearly everything...and then I realized that I only had to change 'FALSE' in 'False' :s

  • edited January 27

    Just came across with @sebastiaan 's code snippet. I found it to be very useful. My question is: I noticed that the fixation's coordinate and the pupil size were the median of samples - is this usually how EyeTribe data is handled? For now, I'm importing the raw gaze data to OGAMA ( just to detect the fixations and then export the event data, which is very inefficient...

    Thanks for your help!

  • My question is: I noticed that the fixation's coordinate and the pupil size were the median of samples - is this usually how EyeTribe data is handled?

    There is no established standard for the EyeTribe per se, but a median is simply more robust to noise. So therefore I would use the median in these kinds of cases.

    I should also point out that I wrote a Python parser for EyeLink, EyeTribe, and SMI data files (it was originally only for the EyeLink, hence the name):

    It's not documented very well, and for the moment I don't intend to actively support it. But it's still easier than writing custom scripts.

    There's much bigger issues in the world, I know. But I first have to take care of the world I know.

Sign In or Register to comment.