Forms
Submitting information
- Each page in oTree can contain a form
- The player fills with some value and then submits it
- Cardinal values
- Integer, Float
- Ordinal values
- Integer, Categorical
- Text
- Strings of numbers and letters
- Cardinal values
- The player fills with some value and then submits it
- Several formats to collect values
- Open fiels
- Buttons
- Radio buttons
- Dropdown lists
- …
Basic structure of forms
- First create fields in models.py
- As an example, if you want to collect name and age
class Player(BasePlayer):
name = models.StringField(label="Your name:")
age = models.IntegerField(label="Your age:")
- Then in pages.py, you will create a class
class Anag(Page):
form_model = 'player'
form_fields = ['name', 'age'] # saved as player.name, player.age
- Finally, in the template Anag.html the form will be displayed with
- To display the forms separately
Input formats
Examples
- In the following examples the participant receives a random number
- The participant is asked to report features of the number
- Several input interfaces are presented
- Radio
- Button
- Checker
- Dropdown
- Radio Sequence
- Text
- Value
- Tabular
- Several input interfaces are presented
Radio
Setting up an individual decision-making task
Our task
- First we investigate individuals’ risk attituted
- Multiple Price List questionnaire (Holt and Laury 2002)
- Trade-off between lotteries
- Multiple Price List questionnaire (Holt and Laury 2002)
- Second we collect pieces of demographic information
- Age,gender, …
Screens
Instructions
Choices
Outcomes
Final questionnaire
Code
models.py
- Define session constants
- Outcomes of lotteries in MPL
class Constants(BaseConstants):
name_in_url = 'MPL'
players_per_group = None
num_rounds = 1
# these are the lottery payoffs, f1 and f2 refer to lottery A and f3 and f4 to lottery B
f1 = 2.00
f2 = 1.60
f3 = 3.85
f4 = 0.10
- Group and Subsession are empty
- Typical of one-shot individual decision making
models.py (ii)
- In Player class we define the “templates” for data collection
- MPL table
class Player(BasePlayer):
# This is for main choices, each variable is one row in the choice table MPL
HL_1 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_2 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_3 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_4 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_5 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_6 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_7 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_8 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_9 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
HL_10 = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
# This is needed for the instructions
HL = models.PositiveIntegerField(choices=[[1, 'A'],[2, 'B']],widget=widgets.RadioSelectHorizontal)
# These variables are collected in the final questionnaire
sex = models.StringField(widget=widgets.RadioSelectHorizontal(),choices=['Male', 'Female'])
age = models.IntegerField(choices = range(18,60,1))
comment = models.TextField(label="Your comment here:")
like = models.IntegerField(choices=[1,2,3,4,5],widget=widgets.RadioSelectHorizontal)
models.py (iii)
- In Player class we compute the payoffs
- Typical of individual decision making
"""
... continue
"""
# Define here the methods associated to Players
# this method is needed to compute payoffs
def set_payoff_HL(self):
#*******************************************
# select random row and random outcome
#*******************************************
self.participant.vars['HL_row'] = random.randint(1,10)
# select one row randomly for payment (from module random)
self.participant.vars['HL_random'] = random.randint(1,10)
# select the number x that defines the outcome of the lottery (if x<=p, outcome is left f1 or f3, otherwise f2 or f4)
# write it to participant.vars['HL_random']
#*******************************************
# select choices in correspondence to random row
#*******************************************
choices = [self.HL_1,self.HL_2,self.HL_3,self.HL_4,self.HL_5,self.HL_6,self.HL_7,self.HL_8,self.HL_9,self.HL_10]
# create a list with all choices of the player (see self)
self.participant.vars['HL_choice'] = choices[self.participant.vars['HL_row']-1]
# select from the list the choice in correspondence to the randomly drawn row (notice the offset)
# write it to participant.vars['HL_choice']
#*******************************************
# Compute here the payoffs
#*******************************************
if self.participant.vars['HL_random'] <= self.participant.vars['HL_row']:
# if the random number is smaller equal than the random row
if self.participant.vars['HL_choice'] == 1: #A
# if the choice was A
self.participant.vars['payoff_HL'] = Constants.f1
# because HL_row is the same as p in the MPL
else :
# if the choice was B
self.participant.vars['payoff_HL'] = Constants.f3
else:
# if the random number is slarger than the random row
if self.participant.vars['HL_choice'] == 1 :#A
# if the choice was A
self.participant.vars['payoff_HL'] = Constants.f2
# because HL_row is the same as p in the MPL
else :
self.participant.vars['payoff_HL'] = Constants.f4
self.payoff = self.participant.vars['payoff_HL']
# write the payoff to player.payoff
pages.py
- In the instructions we need this because we have a simulation of choice protocol
- In the main choice page we need to import a for for each row of the MPL table
- We also need the outcomes, retrieved from constants
- Important to “declare” the variables to display with vars_for_template()
class PageHL(Page):
# which forms are needed from class player
form_model = 'player'
form_fields = ['HL_1','HL_2','HL_3','HL_4','HL_5','HL_6','HL_7','HL_8','HL_9','HL_10'] # all 10 options
# values that are to be displayed (dictionary)
def vars_for_template(self):
# retrieve values from constants and store them in a dictionary
return{
'f1':Constants.f1,
'f2':Constants.f2,
'f3':Constants.f3,
'f4':Constants.f4
}
pages.py (ii)
- Before moving to the next page, we compute payoffs
- See method set_payoff_HL() from models.py
- This way we compute payoffs only once and not when browser is refreshed
pages.py (iii)
- Display outcomes
- declare them with vars_for_template()
- retrieve values from participant.vars and “store” them in a dictionary
- declare them with vars_for_template()
class OutcomeHL(Page):
# values needed to inform subjects about the actual outcome
def vars_for_template(self):
# retrieve values from participant.vars and store them in a dictionary
return{
'payoff_HL': self.player.participant.vars['payoff_HL'],#payoff
'row': self.player.participant.vars['HL_row'], # randomly chosen row
'value': self.participant.vars['HL_random'],# randomly chosen value to define outcome
'choice': self.participant.vars['HL_choice'],# actual choice
# outcomes of the selected row
'p_A_1': self.participant.vars['HL_row'],
'p_A_2': 10-self.participant.vars['HL_row'],
'p_B_1': self.participant.vars['HL_row'],
'p_B_2': 10-self.participant.vars['HL_row']
}
pages.py (iv)
- Forms in the final questionnaire retrieved from class player in models.py
class Anag(Page):
# forms to retrieve individual information
form_model = 'player'
form_fields = ['comment','like','sex','age']# player.comment, player.like, ...
- Manage the sequence of pages
Templates
Instructions
- Style elements
- size of radio buttons
Instructions.html
- Style elements
- size of radio buttons
Instructions.html (ii)
- Main body and demo of MPL
- In a bs container
{% block content %}
<h1>Instructions</h1>
<div class="container p-3 my-3 border" style="font-size:18pt">
<h2> Part 1 </h2>
<p>In the firt part of the experiment you are going to choose between couples of lotteries. </p>
<p>The following is an example of the decision setting you are facing</p>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col" colspan="2" style="text-align:center">A</th>
<th scope="col" ></th>
<th scope="col" colspan="2" style="text-align:center">B</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td > p/10 of €A<sub>1</sub> </td>
<td> (1-p)/10 of €A<sub>2</sub></td>
<td style="font-weight: bold">{{ form.HL }}</td>
<td>p/10 of €B<sub>1</sub></td>
<td >(1-p)/10 of €B<sub>2</sub> </td>
</tr>
</tbody>
</table>
<p>You must choose between lottery A and lottery B, with lottery A delivering €A<sub>1</sub> with probability p/10 and €A<sub>2</sub> with probability (1-p)/10.</p>
<p>Similarly, lottery B delivers €B<sub>1</sub> with probability p/10 and €B<sub>2</sub> with probability (1-p)/10.</p> <p>You will face 10 choices between A and B, with p changing across choices.</p>
<p>All your earnings are virtual, no cash is going to be paid to you. However, choose as if the monetary stakes were real.</p>
</div>
<div class="container p-3 my-3 border" style="font-size:18pt">
<h2> Part 2 </h2>
<p>In the second part of the experiment you are asked to report some information about you.</p>
</div>
Instructions.html
- The button to leave the page
- Put it to the right with a container
"""
[...]
"""
<div class="container" style="font-size:18pt">
<div class="row">
</div>
<div class="row" style="padding-left:135px;">
<div class="col-md-10">
</div>
<div class="col-md-2">
<button name="btn_submit" value="True" class="btn btn-primary btn-large">
<span style="font-size:18pt">Continue</span>
</button>
</div>
</div>
</div>
</body></html>
{% endblock %}
How to run and test your app
settings.py
- Add your app to the list SESSION_CONFIGS
- Description of the app is in a dictionary
- You can set here other parameters (e.g., treatment) that can be then accessed with session.config
- Description of the app is in a dictionary
Start a you app
- Move to your oTree folder with the terminal (usually cd ~/oTree/)
- give the command otree devserver
- copy and paste the url http://localhost:8000/ into you browser
- You will get the following window
Test your app
- To test your app and debug just click on the name of the app
- This creates a number of links (clients) equal to the value in ‘num_demo_participants’ in settings
- Click on the link to open a client
- When a number of clients equal to ‘num_demo_participants’ is open you can start your session
Run a session
- To run a session with N participants
- Click on Sessions in the top bar menu
Click on Create new session
Run a session (ii)
- Choose you app
- Configure your settings
- e.g., number of participants
- Click on create
- You will get a number of links equal to number of participants that you can distribute to your clients
- Configure your settings
Download your data
- To download your data go tp data in the top bar menu
- Click on You can download data in Excel or CSV format here. to download data in an open format
- You can download data for all your apps or separately for each app
Thank you
🦁
To contact me just write me an email
or write me on the forum of the course
Appendix
Assignment
- Easy
- Add a field to the final questionnaire
- Nationality
- Add a field to the final questionnaire
- Less easy
- Change the protocol of the MPL
- Instead of a choice for each row, participants report only the row in which they switch from A to B
- e.g., the sequence AAAAABBBBB become 6
- Change the protocol of the MPL
References
Holt, Charles A, and Susan K Laury. 2002. “Risk Aversion and Incentive Effects.” American Economic Review 92 (5): 1644–55.