Blame view

flaskr/templates/estimation.html 10.7 KB
d01e2cc2   Antoine Goutenoir   Add the template ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% extends "base.html" %}


{% block title %}Estimation {{ estimation.public_id }} of your ✈ travel footprint{% endblock %}


{% block hero %}
<div class="jumbotron">
{% if estimation.has_failed() %}
    <h1>{{ content.estimation.failure.hero.title | safe }}</h1>
    <p>{{ content.estimation.failure.hero.description | markdown | safe }}</p>
{% else %}
    <h1>{{ content.estimation.hero.title | safe }}</h1>
    <p>{{ content.estimation.hero.description | markdown | safe }}</p>
{% endif %}
</div>
{% endblock %}



39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{% macro render_cities(cities) %}
<ul class="numbered-list">
{% for city in cities %}
    <li>
        <span class="city-name" title="{{ city.address }}">
    {% if loop.first %}
        <strong>
        {{ city.city }}
        </strong>
    {% else %}
        {{ city.city }}
    {% endif %}
        </span>
        –
        {{ "%.d" | format(city.footprint | round(0) | int) }} CO<sub>2</sub><small>EQ</small>
    </li>
{% endfor %}
</ul>
{% endmacro %}


d01e2cc2   Antoine Goutenoir   Add the template ...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{% block body %}
<h2>
    {{ estimation.public_id }} ({{ estimation.status.name }})
</h2>
{% if estimation.errors or estimation.warnings %}
<div class="row">
{% if estimation.warnings %}
    <div class="col-md-6 alert-warning card">
        <div class="card-body">
            <h3 class="card-title">Warnings</h3>
            <pre>
{{ estimation.warnings }}
            </pre>
        </div>
    </div>
{% endif %}
{% if estimation.errors %}
    <div class="col-md-6 alert-danger card">
        <div class="card-body">
            <h3 class="card-title">Errors</h3>
            <pre>
{{ estimation.errors }}
            </pre>
        </div>
    </div>
{% endif %}
</div>
{% endif %}
f3694728   Antoine Goutenoir   Display a summary.
70

f3694728   Antoine Goutenoir   Display a summary.
71

39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
72
73
<div class="row">
    <h4>Total CO<sub>2</sub> footprint (in grams-equivalent) of each city</h4>
b7411dd3   Antoine Goutenoir   Improve the plots...
74
    <div id="cities_footprints_d3viz" class="plot-container"></div>
30f014d5   Antoine Goutenoir   Add a lollipop pl...
75
    <hr>
b7411dd3   Antoine Goutenoir   Improve the plots...
76
    <div id="cities_footprints_d3viz_lollipop" class="plot-container"></div>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
77
78
79
80
81
82
83
84
85
{#    <br>#}
{#    <p>A Legend here</p>#}
</div>

<hr>

<div class="row">

{% if not estimation.has_failed() %}
30f014d5   Antoine Goutenoir   Add a lollipop pl...
86
{#{% set estimation_output = estimation.get_output_dict() %}#}
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
87
88
{% if estimation.has_many_to_many() %}
    <div class="col-md-6">
f3694728   Antoine Goutenoir   Display a summary.
89
    <p>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
90
        For each destination city, the sum of the travels from all the origins.
f3694728   Antoine Goutenoir   Display a summary.
91
    </p>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
92
93
94
95
96
97
98
    {{ render_cities(estimation_output.cities) }}
    </div>
{% else %}
    <div class="col-md-6">
    <p>
        Carbon footprint for each city.
    </p>
30f014d5   Antoine Goutenoir   Add a lollipop pl...
99
    {{ render_cities(estimation_output.cities) }}
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
100
    </div>
f3694728   Antoine Goutenoir   Display a summary.
101
102
{% endif %}

d01e2cc2   Antoine Goutenoir   Add the template ...
103
    <div class="col-md-6">
490282b4   Antoine Goutenoir   Fix the download ...
104
105
106
107
108
109
110
        <ul class="nav">
            <li class="nav-item m-4">
                <a href="/estimation/{{ estimation.public_id }}.csv" class="btn btn-lg btn-primary">
                    Download CSV
                </a>
            </li>
            <li class="nav-item m-4">
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
111
112
                <a href="/estimation/{{ estimation.public_id }}.yml" class="btn btn-lg btn-warning">
                    Download Raw YAML
490282b4   Antoine Goutenoir   Fix the download ...
113
114
                </a>
            </li>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
115
116
117
118
119
120
121
122
123
124
{#            <li class="nav-item m-4">#}
{#                <a href="/estimation/{{ estimation.public_id }}.xls" class="btn btn-lg btn-secondary disabled">#}
{#                    Download XLS#}
{#                </a>#}
{#            </li>#}
{#            <li class="nav-item m-4">#}
{#                <a href="/estimation/{{ estimation.public_id }}.ods" class="btn btn-lg btn-secondary disabled">#}
{#                    Download ODS#}
{#                </a>#}
{#            </li>#}
490282b4   Antoine Goutenoir   Fix the download ...
125
        </ul>
d01e2cc2   Antoine Goutenoir   Add the template ...
126
    </div>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
127

d01e2cc2   Antoine Goutenoir   Add the template ...
128
</div>
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
129
130
131
132
133
134
135
136
137
138
139

<hr>

{#<div class="row">#}
{#    <div class="col-md-6">#}
{#        <h3>Raw Output <small>(YAML)</small></h3>#}
{#        <pre>#}
{#{{ estimation.output_yaml }}#}
{#        </pre>#}
{#    </div>#}
{#</div>#}
d01e2cc2   Antoine Goutenoir   Add the template ...
140
141
{% endif %}
{% endblock %}
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
142
{% block js %}
b7411dd3   Antoine Goutenoir   Improve the plots...
143
144
145
146
147
<script src="/static/js/vendor/d3.v4.js"></script>
<script src="/static/js/vendor/d3-legend.js"></script>
{#<script src="https://d3js.org/d3.v4.js"></script>#}
{#<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.6/d3-legend.js"></script>#}

39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
148
149
150
151
152
153
154
155
<script type="text/javascript">

/** POLYFILLS **/
Math.log10 = Math.log10 || function(x) {
  return Math.log(x) * Math.LOG10E;
};

/**
c890bcbc   Antoine Goutenoir   Review.
156
 * Useful for axes' domains on plots.
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
 * @param value
 * @returns {number}
 */
var ceil_value_to_magnitude = function(value) {
    var sign = 1;
    if (value < 0) {
        value = Math.abs(value);
        sign = -1;
    }
    if (value < 1) {
        return sign;
    }

    var low = Math.pow(10, Math.floor(Math.log10(value)));

    var cursor = low;
b7411dd3   Antoine Goutenoir   Improve the plots...
173
174
    var noloop = 0;
    while ((cursor < value) && (noloop <= 100)) {
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
175
        cursor += 0.1 * low;
b7411dd3   Antoine Goutenoir   Improve the plots...
176
        noloop += 1;
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
177
178
179
180
181
    }

    return sign * cursor;
};

b7411dd3   Antoine Goutenoir   Improve the plots...
182
183
184
185
186
/** CONFIG **/

var plots_config = {
    'cities_count': {{ estimation_output.cities | length }}
};
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
187
188

/** PLOTS **/
30f014d5   Antoine Goutenoir   Add a lollipop pl...
189

39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
190
191
192
jQuery(document).ready(function($){

    var vizid = "#cities_footprints_d3viz";
c890bcbc   Antoine Goutenoir   Review.
193
194
195
    var csvUrl = "/estimation/{{ estimation.public_id }}.csv";
    var x_key = 'city';
    var y_key = 'co2 (g)';
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
196
197

    // Set the dimensions and margins of the graph
b7411dd3   Antoine Goutenoir   Improve the plots...
198
    var margin = {top: 10, right: 30, bottom: 150, left: 150},
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
        height = 666 - margin.top - margin.bottom;
    var width = Math.max(880, $(vizid).parent().width());
    width = width - margin.left - margin.right;

    // Append the svg object to the body of the page
    var svg = d3.select(vizid)
      .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");

    // Parse the Data
c890bcbc   Antoine Goutenoir   Review.
213
    d3.csv(csvUrl, function(data) {
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
214
215
216
217
218
219
220
221

        // Extrema
        var data_y_max = d3.max(data, function(d) { return parseFloat(d['co2 (g)']); });
        var axis_y_max = ceil_value_to_magnitude(data_y_max);

        // X axis
        var x = d3.scaleBand()
          .range([ 0, width ])
c890bcbc   Antoine Goutenoir   Review.
222
          .domain(data.map(function(d) { return d[x_key]; }))
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
          .padding(0.2);
        svg.append("g")
          .attr("transform", "translate(0," + height + ")")
          .call(d3.axisBottom(x))
          .selectAll("text")
            .attr("transform", "translate(-10,0)rotate(-45)")
            .style("text-anchor", "end");

        // Add Y axis
        var y = d3.scaleLinear()
          .range([ height, 0 ])
          .domain([ 0, axis_y_max ]);
        svg.append("g")
          .call(d3.axisLeft(y));

        // Bars
        svg.selectAll("mybar")
          .data(data)
          .enter()
          .append("rect")
c890bcbc   Antoine Goutenoir   Review.
243
            .attr("x", function(d) { return x(d[x_key]); })
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
244
245
            .attr("width", x.bandwidth())
            .attr("fill", "#d0808b")
c890bcbc   Antoine Goutenoir   Review.
246
            // Hide bars at the beginning
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
247
248
249
250
251
252
253
            .attr("height", function(d) { return height - y(0); }) // always equal to 0
            .attr("y", function(d) { return y(0); });

        // Animation
        svg.selectAll("rect")
          .transition()
          .duration(800)
c890bcbc   Antoine Goutenoir   Review.
254
255
          .attr("y", function(d) { return y(d[y_key]); })
          .attr("height", function(d) { return height - y(d[y_key]); })
39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
256
257
258
259
260
261
          .delay(function(d, i) { return(i*100); });

        // …
    });

});
30f014d5   Antoine Goutenoir   Add a lollipop pl...
262
263
264
265
266
267
268
269


jQuery(document).ready(function($){
    var vizid = "#cities_footprints_d3viz_lollipop";
    var csvUrl = "/estimation/{{ estimation.public_id }}.csv";
    var y_key = 'city';
    var x_key = 'co2 (g)';

b7411dd3   Antoine Goutenoir   Improve the plots...
270
271
    var margin = {top: 10, right: 30, bottom: 150, left: 150},
        height = Math.max(300, 100+16*plots_config['cities_count']) - margin.top - margin.bottom;
30f014d5   Antoine Goutenoir   Add a lollipop pl...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
    var width = Math.max(880, $(vizid).parent().width());
    width = width - margin.left - margin.right;

    var svg = d3.select(vizid)
      .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform",
              "translate(" + margin.left + "," + margin.top + ")");

    d3.csv(csvUrl, function (data) {

        // Extrema
        var data_x_max = d3.max(data, function(d) { return parseFloat(d[x_key]); });
        var axis_x_max = ceil_value_to_magnitude(data_x_max);

        // Add X axis
        var x = d3.scaleLinear()
            .domain([0, axis_x_max])
            .range([0, width]);
        svg.append("g")
            .attr("transform", "translate(0," + height + ")")
            .call(d3.axisBottom(x))
            .selectAll("text")
            .attr("transform", "translate(-10,0)rotate(-45)")
            .style("text-anchor", "end");

        // Y axis
        var y = d3.scaleBand()
            .range([0, height])
            .domain(data.map(function (d) {
                return d[y_key];
            }))
            .padding(1);
        svg.append("g")
            .call(d3.axisLeft(y));

b7411dd3   Antoine Goutenoir   Improve the plots...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
        {#svg.append("g")#}
        {#    .attr("class", "legendQuant")#}
        {#    .attr("transform", "translate(20,20)");#}
        {##}
        {#var legend = d3.legendColor()#}
        {#    .labelFormat(d3.format(".2f"))#}
        {#    .useClass(true)#}
        {#    .title("Legend")#}
        {#    .titleWidth(100)#}
        {#    .scale(y);#}
        {##}
        {#svg.select(".legendQuant")#}
        {#    .call(legend);#}

        svg.append("g")
            .append('text')
            .attr("transform", "translate("+(-180+width/2.0)+","+(height+111)+")")
            {#.text("CO2 emissions as a function of travelling distance");#}
            .text("CO\u2082 emissions equivalent per target city.");
30f014d5   Antoine Goutenoir   Add a lollipop pl...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373

        // Lines
        svg.selectAll("myline")
            .data(data)
            .enter()
            .append("line")
//            .attr("x1", function (d) {
//                return x(d[x_key]);
//            })
            .attr("x1", x(0))
            .attr("x2", x(0))
            .attr("y1", function (d) {
                return y(d[y_key]);
            })
            .attr("y2", function (d) {
                return y(d[y_key]);
            })
            .attr("stroke", "grey");

        // Circles
        svg.selectAll("mycircle")
            .data(data)
            .enter()
            .append("circle")
            .attr("cx", function (d) {
                return x(d[x_key]);
            })
            .attr("cy", function (d) {
                return y(d[y_key]);
            })
            .attr("r", "0")
            .style("fill", "#69b3a2")
            .attr("stroke", "black");

        var animation_duration = 300;
        var animation_delay = 100;

        svg.selectAll("circle")
            .transition()
            .duration(animation_duration)
            .attr("r", "4")
            .delay(function(d, i) { return(i*animation_delay); });

        svg.selectAll("line")
            .transition()
b7411dd3   Antoine Goutenoir   Improve the plots...
374
            .duration(animation_duration*0.618)
30f014d5   Antoine Goutenoir   Add a lollipop pl...
375
376
377
378
379
380
            .attr("x1", function (d) { return x(d[x_key]); })
            .delay(function(d, i) { return(i*animation_delay); });
    });

});

39d46569   Antoine Goutenoir   Surpriiiiise ! :p...
381
382
</script>
{% endblock %}