oTree Forum >

Preference order in dictator game

#1 by rionny

I was wondering if it was possible to create a preference order for multiple choice options, i.e. if there's three options for set monetary distributions, I want to know what they would choose for their first (most preferable choice) and their second (most preferable) choice. 

I think it's possible to use some kind of if function to create a pseudo second page for each of the possible choices - i.e. if choice A is chosen, it then displays a second page with just choice B and C, (and all other permutations) but I was hoping there's a simpler way.

Thank you in advance

#2 by BonnEconLab

If I understand you correctly, you would like them to sort alternatives like

(10, 0)
(8, 2)
(5, 5)
(2, 8)

into, say,

(5, 5)
(8, 2)
(10, 0)
(2, 8)

The easiest way would be, of course, to put a text field behind each option and let participants enter a number that represents the ranking. You could then ensure via JavaScript or oTree’s error that each number from 1 to 4 was entered only once.

Qualtrics offers a way to sort alternatives via drag-and-drop. You could implement this fairly easily with oTree, it seems to me, using jQuery: https://jqueryui.com/sortable/. All you need to add to the source code on https://jqueryui.com/sortable/ is a function that reads out the order of the elements after the drag-and-drop.

#3 by BonnEconLab

Here is some example code for the preference ranking via dragging alternatives into place to sort them vertically:


In __init__.py, include:


class SortAlternatives(Page):

    form_model = 'player'
    form_fields = ['preference_ranking']


Contents of the SortAlternatives.html template:


{{ block title }}

Survey

{{ endblock }}


{{ block content }}

<p>Please rank the following alternatives.</p>

<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<style>
  #sortable { list-style-type: none; margin: 0; padding: 0; width: 100%; }
  #sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; width: 500px !important;}
  #sortable li span { position: absolute; margin-left: -1.3em; }
</style>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
  var elements;
  function recordOrder() {
    elements = document.getElementsByName("preference-ranking");
    var ranking = []
    for (let i = 0; i < elements.length; i++) {
      ranking.push(elements[i].id);
    }
    document.getElementById("id_preference_ranking").value = "[" + ranking.toString() + "]";
  };
  $( function() {
    $( "#sortable" ).sortable();
  } );
</script>

<ul id="sortable" class="bg-light p-3 text-center">
  <li name="preference-ranking" id="[10, 0]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>€10 for you, €0 euro for your partner</li>
  <li name="preference-ranking" id="[8, 2]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>€8 for you, €2 euro for your partner</li>
  <li name="preference-ranking" id="[5, 5]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>€5 for you, €5 euro for your partner</li>
  <li name="preference-ranking" id="[2, 8]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>€2 for you, €8 euro for your partner</li>
  <li name="preference-ranking" id="[0, 10]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>€0 for you, €10 euro for your partner</li>
</ul>

{{ formfields }}

{{ next_button }}

<script>
  function recordOrderContinuously(){
    recordOrder();
    setTimeout(recordOrderContinuously, 100);
  }
  recordOrderContinuously();
</script>

{{ endblock }}


Of course, you can make the input field invisible, read only, etc. I am leaving it visible for debugging.

#4 by rionny

Hi,

Thanks so much for the quick response, and yes that would be exactly the kind of idea I was thinking about. Thank you so much for sending the code example too that will definitely help me a lot. Just as a follow up, unrelated question, I was also struggling with the logistics of creating a "profile" for the participants based on the answers to their questions. It would only really need to be basic, mainly just their nationality displayed next to their name (maybe as a predetermined icon since there's only two options anyway). 

Kind regards, and thank you again

#5 by rionny

Hi,
Sorry to bother again, but I was struggling with the rank order not getting saved. I was wondering if there was a problem with the code, or if there was something else I needed to add to make sure it worked properly.

#6 by BonnEconLab

As always, it is difficult to impossible to debug code without seeing it ...

I tested the code that I posted before I posted it, including whether it saves the resulting order in the database. The attached screenshot shows that it works as intended.

Maybe I should have mentioned that my method requires preference_ranking to be a StringField:

class Player(BasePlayer):

    preference_ranking = models.StringField()

#7 by rionny

from otree.api import *

class C(BaseConstants):
    NAME_IN_URL = 'distrubitiong'
    PLAYERS_PER_GROUP = 3
    NUM_ROUNDS = 1

class Subsession(BaseSubsession):
    pass

class SortAlternatives(Page):
    form_model = 'player'
    form_fields = ['preference_ranking']

class Group(BaseGroup):
    pass

class Player(BasePlayer):
    preference_ranking = models.StringField()
    pass

# PAGES
class SortAlternatives(Page):
    pass

class Results(Page):
    pass

page_sequence = [SortAlternatives, Results]
----------------
SortAlternatives page:


{{ block title }}
    Preference Order
{{ endblock }}
{{ block content }}
<p>You are the <strong>Decision Maker</strong>. Please rank the following alternatives.</p>

<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<style>
  #sortable { list-style-type: none; margin: 0; padding: 0; width: 100%; }
  #sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; width: 600px !important;}
  #sortable li span { position: absolute; margin-left: -1.3em; }
</style>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
  var elements;
  function recordOrder() {
    elements = document.getElementsByName("preference-ranking");
    var ranking = []
    for (let i = 0; i < elements.length; i++) {
      ranking.push(elements[i].id);
    }
    document.getElementById("id_preference_ranking").value = "[" + ranking.toString() + "]";
  };
  $( function() {
    $( "#sortable" ).sortable();
  } );
</script>

<ul id="sortable" class="bg-light p-3 text-center">
  <li name="preference-ranking" id="[2500, 3500, 3000]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>2500 for you, 3500 yen for your family friend, 3000 for unknown stranger</li>
  <li name="preference-ranking" id="[3000, 3000, 3000]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>3000 for you, 3000 yen for your family friend, 3000 for unknown stranger</li>
  <li name="preference-ranking" id="[4000, 3000, 3000]" class="ui-state-default btn"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>4000 for you, 3000 yen for your family friend, 3000 for unknown stranger</li>
</ul>

{{ formfields }}

{{ next_button }}

<script>
  function recordOrderContinuously(){
    recordOrder();
    setTimeout(recordOrderContinuously, 100);
  }
  recordOrderContinuously();
</script>


    {{ formfields }}
    {{ next_button }}

{{ endblock }}






Sorry to be a bother, and thanks for the help.

#8 by rionny

Apologies, just realized I'm a moron and put the class SortAlternatives(Page): twice, one with just pass. The code works perfect, thanks for your patience, I really appreciate it.

Kind regards,
Z

#9 by rionny

Hi, I'm sorry to bother again, but I was wondering if it was possible to track payoffs based on the order for the three players? I am really at a lost as to how to track for all three players, and how to track up the first choice from the rank order.

Write a reply

Set forum username