oTree Forum >

Dynamically assign player variables based on round number from CSV

#1 by ckormylo

Hi all - 

I have a 20 round game where each round I must assign a "price movement" and a "suggested investment amount". There are 500 different variations of these 20 rounds so I have them in a CSV file with columns "ID", "Round", "PriceMovement", "SuggInvest". On the results screen I have a chart that plots the price movement dynamically. So in Round 1, it has 1 data point and in Round 5 it has 5 data points. 

I am currently setting 20 different player variables, r1 = models.FloatField(), r2 = models.FloatField... etc. 

Then I have a function that triggers as below: 

def set_values(player):
     subsession = player.subsession
     round = player.round_number
     
     for i in range(1, round + 1):
          exec(f"player.r{i} = price_dict[i]")

Finally, the html generates the graph via: 
<script>
    google.charts.load('current', {packages: ['corechart', 'line']});
    google.charts.setOnLoadCallback(drawBasic);

    function drawBasic() {
        var data = new google.visualization.DataTable();
        data.addColumn('number', 'Round');
        data.addColumn('number', 'Price');

        var roundNumber = {{ subsession.round_number }};

        data.addRows([
            [0, 100],
            [1, {{ player.r1 }}],
            [2, {{ player.r2 }}],
            [3, {{ player.r3 }}],
            [4, {{ player.r4 }}],
            [5, {{ player.r5 }}],
            [6, {{ player.r6 }}],
            [7, {{ player.r7 }}],
            [8, {{ player.r8 }}],
            [9, {{ player.r9 }}],
            [10, {{ player.r10 }}],
            [11, {{ player.r11 }}],
            [12, {{ player.r12 }}],
            [13, {{ player.r13 }}],
            [14, {{ player.r14 }}],
            [15, {{ player.r15 }}],
            [16, {{ player.r16 }}],
            [17, {{ player.r17 }}],
            [18, {{ player.r18 }}],
            [19, {{ player.r19 }}],
            [20, {{ player.r20 }}]
        ].slice(0, roundNumber + 1));

        var options = {
            hAxis: { title: 'Round', minValue: 0, maxValue: 20, multiples: 1, gridlines: { count: 20 }},
            vAxis: { title: 'Price'},
            title: 'Asset Price'
        };

        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
    }
</script>

In the function set_values(), I call a dictionary "price_dict" which would ideally come from reading the CSV file, picking a random "ID" which would pull 20 rows from the CSV file that all have that ID, and then create a dictionary from those rows that includes key:value pairs like "Round:PriceMovement" (e.g., {1:45.7, 2:14.2, 3:108.9...}. That is the part I am struggling with. I read through the documentation on reading CSV files and possibly using an ExtraModel class but nothing I've tried has worked. Any tips or example games that do this? I tried finding the Stroop task as the documentation suggested but I couldn't find any that utilize a CSV.

#2 by ckormylo

I think I may have figured it out. Instead of using dictionaries, I just assign all asset change variables (a1-a20) in the creating_session function. The HTML code slices the data on round number anyways so I realized there's no reason I can't assign all 20 rounds from the get go. There may be a more efficient way to do this but for now it seems to work. See code below. 
**********************************
class Constants(BaseConstants):
    name_in_url = 'Game'
    players_per_group = None
    num_rounds = 20


class Subsession(BaseSubsession):
    pass


def creating_session(subsession: Subsession):
    import csv

    f = open(__name__ + '/MarketData.csv')

    reader = list(csv.DictReader(f))
    players = subsession.get_players()
    for i in range(len(players)):
        import random
        player = players[i]
        random_id = random.randint(1, 275)
        filtered_data = [row for row in reader if row['ID'] == str(random_id)]
        for j in range(1, Constants.num_rounds + 1):
            exec(f"player.r{j} = float(filtered_data[{j - 1}]['AssetChange'])")

class Group(BaseGroup):
    pass


class Player(BasePlayer):
    r1 = models.FloatField()
    r2 = models.FloatField()
    r3 = models.FloatField()
    r4 = models.FloatField()
    r5 = models.FloatField()
    r6 = models.FloatField()
    r7 = models.FloatField()
    r8 = models.FloatField()
    r9 = models.FloatField()
    r10 = models.FloatField()
    r11 = models.FloatField()
    r12 = models.FloatField()
    r13 = models.FloatField()
    r14 = models.FloatField()
    r15 = models.FloatField()
    r16 = models.FloatField()
    r17 = models.FloatField()
    r18 = models.FloatField()
    r19 = models.FloatField()
    r20 = models.FloatField()

Write a reply

Set forum username