Open experiments using code in a preceding experiment

Hello,

Is there a way to automatically open a second psychopy experiment after running a first? I would make one big file with both experiments, but the way they’re coded makes it difficult. Also, I’d like information from the first experiment (participant number) to determine which experiment to run next. Is there a way to do this?

Thank you,
Victor

There are several ways to achieve this, if you’re coding it yourself you’re already on the right path. It’s actually a much better idea to have the two experiments as separate files.

It will really be worth your while to make sure you have a good understanding of how functions work, of how to import code from another file, and maybe learn about how classes work. Once you understand these basic python and programming concepts, this should make a lot of sense. Take a few days and do some python tutorials on these topics (though classes might be a bit of a bigger topic that will take time to absorb).

To give a short answer, I would recommend writing a separate file that acts as your main script, and calls the other scripts. Here’s an example where the two entire experiments would each be wrapped in a function I’m calling “run”. Since we know functions can accept arguments, and then return values, you can save the values returned from the first experiment and pass them to the function that contains your second experiment. Here’s a very simple example with three files:

exp1.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-

def run(arg1, arg2):

    # experiment code written here
    # note that indentation is very important
    # in python
    result1 = arg1 + arg2

    return result1

exp2.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-

def run(arg1, arg2, arg3):

    # experiment code here
    result2 = arg1 + arg2 + arg3

    return result2

expController.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-

# Here we make the code from
# exp1.py and exp2.py available
import exp1
import exp2

if __name__ == '__main__':

    arg1 = u"Hey "
    arg2 = u"Steve."
    # we call the function "run()" in exp1, 
    # and save its return value in a variable 
    # called result1, which we plan to hand to
    # experiment 2
    result1 = exp1.run(arg1, arg2)

    arg3 = u" How're "
    arg4 = u"you?"
    # run experiment 2
    result2 = exp2.run(result1, arg3, arg4)
    print(result2)

You also need to add a file called __init__.py (that’s two underscores before and after init), in the same folder. This file can be blank, but it needs to exist. This tells python that code from this folder can be imported.

I recommend making these four files and putting them in a separate folder to test this concept out. For this example to work, exp1.py, exp2.py, expController.py and __init__.py all have to be in the same folder.

Then to run it, in the terminal / command line, make sure that you’re in the same folder as the as the script, and run:

python expController.py 

This calls our main script, which will call the individual experiment scripts. In this example, it should print “Hey Steve. How’re you?” to the console. Hopefully this will get you started, and maybe someone else will chime in with different ideas, but I would stay away from a solution using execfile(), especially since you want to pass around arguments, and doing it this way will introduce you to some fundamental programming concepts.

And rereading your question, I would put the code for deciding which experiment to run in the expController.py.

1 Like

Hi Daniel,

Thank you for the thorough response. I understand the code you sent, but I’m having trouble applying it to my experiments.

Here’s what I tried:

Both experiment 1 and 2

def run():
    # indented experiment code from builder

Experiment controller

import exp1
import exp2

if __name__ == '__main__':
    exp1.run()
    exp2.run()

This would only run experiment 1. I played around with it but couldn’t get it to run both experiments one after the other.

Ideally, what I’m looking for is code for a code component in the builder of experiment 1 that would open experiment 2 (in a different folder, if possible) if the participant number was say 24, 68, or 95; or open a different experiment if it was a different participant number. Is there a way to do this?

You know I suspect that the call to core.quit() at the end of experiment 1 might kill the whole process. You could add a condition before that, and if this is one of your chosen users you wouldn’t run that line (see below for an example of a condition like this).

I’m away from my computer so I can’t test this, but I think this general idea would accomplish what you’re asking for:

Have experiment2 in a folder at the same level as experiment1:

experiment1/
    experiment1_lastrun.py
    experiment2/
        experiment2_lastrun.py

Add a routine at the end of experiment 1 with a code component:

exp2List = ['24', '68', '95']
# Find the name of the variable 
# holding the participant number,
# Careful about whether it's a string
# or number.
# Here I'll call it subj
if subj in exp2List:
    # switch to path of exp2 so data
    # saving data still works
    os.chdir('experiment2')
    # call the script
    execfile('experiment2_lastrun.py')

Of course, check my typing, again I’m doing this off the top of my head. Note that the “lastrun” script is generated automatically by the builder when you run, so if you make any changes in experiment 2 in the builder, you have to run it to update that file.

If I’m right, something like the above will call experiment 2 at the end of experiment 1. But again, this is kind of ugly design and it may come with side effects and some restrictions. For one, note that the dialog that collects subject info at the beginning of most builder experiments will run again (the one for experiment 2). If you wanted to have information from experiment 1 passed to and saved in experiment two, I again recommend the way I suggested earlier. You could pass info like the subject number as an argument to your experiment2 run function, and replace the code that presents the dialog. But of course, you’ll decide what you think is the most appropriate for your situation.

1 Like

Hi! I’m trying to compilate several experiments in one masters. I’ve followed these suggestions but I only can run the first experiment.
Here is the code in my “master” file:

import exp1.py
import exp2.py

exp1.run()
exp2.run()

I don’t need to save any data from one to another experiment.

Originally I have the experiment in PsychoPy.

Thanks!

How does exp1.run() terminate?

Hi. I’ ve commented core.quit () but i don’t know why it doesn’t work. When I run the exp2 first it work perfect. Thanks!

Hi, i’ve finally achieved to run two experiments from a master file. HOWEVER, I have to press OK (or cancel) in a message (where commonly info about participant, session, etc, is loaded). I would like that the second experiment run inmediatly, it is, avoiding any message. Anyone know how we can achieve it? Thanks!

That is only happening because your code is explicitly asking for a dialog to appear. Simply remove that code if it is not necessary. It will look something like this:

# Store info about the experiment session
expName = 'PsychoPy_Flip_mirror_question'  # from the Builder filename that created this    script
expInfo = {'participant':'', 'session':'001'}
dlg = gui.DlgFromDict(dictionary=expInfo, title=expName)
if dlg.OK == False:
    core.quit()  # user pressed cancel
expInfo['date'] = data.getDateStr()  # add a simple timestamp
expInfo['expName'] = expName

Exactly! I saw the script again and could identify that dialog box. However, when I comment that dialog box the computer desktop is showed between experiments. Anyone know how we can avoid that?
Thanks!!!

Presumably because what you are doing is sequentially running two lots of code that were originally designed to be executed in isolation. I’m guessing the main PsychoPy window gets closed at the end of your first function and then recreated at the beginning of the second.

If you want a seamless transition between the two, you would need to get your hands dirty by digging in to the code to preserve the window object across runs of the two functions.

Thanks!
By the moment, it is the best that I can achieve (we are relatively new in psychopy, and all member of my group are psychologists). I hope we can achieve a more elegant solution for future experiments. Here is the “partial” solution that we have achieved considering previous suggestions:

**************** previous experiment ****************
thisExp.abort() # or data files will save again on exit
win.close()
#core.quit()
**************** next experiment ****************
#dlg = gui.DlgFromDict(dictionary=expInfo, title=expName)
#if dlg.OK == False:

core.quit() # user pressed cancel

expInfo[‘date’] = data.getDateStr() # add a simple timestamp
expInfo[‘expName’] = expName

Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc

#filename = thisDir + os.sep + u’data/%s%s_%s’ % (expInfo[‘participant’], expName, expInfo[‘date’])
filename = thisDir + os.sep + u’data/%s%s’ % (expName, expInfo[‘date’])

As I mentioned, the computer desktop is showed between experiment. We couldn’t achieve how to keep psychopy open beetween experiments, so it is a partial solution. In case anyone can achieve, please, share that solution.

To carry-out a new experiment!