Blame view

flaskr/static/js/plots/sorted-emissions-inequality.js 15.6 KB
2ee2acee   Antoine Goutenoir   feat: continue wi...
1
2
3
function draw_sorted_emissions_inequality(containerSelector, csvUrl) {

    // set the dimensions and margins of the graph
85984e42   Antoine Goutenoir   design: improve t...
4
    let margin = {top: 50, right: 30, bottom: 80, left: 75},
2ee2acee   Antoine Goutenoir   feat: continue wi...
5
6
7
8
9
10
11
12
13
        width = 600 - margin.left - margin.right,
        height = 700 - margin.top - margin.bottom;

    function getTicks(maxValue, interval, startValue = 0) {
        let range = [];
        for (let i = startValue; i <= maxValue; i += interval) {
            range.push(i);
        }
        return range;
566355a9   Adrenesis   Add sorted-carbon...
14
    }
2ee2acee   Antoine Goutenoir   feat: continue wi...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

    function getBottomTicks(maxAttendeePercent) {
        return getTicks(maxAttendeePercent, 20);
    }

    function getLeftTicks(maxemissionsPercent) {
        return getTicks(maxemissionsPercent, 20);
    }

    function getSliceCollision(x, y, barSettings) {
        let result = false;
        barSettings.forEach((element, index) => {
            if (x < element.rightBorder && x > element.leftBorder) {
                let binYDiff = element.topBorder - element.bottomBorder;
                let binXDiff = element.rightBorder - element.leftBorder;
                let binDiagonalAngle = Math.atan2(binYDiff, binXDiff);
                // let binYCenter = (element.topBorder + element.bottomBorder)/2;
                // let binXCenter = (element.rightBorder + element.leftBorder)/2;
                let mouseXDiff = element.rightBorder - x;
                let mouseYDiff = element.topBorder - y;
                let mouseToCenterAngle = Math.atan2(mouseYDiff, mouseXDiff);
                // console.log(binDiagonalAngle);
                // console.log(mouseToCenterAngle);

                if (mouseToCenterAngle < binDiagonalAngle) {
                    barSettings.forEach((element, index) => {
                        if (y < element.topBorder && y > element.bottomBorder) {
                            let lb = barSettings[index].leftBorder;
                            let rb = barSettings[index].rightBorder;
                            let tb = barSettings[index].topBorder;
                            let bb = barSettings[index].bottomBorder;
                            let binCollisionRatio = (y - bb) / (tb - bb);
                            let otherAxisLevel = (rb - lb) * binCollisionRatio + lb;
                            result = {
                                binDiagonalAngle: binDiagonalAngle,
                                isXDriving: false,
                                binIndex: index,
                                otherAxisLevel: otherAxisLevel
                            };

                        }
                    });
566355a9   Adrenesis   Add sorted-carbon...
57
58


2ee2acee   Antoine Goutenoir   feat: continue wi...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
                }
                else {
                    let lb = barSettings[index].leftBorder;
                    let rb = barSettings[index].rightBorder;
                    let tb = barSettings[index].topBorder;
                    let bb = barSettings[index].bottomBorder;
                    let binCollisionRatio = (x - lb) / (rb - lb);
                    let otherAxisLevel = (tb - bb) * binCollisionRatio + bb;
                    // console.log(otherAxisLevel);
                    result = {
                        binDiagonalAngle: binDiagonalAngle,
                        isXDriving: true,
                        binIndex: index,
                        otherAxisLevel: otherAxisLevel
                    }
566355a9   Adrenesis   Add sorted-carbon...
74
75
                }
            }
2ee2acee   Antoine Goutenoir   feat: continue wi...
76
77
78
        });
        return result;

566355a9   Adrenesis   Add sorted-carbon...
79
    }
566355a9   Adrenesis   Add sorted-carbon...
80

13b5231b   Adrenesis   Add an area to te...
81
    function refreshCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, tooltip, selectedArea) {
2ee2acee   Antoine Goutenoir   feat: continue wi...
82
83
84
        const x = d3.pointer(event)[0];
        const y = d3.pointer(event)[1];
        // var y = d3.event.pageY - document.getElementById(<id-of-your-svg>).getBoundingClientRect().y + 10
4256c477   Antoine Goutenoir   feat: integrate t...
85
86
        tooltip.style("left", (x + 10) + "px");
        tooltip.style("top", (y - 30) + "px");
2ee2acee   Antoine Goutenoir   feat: continue wi...
87
88
89
        let xInGraph = xScale.invert(x - margin.left);
        let yInGraph = yScale.invert(y - margin.top);

2ee2acee   Antoine Goutenoir   feat: continue wi...
90
91
92
93
94
95
96
97
98
99
100
        // let sliceId = xScale.invert(x * 1.025 - d3.selectAll("g.yl.axis")._groups[0][0].getBoundingClientRect().x- margin.left)/500 +1;
        // let attendeePercent = (getAttendeeOnRight(sliceId, attendeeNumberPerGroup) / attendeeSum * 100.0).toFixed(1);
        if (
            x < margin.left
            ||
            x > width + margin.left
            ||
            y < margin.top
            ||
            y > height + margin.top
    ) {
4256c477   Antoine Goutenoir   feat: integrate t...
101
102
            vertical.style("display", "none");
            horizontal.style("display", "none");
13b5231b   Adrenesis   Add an area to te...
103
            selectedArea.style("display", "none");
4256c477   Antoine Goutenoir   feat: integrate t...
104
            tooltip.style("display", "none");
566355a9   Adrenesis   Add sorted-carbon...
105
        }
2ee2acee   Antoine Goutenoir   feat: continue wi...
106
        else {
4256c477   Antoine Goutenoir   feat: integrate t...
107
108
            vertical.style("display", "inherit");
            horizontal.style("display", "inherit");
13b5231b   Adrenesis   Add an area to te...
109
            selectedArea.style("display", "inherit");
4256c477   Antoine Goutenoir   feat: integrate t...
110
            tooltip.style("display", "inherit");
2ee2acee   Antoine Goutenoir   feat: continue wi...
111
112
113
            let sliceCollision = getSliceCollision(xInGraph, yInGraph, barSettings);
            // console.log(sliceCollision);
            if (sliceCollision) {
2ee2acee   Antoine Goutenoir   feat: continue wi...
114
115
116
                if (sliceCollision.isXDriving) {
                    vertical.style("left", x + "px");
                    horizontal.style("top", yScale(sliceCollision.otherAxisLevel) + margin.top + "px");
13b5231b   Adrenesis   Add an area to te...
117
118
119
120
                    selectedArea.style("top", yScale(sliceCollision.otherAxisLevel) + margin.top + "px");
                    selectedArea.style("height", yScale(0)  - yScale(sliceCollision.otherAxisLevel) + "px");
                    selectedArea.style("left", xScale(0) + margin.left + "px");
                    selectedArea.style("width", x - margin.left - xScale(0) + "px");
85984e42   Antoine Goutenoir   design: improve t...
121
122
123
124
125
126
                    tooltip.text(
                        Math.round(xInGraph) +
                        "% of 🖘 attendees emitted " +
                        Math.round(sliceCollision.otherAxisLevel) +
                        "% of CO\u2082 equivalent"
                    );
2ee2acee   Antoine Goutenoir   feat: continue wi...
127
128
                } else {
                    horizontal.style("top", y + "px");
4256c477   Antoine Goutenoir   feat: integrate t...
129
                    vertical.style("left", xScale(sliceCollision.otherAxisLevel) + margin.left + "px");
13b5231b   Adrenesis   Add an area to te...
130
131
132
133
                    selectedArea.style("top", margin.top + "px");
                    selectedArea.style("height", y - margin.top + "px");
                    selectedArea.style("left", xScale(sliceCollision.otherAxisLevel) + margin.left + "px");
                    selectedArea.style("width", xScale(100) - (xScale(sliceCollision.otherAxisLevel)) + "px");
85984e42   Antoine Goutenoir   design: improve t...
134
135
136
137
138
139
                    tooltip.text(
                        Math.round(100.0 - sliceCollision.otherAxisLevel) +
                        "% of 🖙 attendees emitted " +
                        Math.round(100.0 - yInGraph) +
                        "% of CO\u2082 equivalent"
                    );
2ee2acee   Antoine Goutenoir   feat: continue wi...
140
141
                }
            }
566355a9   Adrenesis   Add sorted-carbon...
142

2ee2acee   Antoine Goutenoir   feat: continue wi...
143
        }
4256c477   Antoine Goutenoir   feat: integrate t...
144
        // tooltip.text(attendeePercent + " % of attendees");
2ee2acee   Antoine Goutenoir   feat: continue wi...
145
146
        // console.log(d3.selectAll("g.x.axis")._groups[0][0]);
        // console.log(d3.selectAll("g.x.axis")._groups[0][0].getBoundingClientRect().x);
566355a9   Adrenesis   Add sorted-carbon...
147
    }
566355a9   Adrenesis   Add sorted-carbon...
148

2ee2acee   Antoine Goutenoir   feat: continue wi...
149
150
151
152
    function addVerticalLineAndListenCursor(xScale, yScale, barSettings) {
        let vertical = d3.select(containerSelector)
            .append("div")
            .attr("class", "no-pointer-events")
4256c477   Antoine Goutenoir   feat: integrate t...
153
            .style("display", "none")
2ee2acee   Antoine Goutenoir   feat: continue wi...
154
155
156
157
            .style("position", "absolute")
            .style("z-index", "19")
            .style("width", "2px")
            .style("height", (height) + "px")
4256c477   Antoine Goutenoir   feat: integrate t...
158
            .style("top", (margin.top) + "px")
2ee2acee   Antoine Goutenoir   feat: continue wi...
159
160
161
162
163
164
165
            .style("bottom", "30px")
            .style("left", "0px")
            .style("background", "#000");

        let horizontal = d3.select(containerSelector)
            .append("div")
            .attr("class", "no-pointer-events")
4256c477   Antoine Goutenoir   feat: integrate t...
166
            .style("display", "none")
2ee2acee   Antoine Goutenoir   feat: continue wi...
167
168
169
170
171
172
            .style("position", "absolute")
            .style("z-index", "19")
            .style("width", (width) + "px")
            .style("height", "2px")
            .style("top", "0px")
            .style("bottom", "30px")
4256c477   Antoine Goutenoir   feat: integrate t...
173
            .style("left", (margin.left) + "px")
2ee2acee   Antoine Goutenoir   feat: continue wi...
174
175
            .style("background", "#000");

4256c477   Antoine Goutenoir   feat: integrate t...
176
        let tooltip = d3.select(containerSelector)
2ee2acee   Antoine Goutenoir   feat: continue wi...
177
            .append("div")
85984e42   Antoine Goutenoir   design: improve t...
178
            .attr("class", "no-pointer-events plot-tooltip")
4256c477   Antoine Goutenoir   feat: integrate t...
179
            .style("display", "none")
2ee2acee   Antoine Goutenoir   feat: continue wi...
180
181
            .style("position", "absolute")
            .style("z-index", "20")
4256c477   Antoine Goutenoir   feat: integrate t...
182
183
            .style("width", "230px")
            .style("height", "60px")
2ee2acee   Antoine Goutenoir   feat: continue wi...
184
185
186
            .style("top", "10px")
            .style("bottom", "30px")
            .style("left", "0px")
4256c477   Antoine Goutenoir   feat: integrate t...
187
            .style("padding", "7px 10px")
2ee2acee   Antoine Goutenoir   feat: continue wi...
188
189
190
            .style("border", "1px solid grey")
            .style("background", "rgba(255, 255, 255, 0.7)");

13b5231b   Adrenesis   Add an area to te...
191
192
193
194
195
        let selectedArea = d3.select(containerSelector)
            .append("div")
            .attr("class", "no-pointer-events")
            .style("display", "none")
            .style("position", "absolute")
e0905f97   Antoine Goutenoir   fix: make selecti...
196
            .style("z-index", "10")
13b5231b   Adrenesis   Add an area to te...
197
198
199
200
201
            .style("width", "0px")
            .style("height", (height) + "px")
            .style("top", (margin.top) + "px")
            .style("bottom", "30px")
            .style("left", "0px")
e0905f97   Antoine Goutenoir   fix: make selecti...
202
            .style("background", "rgba(60, 200, 60, 0.2)");
13b5231b   Adrenesis   Add an area to te...
203

2ee2acee   Antoine Goutenoir   feat: continue wi...
204
205
        d3.select(containerSelector)
            .on("mousemove", function (event) {
13b5231b   Adrenesis   Add an area to te...
206
                refreshCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, tooltip, selectedArea);
2ee2acee   Antoine Goutenoir   feat: continue wi...
207
208
            })
            .on("mouseover", function (event) {
13b5231b   Adrenesis   Add an area to te...
209
                refreshCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, tooltip, selectedArea);
2ee2acee   Antoine Goutenoir   feat: continue wi...
210
211
            });
    }
566355a9   Adrenesis   Add sorted-carbon...
212
213


2ee2acee   Antoine Goutenoir   feat: continue wi...
214
215
216
    document.addEventListener("DOMContentLoaded", () => {
        width = Math.max(880, $(containerSelector).parent().width());
        width = width - margin.left - margin.right;
566355a9   Adrenesis   Add sorted-carbon...
217
218
        let maxAttendeePercent = 100;
        let maxEmissionsPercent = 100;
2ee2acee   Antoine Goutenoir   feat: continue wi...
219
        let svg = d3.select(containerSelector)
566355a9   Adrenesis   Add sorted-carbon...
220
221
222
223
224
225
226
227
228
229
230
231
            .append("svg")
            .attr("id", "graph-svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform",
                "translate(" + margin.left + "," + margin.top + ")");

        let emissionsPerGroup = [];
        let attendeeNumberPerGroup = [];
        let emissionsSum = 0;
        let attendeeSum = 0;
2ee2acee   Antoine Goutenoir   feat: continue wi...
232
233
234
235
236
        let data = [];
        d3.csv(csvUrl, function (datum) {
            let trainAttendee = parseInt(datum["train trips_amount"]);
            let planeAttendee = parseInt(datum["plane trips_amount"]);
            if (trainAttendee === 0 && planeAttendee === 0) {
566355a9   Adrenesis   Add sorted-carbon...
237
238
239
                return;
            }
            let attendeeNumber = trainAttendee + planeAttendee;
2ee2acee   Antoine Goutenoir   feat: continue wi...
240
241
242
            let distance_km = datum.distance_km / attendeeNumber;
            let co2_kg = parseFloat(datum.co2_kg);
            if (co2_kg === "NaN" || distance_km === "NaN") {
566355a9   Adrenesis   Add sorted-carbon...
243
244
                return;
            }
2ee2acee   Antoine Goutenoir   feat: continue wi...
245
            data.push(datum);
566355a9   Adrenesis   Add sorted-carbon...
246
        }).then((() => {
2ee2acee   Antoine Goutenoir   feat: continue wi...
247
248
249
            data.forEach((datum, index) => {
                let trainAttendee = parseInt(datum["train trips_amount"]);
                let planeAttendee = parseInt(datum["plane trips_amount"]);
566355a9   Adrenesis   Add sorted-carbon...
250
                let attendeeNumber = trainAttendee + planeAttendee;
2ee2acee   Antoine Goutenoir   feat: continue wi...
251
                datum["emissions_per_capita"] = parseFloat(datum.co2_kg) / attendeeNumber;
566355a9   Adrenesis   Add sorted-carbon...
252
253
            });

2ee2acee   Antoine Goutenoir   feat: continue wi...
254
            data.sort(function (a, b) {
566355a9   Adrenesis   Add sorted-carbon...
255
256
257
258
259
260
261
262
                if (a.emissions_per_capita > b.emissions_per_capita) {
                    return 1;
                }
                if (b.emissions_per_capita > a.emissions_per_capita) {
                    return -1;
                }
                return 0;
            });
85984e42   Antoine Goutenoir   design: improve t...
263
            // console.log(data);
566355a9   Adrenesis   Add sorted-carbon...
264
            let dataIndex = 0;
2ee2acee   Antoine Goutenoir   feat: continue wi...
265
266
267
            data.forEach((datum, index) => {
                let trainAttendee = parseInt(datum["train trips_amount"]);
                let planeAttendee = parseInt(datum["plane trips_amount"]);
566355a9   Adrenesis   Add sorted-carbon...
268
                let attendeeNumber = trainAttendee + planeAttendee;
2ee2acee   Antoine Goutenoir   feat: continue wi...
269
                let co2_kg = parseFloat(datum.co2_kg);
566355a9   Adrenesis   Add sorted-carbon...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
                emissionsSum += co2_kg;
                attendeeSum += attendeeNumber;
                emissionsPerGroup[dataIndex] = emissionsSum;
                attendeeNumberPerGroup[dataIndex] = attendeeSum;
                dataIndex += 1;
            });
            // emissionsPerGroup.forEach((element, index) => {
            //     maxemissions = Math.max(maxemissions, element);
            //     maxemissionsPercent = Math.max(maxemissionsPercent, element / emissionsSum * 100.0)
            // });
            // maxDistance += 2000;
            // console.log(maxDistance);

            //Title
            svg.append("text")
                .attr("transform",
85984e42   Antoine Goutenoir   design: improve t...
286
                    "translate(" + (0) + ", -15)")
566355a9   Adrenesis   Add sorted-carbon...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
                .style("font-weight", "bold")
                .style("font-size", "130%")
                .text("Sorted carbon emissions");

            // X axis: scale and draw:
            let x = d3.scaleLinear()
                .domain([0, maxAttendeePercent])
                .range([0, width]);
            let xAxis = d3.axisBottom(x)
                .tickValues(getBottomTicks(maxAttendeePercent));
            svg.append("g")
                .attr("transform", "translate(0," + height + ")")
                .attr("class", "x axis")
                .call(xAxis);

            // Y axis Left
            let y = d3.scaleLinear()
                .domain([0, maxEmissionsPercent])
                .range([height, 0]);
            let yAxis = d3.axisLeft(y)
                .tickValues(getLeftTicks(maxEmissionsPercent));
            svg.append("g")
                .attr("class", "y axis")
                .call(yAxis);

            svg.append("text")
                .attr("transform",
2ee2acee   Antoine Goutenoir   feat: continue wi...
314
                    "translate(" + (width / 2) + " ," +
566355a9   Adrenesis   Add sorted-carbon...
315
316
317
318
319
320
                    (height + margin.top + 12) + ")")
                .style("text-anchor", "middle")
                .text("% of participants, sorted by per capita emission");

            svg.append("text")
                .attr("transform", "rotate(-90)")
85984e42   Antoine Goutenoir   design: improve t...
321
                .attr("y", 0 - 4*margin.left/5)
2ee2acee   Antoine Goutenoir   feat: continue wi...
322
                .attr("x", 0 - (height / 2))
566355a9   Adrenesis   Add sorted-carbon...
323
324
325
326
327
328
329
330
                .attr("dy", "1em")
                .style("text-anchor", "middle")
                .text("% of total emissions");

            let barSettings = [];
            emissionsPerGroup.forEach((element, index) => {
                let bottomBorder;
                let leftBorder;
2ee2acee   Antoine Goutenoir   feat: continue wi...
331
                if (index === 0) {
566355a9   Adrenesis   Add sorted-carbon...
332
333
334
                    bottomBorder = 0;
                    leftBorder = 0;
                }
2ee2acee   Antoine Goutenoir   feat: continue wi...
335
336
337
                else {
                    bottomBorder = emissionsPerGroup[index - 1] / emissionsSum * 100.0;
                    leftBorder = attendeeNumberPerGroup[index - 1] / attendeeSum * 100.0;
566355a9   Adrenesis   Add sorted-carbon...
338
                }
2ee2acee   Antoine Goutenoir   feat: continue wi...
339
340
341
342
343
344
345
                barSettings[index] =
                    {
                        topBorder: emissionsPerGroup[index] / emissionsSum * 100.0,
                        bottomBorder: bottomBorder,
                        leftBorder: leftBorder,
                        rightBorder: attendeeNumberPerGroup[index] / attendeeSum * 100.0,
                    };
566355a9   Adrenesis   Add sorted-carbon...
346
347
348
349
350
351
352
353
354
                // console.log(index);
                // console.log(barSettings[index]);
            });
            // console.log(barSettings);
            svg.selectAll("rect")
                .data(barSettings)
                .enter()
                .append("rect")
                .attr("x", 1)
2ee2acee   Antoine Goutenoir   feat: continue wi...
355
356
357
358
359
360
361
362
363
                .attr("transform", function (d) {
                    return "translate(" + x(d.leftBorder) + "," + y(d.topBorder) + ")";
                })
                .attr("width", function (d) {
                    return x(d.rightBorder) - x(d.leftBorder) - 1;
                })
                .attr("height", function (d) {
                    return (y(d.bottomBorder) - y(d.topBorder));
                })
566355a9   Adrenesis   Add sorted-carbon...
364
365
366
367
368
                .style("z-index", "500")
                .style("fill", "#4444E5");
            addVerticalLineAndListenCursor(x, y, barSettings);
        }));

2ee2acee   Antoine Goutenoir   feat: continue wi...
369
370
371
372

    });

}