oTree Forum >

Narrow data format in Otree

#1 by thaicao (edited )

Dear all, 

In my experiment, I want to conduct a multi-armed bandit task where participants can sample values of different distributions by clicking on the respective buttons as long as they want. For each click, I want to record the id of the button and the values generated from the options. However, my code only records the id and value from the last click (see code). Because there is no restriction on the number of samples so I can't create a player field for each sample. Is there any way to have a narrow data format where each row of the dataset record the id and value of a sample/button click? I'm very new at Otree and programming, so I'm very grateful for any suggestions. 

Python code:
# CLASSES
class C(BaseConstants):
    NAME_IN_URL = 'Arm5'
    PLAYERS_PER_GROUP = None
    NUM_ROUNDS = 1
    BANDIT_ARMS = 3
    BANDIT_MU = (5.1, 5.2, 5.3)
class Subsession(BaseSubsession):
    pass
class Group(BaseGroup):
    pass
class Player(BasePlayer):
    value = models.FloatField()
    arm = models.IntegerField()

# FUNCTIONS
def custom_export(players):
    yield ['participant_code', 'id_in_group'] 
    for p in players:
        pp = p.participant
        yield [pp.code, p.id_in_group]

# PAGES
class Bandit(Page):
    form_model = 'player'
    @staticmethod
    def live_method(player: Player, data):        
        import random
        player.arm = data
        mu = C.BANDIT_MU[data]
        player.value = round(random.uniform(mu -5, mu +5),2)
        response = dict(arm = player.arm, value = player.value)
        return {player.id_in_group: response}
HTML:  
<body>
    <input id="1" type="button" value ="1" onclick="sendValue(this.id)" > Option 1 </input> 
    <input id="2" type="button" value="2" onclick="sendValue(this.id)" > Option 2 </input>
    <input id="3" type="button" value="3" onclick="sendValue(this.id)" > Option 3 </input>
    <div>Value of option </div> <div id="output"></div>
</body>

<script>  
  // Get a reference to the output element
  const outputElement = document.getElementById("output");

  // send the value of the option being clicked to python code
  function sendValue(clicked){
    liveSend(parseInt(document.getElementById(clicked).value))
  }
  // Sending the random value from python to page
  function liveRecv(data){
    outputElement.innerHTML = data.arm + " is " + data.value
  }
  // Hide the new value after 3 seconds
  setTimeout(function() {
    outputElement.innerHTML = "";
  }, 3000)
</script>

#2 by thaicao

I found a solution in case anyone has the same problem:
- create a player string field to contain the repeated trials
class Player(BasePlayer):
    ...
    seq_value = models.LongStringField(initial= "") # record the sequence of values sampled
    seq_arm = models.LongStringField(initial= "") # record the sequence of arms sampled
- append the new data into the blank string field every time a button is pressed using live_method
class Bandit(Page):
    form_model = 'player'
    @staticmethod
    def live_method(player: Player, data): 
    ...
    player.seq_value += ";" + str(player.value) # append the sampled value to the sequence
       player.seq_arm += ";" + str(player.arm)

Write a reply

Set forum username