Session V - oTree Introduction & Individual Experiments
IMPRS Be Smart Summer School
2023-08-08



Using a text editor
oTree studio (https://www.otreehub.com/)


(my suggestion)
ot (or your project name)
├── oTree
│ ├── app1
│ ├── app2
│ ├── ...
└── venv
ot: A container folderoTree: oTree software (project folder)venv: Virtual Environmentot| Command | Windows | MacOS/Linux |
|---|---|---|
| print current location | pwd |
cd |
| list files here | dir |
ls |
| go to directory | cd NAME |
cd NAME |
| create directory | mkdir NAME |
mkdir NAME |
| delete file | del filename |
rm filename |
| activate virtual env. | PATH\Scripts\activate |
source PATH\bin\activate |
| deactivate virtual env. | deactivate |
deactivate |
| run oTree server (dev.) | otree devserver |
otree devserver |
| create app | otree startapp APPNAME |
otree startapp APPNAME |
Make sure you have your virtual environment activated
Make sure you are in the oTree (project) folder
Create the app
In our case we will use the name my_survey:
Go to settings.py
Modify SESSION_CONFIGS as below

settings.py: oTree settings filemy_survey folder: the app in our oTree project. We apps on our own.
__init__.py: Backend components (pages and models)*.html: Frontend components (templates)__init__.py looks like?The simplest experiment is a survey experiment
We ask some questions and collect the answers
Usually we only need only Player and Constants classes
name)age)continent)enjoyment)comments)(Assume we created the project and the app)
__init__.py)__init__.py)page_sequence (in __init__.py)Player model (in __init__.py in app folder)
__init__.py in app folder)
page_sequence (in __init__.py in app folder)
| Variable | Field Type |
|---|---|
name |
StringField |
age |
IntegerField |
continent |
StringField |
enyjoyment |
IntegerField |
comments |
LongStringField |
Player class__init__.py| Field Name | What for? | Example |
|---|---|---|
| StringField | Short text, Categories | department = Models.StingField() |
| IntegerField | Integer (whole numbers) | age = Models.IntegerField() |
| FloatField | Decimals | percentage = Models.FloatField() |
| BooleanField | True or False | is_dictator = Models.BooleanField() |
| CurrencyField | Numbers in currency format | earned_stage1 = Models.CurrencyField() |
| LongStringField | Long test | diary_entry = Models.LongStringField() |
label: The label of the fieldmin and max: The minimum and maximum values for the fieldblank: Empty field allowed or notinitial: Default value for the fieldchoices: Multiple choices for the field| Page | Description |
|---|---|
Survey |
Survey questions |
Results |
Feedback. Thanks etc |
__init__.pypage_sequence listhtml template in the same folderTemplates use HTML codes, and oTree template items (indicated by {{ }}).
Indentation is not important in templates.
oTree has two default blocks:{{ block title }}, and {{ block content }}
You can reach variables of the player with {{ player.variablename }}
You can have conditional content by {{ if CONDITION }}
Now we will build a simple interactive experiment.
We will ask participants two options:
| Page | Description |
|---|---|
Choice |
Choice between risky and safe options |
Results |
Feedback. Thanks etc |
| Variable | Description |
|---|---|
wants_risky |
Whether the player wants the risky option or not |
is_lucky |
If the player won the lottery or not |
| Variable | Place | Type |
|---|---|---|
wants_risky |
Player class |
BooleanField() |
is_lucky |
Player class |
BooleanField |
RISKY_PAYOFF |
C class (Constants) |
integer |
SAFE_PAYOFF |
C class (Constants) |
integer |
Let’s implement those at first. We will deal later with the payoffs.
set_payoffs is a common name.player object as input and set the payoffs of the player.player.fieldnameplayer.payoff which we can use to set the payoff of the playerWe need to call the set_payoffs function at some point.
One option is to call it at the end of the Choice page.
We can do this by using the before_next_page() function (method).
This can defined in the Choice class. If it is defined, it will be called before the next page is loaded.
It takes two arguments: player and timeout_happened
Results.htmlRemember that we can conditionally show participants different content.
{{ if player.wants_risky_choice }}
You chose the risky option
{{ else }}
You chose the safe option
{{ endif }}