compute the average

192 views
Skip to first unread message

Ruggiero Rippo

unread,
Mar 17, 2021, 6:07:14 AM3/17/21
to oTree help & discussion
Hi there, 

I am trying to set up table where player inputs three numbers in three integerfields model. And then i would like to have a form where the average value of these 3 is computed.

So far I have in class player 

income1 = models.IntegerField(default = 0)
income2 = models.IntegerField(default = 0)
income3 = models.IntegerField(default = 0)

in Class page

form_model = 'player'
form_fields = ['income1',
'income2',
'income3',
]
def income_avgerage(self):
income_total = sum(self.player.income1, self.player.income2,
self.player.income3)
return income_total

But nothing happen

Thx!

Rok

unread,
Mar 17, 2021, 9:44:00 AM3/17/21
to oTree help & discussion

On the page where you want to display the average, add the function vars_for_template(), something like this:

class MyPage(Page):
  def vars_for_template(self):
    player = self.player
    average = (player.income1 + player.income2 + player.income3) / 3
    return dict(average_value = average)

Then in your HTML on that page, write {{ average_value }} where you want your average to appear.

Good luck,
Rok

Message has been deleted

Ruggiero Rippo

unread,
Mar 17, 2021, 9:51:06 AM3/17/21
to Rok, oTree help & discussion
Hi Rok,

Trying to use your suggestion but now i get this error

unsupported operand type(s) for +: 'NoneType' and 'NoneType'

My code 
class InstructionsA(Page):

form_model = 'player'
form_fields = ['income1',
'income2',
'income3',
]

   def is_displayed(self):
return self.round_number == 1

def vars_for_template(self):
player = self.player
average = (player.income1 + player.income2 + player.income3) / 3
return dict(average_value = average)


My html


<table class="table-bordered" style="width:100%">
<tr style="background-color:#ffb380">
<th scope="col" colspan="1" style="text-align:center"> Anno </th>
<th scope="col" colspan="1" style="text-align:center"> 2018 - 2019 </th>
<th scope="col" colspan="1" style="text-align:center"> 2019 - 2020 </th>
<th scope="col" colspan="1" style="text-align:center"> 2020 - 2021 </th>
<th scope="col" colspan="1" style="text-align:center"> MEDIA </th>

</tr>
<tr style="background-color:#ffe0cc">
<td scope="col" colspan="1" style="text-align:center"> Reddito/ettaro </td>
<td> <input type="number" name="income1" min="0" > €/ha</td>
<td> <input type="number" name="income2" min="0" > €/ha</td>
<td> <input type="number" name="income3" min="0" > €/ha</td>
<td> {{ average_value }} €/ha</td>
</tr>
</table>

---------------------------------------------------------------------------------------------------------------------------

Ruggiero Rippo 
Center Agriculture Food and Environment (C3A) & Department of Economics, University of Trento ||  


--
You received this message because you are subscribed to a topic in the Google Groups "oTree help & discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/otree/J_z7Siw16Ro/unsubscribe.
To unsubscribe from this group and all its topics, send an email to otree+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/otree/5bcde743-f1d7-48c7-aed4-413a4f3c94c6n%40googlegroups.com.

Rok

unread,
Mar 17, 2021, 9:53:03 AM3/17/21
to oTree help & discussion
Alternatively, you can make a method in Player that calculates the average:

def get_average(self):
  return (self.income1 + self.income2 + self.income3) / 3

You can call it in your HTML same as a variable: {{ player.get_average }}

Rok

Rok

unread,
Mar 17, 2021, 9:55:44 AM3/17/21
to oTree help & discussion
Are you trying to show the average value in real time, as the player fills out the form?

Rok

unread,
Mar 17, 2021, 9:59:35 AM3/17/21
to oTree help & discussion
You get the error above because you are trying to add together two variables that don't have a value yet. To fix the error you have to change 'default' to 'initial' in your value definitions in player, like: income1 = models.IntegerField(initial = 0)

Ruggiero Rippo

unread,
Mar 17, 2021, 10:03:04 AM3/17/21
to oTree help & discussion
Yes. The code work, but it displays just zero, and it does not change as i put the values in the formfields

Rok

unread,
Mar 17, 2021, 10:27:49 AM3/17/21
to oTree help & discussion
Yes, the code like that will not update in real time when you enter values. I thought you wanted to calculate the average and display it on one of the following pages.

If you want the value to calculate in real time you have to use javascript:


Rok

Ruggiero Rippo

unread,
Mar 17, 2021, 11:01:49 AM3/17/21
to oTree help & discussion
Thank you Rok it works wondefully. 

I do you think is possible than to store the output value? 

 Screenshot 2021-03-17 at 16.00.08.png
{% extends "global/Page.html" %}
{% load otree static %}

{% block title %}
{% endblock %}

{% block content %}
<h1>FASE 1 ISTRUZIONI</h1>
<h3>LE SUE OPINIONI SU I FUTURI REDDITI AD ETTARO DA MELE </h3>
<p />
<div class="w3-container border-top border-bottom">
<p> Assumendo che a Gennaio 2022 Lei sia un melicoltore con le seguenti caratteristiche:</p>
<ul>
<li> La sua area a melo è pari a ettari.</li>
<p />
<li> Ha sottoscritto la polizza multirischio Co.Di.Pr.A. Il premio pagato è di €/ha. </li>
<p />
<li> Il valore di mele assicurato è di €/ha. </li>
<p />
<li> I suoi costi (esclusi ammortamenti e costi per il personale) per la produzioni sono pari a €/ha.</li>
</ul>
</div>

<p />
<div class="w3-container border-bottom">
<h5> I suoi redditi ad ettaro nel triennio 2018 - 2021 e il suo reddito medio</h5>

<table class="table-bordered" style="width:100%">
<tr style="background-color:#ffb380">
<th scope="col" colspan="1" style="text-align:center"> Anno </th>
<th scope="col" colspan="1" style="text-align:center"> 2018 - 2019 </th>
<th scope="col" colspan="1" style="text-align:center"> 2019 - 2020 </th>
<th scope="col" colspan="1" style="text-align:center"> 2020 - 2021 </th>
<th scope="col" colspan="1" style="text-align:center"> MEDIA </th>
</tr>
<tr style="background-color:#ffe0cc">
<td scope="col" colspan="1" style="text-align:center; width: 160px;"> Reddito/ettaro </td>
<td> <input class="income_input" id="income1" type="number" name="income1" min="0" > €/ha</td>
<td> <input class="income_input" id="income2" type="number" name="income2" min="0" > €/ha</td>
<td> <input class="income_input" id="income3" type="number" name="income3" min="0" > €/ha</td>
<td> <span id="average_span"></span> €/ha</td>
</tr>
</table>
<script>window.onload = init_average();

function init_average(){
avg_span = document.getElementById("average_span");
income1 = document.getElementById("income1");
income2 = document.getElementById("income2");
income3 = document.getElementById("income3");

document.querySelectorAll('.income_input').forEach(item => {
item.addEventListener('change', event => {
sum_incomes = get_input_value(income1) + get_input_value(income2) + get_input_value(income3);
avg_span.innerHTML = parseFloat(sum_incomes / 3).toFixed(2);
})
})

}

function get_input_value(input){
if(input.value == ''){
return 0;
}
else {
return parseFloat(input.value);
}
}</script>

<ul>
<p />
<li> Il reddito medio è calcolato considerando i ricavi della vendita delle Mele al netto dei costi
(costi che come da Regolamento IST, considerano i costi di produzione diretti, escludendo ammortamenti e personale)</li>
</ul>
</div>
<p />
{% next_button %}

{% endblock %}


Ruggiero Rippo

unread,
Mar 17, 2021, 12:25:26 PM3/17/21
to oTree help & discussion
Hoping this can be useful for everybody.

First of all thx to Tom and Rok. 
Second, I manage to keep code simple and clean.  In the way I present below, in your html you will see the average as soon as you'll input values in the formfield. Then when moving on the next page, otree will quietly compute the average and store the same result (I rounded it to second digit) in your database. 

class Instructions(Page):

form_model = 'player'
form_fields = ['income1',
'income2',
'income3',
]

def is_displayed(self):
return self.round_number == 1

def before_next_page(self):
self.player.avginc = statistics.mean([self.player.income1, self.player.income2,self.player.income3])
self.player.avginc = round(self.player.avginc,2)

class Results(Page):
pass

page_sequence = [Instructions, Results]

In Template 

{% extends "global/Page.html" %}
{% load otree static %}

{% block title %}
{% endblock %}

{% block content % }
<table>
<tr style="background-color:#ffe0cc">
<td scope="col" colspan="1" style="text-align:center; width: 160px;"> Reddito/ettaro </td>
<td> <input class="income_input" id="income1" type="number" name="income1" min="0" > €/ha</td>
<td> <input class="income_input" id="income2" type="number" name="income2" min="0" > €/ha</td>
<td> <input class="income_input" id="income3" type="number" name="income3" min="0" > €/ha</td>
<td> <span id="avginc" ></span> €/ha</td>

</tr>
</table>
<script>window.onload = init_average();

function init_average(){
avginc = document.getElementById("avginc");

income1 = document.getElementById("income1");
income2 = document.getElementById("income2");
income3 = document.getElementById("income3");

document.querySelectorAll('.income_input').forEach(item => {
item.addEventListener('change', event => {
sum_incomes = get_input_value(income1) + get_input_value(income2) + get_input_value(income3);
avginc.innerHTML = parseFloat(sum_incomes / 3).toFixed(2);

})
})

}

function get_input_value(input){
if(input.value == ''){
return 0;
}
else {
return parseFloat(input.value);
}
}
</script>

<ul>
<p />
<li> Il reddito medio è calcolato considerando i ricavi della vendita delle Mele al netto dei costi
(costi che come da Regolamento IST, considerano i costi di produzione diretti, escludendo ammortamenti e personale)</li>
</ul>
</div>
<p />
{% next_button %}


{% endblock %}

Rok

unread,
Mar 17, 2021, 3:22:26 PM3/17/21
to oTree help & discussion
Glad you got it working. :)

I just noticed, if you want to make your average calculation even more responsive, you can add another event listener, like this:

  document.querySelectorAll('.income_input').forEach(item => {
    item.addEventListener('change', event => {
    sum_incomes = get_input_value(income1) + get_input_value(income2) + get_input_value(income3);
  avg_span.innerHTML = parseFloat(sum_incomes / 3).toFixed(2);
    })
    item.addEventListener('keyup', event => {
    sum_incomes = get_input_value(income1) + get_input_value(income2) + get_input_value(income3);
  avg_span.innerHTML = parseFloat(sum_incomes / 3).toFixed(2);
    })
  })

Reply all
Reply to author
Forward
0 new messages