Getting Started

Gotchas

  • otree-redwood currently only works with python3 and Google Chrome. We have long term plans to add support for other browsers, but for now only google chrome will work correctly

  • Redwood has not been tested on Windows. There’s no reason it shouldn’t work, but you may have some troubles, particularly with the virtual environment

    • Consider using the Windows Subsystem for Linux. This will give you an Ubuntu-like environment on Windows and may make installation easier. You can find instructions for that on the Microsoft website here
  • If you see an error that looks like error: Python.h: No such file or directory, you need to install the Python development libraries. These should be included on OS X. On Linux, you can install them with your package manager, for example:

    sudo apt-get install python3-dev
    
  • If your Redwood experiment generates a large number of messages, you may get warnings from oTree about sqlite running out of connections. The solution to this problem is to use a fully featured database such as Postgres. Instructions for integrating Postgres with oTree can be found in the oTree docs

Installing otree-redwood

  1. (Optional) Create and activate a python virtual environment to manage otree’s python dependencies:
python3 -m venv venv
source venv/bin/activate

Virtual environments allow you to isolate your project’s dependencies from your main python installation. Read more about virtual environments here

  1. Use pip to install the otree-redwood library and the LEEPS fork of otree-core:
pip install otree-redwood git+https://github.com/leeps-lab/otree-core
  1. Start a new oTree project:
otree startproject oTree
cd oTree
  1. Save current versions of all dependencies in a requirements file so they can be quickly installed later:
pip freeze > requirements_base.txt

You can reinstall these dependencies later with

pip install -r requirements_base.txt
  1. Update INSTALLED_APPS and EXTENSION_APPS in your settings.py
...
INSTALLED_APPS = ['otree', 'django_extensions']
EXTENSION_APPS = ['otree_redwood']
...
  1. Create a new oTree experiment:
otree startapp my_experiment
  1. Use the otree-redwood classes in your experiment’s models.py file:

Instead of extending otree.api.BaseGroup, your Group class extends one of the otree-redwood Groups - Base Group or DecisionGroup. Your Group class needs a period_length function. This is similar to oTree’s timeout_seconds variable. When the period timer expires players will be automatically moved to the next page.

You still extend otree.api.BasePlayer, but your Player class needs an initial_decision function. This is the decision the player starts with. You can let the player choose their initial decision with a normal oTree page.

from otree_redwood.models import Event, DecisionGroup

class Group(DecisionGroup):

  def period_length(self):
    return Constants.period_length

class Player(BasePlayer):

  def initial_decision(self):
    return 0.5
  1. Use the otree-redwood web components in one of your experiments HTML templates.

Make sure your template inherits from “otree_redwood/Page.html” instead of the usual “global/Page.html”. This is required for the otree-constants webcomponent to work correctly.

An example minimal otree_redwood template:

{% extends "otree_redwood/Page.html" %}

{% block scripts %}
  <!-- Import the redwood-decision and redwood-period webcomponents. -->
  <link
    rel="import"
    href="/static/otree-redwood/webcomponents/redwood-decision/redwood-decision.html">
  <link
    rel="import"
    href="/static/otree-redwood/webcomponents/redwood-period/redwood-period.html">

  <script>
    // Get the decision component and other-decision element.
    var decision = document.querySelector("redwood-decision");
    var otherDecision = document.getElementById("other-decision");

    // Log period start/end to the JavaScript console.
    document.querySelector("redwood-period").addEventListener('period-start', function(event) {
      console.log('period started');
    });
    document.querySelector("redwood-period").addEventListener('period-end', function(event) {
      console.log('period ended');
    });

    // When group decisions changes, update the text of the otherDecision element.
    decision.addEventListener('group-decisions-changed', function(event) {
      otherDecision.innerText = decision.otherDecision;
    });

    // Attach this to a button onclick event to set your decision when the button is clicked.
    function setDecision(d) {
      decision.myDecision = d;
    }
  </script>
{% endblock %}

{% block content %}
  <!-- Include the components on the page -->
  <redwood-period></redwood-period>
  <redwood-decision></redwood-decision>

  <p>Other Decision: <span id="other-decision"></span></p>

  <button type="button" onclick="setDecision(0)">Decision=0</button>
  <button type="button" onclick="setDecision(1)">Decision=1</button>
{% endblock %}