From 2ee2acee1a876d02b0d164f779f85674840b6ca6 Mon Sep 17 00:00:00 2001 From: Antoine Goutenoir Date: Thu, 1 Oct 2020 06:27:01 +0200 Subject: [PATCH] feat: continue with emission inequality plot --- flaskr/static/js/plots/sorted-carbon-emissions.js | 347 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- flaskr/static/js/plots/sorted_emissions_inequality.js | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+), 347 deletions(-) delete mode 100644 flaskr/static/js/plots/sorted-carbon-emissions.js create mode 100644 flaskr/static/js/plots/sorted_emissions_inequality.js diff --git a/flaskr/static/js/plots/sorted-carbon-emissions.js b/flaskr/static/js/plots/sorted-carbon-emissions.js deleted file mode 100644 index a2e07aa..0000000 --- a/flaskr/static/js/plots/sorted-carbon-emissions.js +++ /dev/null @@ -1,347 +0,0 @@ -// set the dimensions and margins of the graph -let margin = {top: 30, right: 10, bottom: 62, left: 72}, - 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; -} - -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 - }; - - } - }); - - - } - 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 - } - } - } - }); - return result; - -} - -function setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box) -{ - // mousex = d3.mouse(this); - var x = d3.pointer(event)[0]; - var y = d3.pointer(event)[1]; - // var y = d3.event.pageY - document.getElementById().getBoundingClientRect().y + 10 - // x += 5; - box.style("left", (x + 10) + "px"); - box.style("top", (y - 20) + "px"); - let xInGraph = xScale.invert(x - d3.selectAll("g.y.axis")._groups[0][0].getBoundingClientRect().right); - let yInGraph = yScale.invert(y - margin.top ); - - - - // 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 > width + d3.selectAll("g.y.axis")._groups[0][0].getBoundingClientRect().right || - x < d3.selectAll("g.y.axis")._groups[0][0].getBoundingClientRect().right || - y < margin.top +5 || - y > d3.selectAll("g.x.axis")._groups[0][0].getBoundingClientRect().top) - { - vertical.style("width", 0); - horizontal.style("height", 0); - box.style("display", "none"); - } - else - { - vertical.style("width", "2px"); - horizontal.style("height", "2px"); - box.style("display", "inherit"); - let sliceCollision = getSliceCollision(xInGraph, yInGraph, barSettings); - // console.log(sliceCollision); - if(sliceCollision) - { - if(sliceCollision.isXDriving) - { - - vertical.style("left", x + "px" ); - horizontal.style("top", yScale(sliceCollision.otherAxisLevel) + margin.top + "px"); - - box.text(xInGraph + " " + sliceCollision.otherAxisLevel); - } - else - { - horizontal.style("top", y + "px"); - vertical.style("left", xScale(sliceCollision.otherAxisLevel) + d3.selectAll("g.y.axis")._groups[0][0].getBoundingClientRect().right + "px" ); - - box.text(sliceCollision.otherAxisLevel + " " + yInGraph); - } - } - - } - // box.text(attendeePercent + " % of attendees"); - // console.log(d3.selectAll("g.x.axis")._groups[0][0]); - // console.log(d3.selectAll("g.x.axis")._groups[0][0].getBoundingClientRect().x); -} - -function addVerticalLineAndListenCursor(xScale, yScale, barSettings) { - let vertical = d3.select("#chart-container") - .append("div") - .attr("class", "remove") - .style("position", "absolute") - .style("z-index", "19") - .style("width", "2px") - .style("height", (height) + "px") - .style("top", (10 + margin.top) + "px") - .style("bottom", "30px") - .style("left", "0px") - .style("background", "#000"); - - let horizontal = d3.select("#chart-container") - .append("div") - .attr("class", "remove") - .style("position", "absolute") - .style("z-index", "19") - .style("width", (width) + "px") - .style("height", "2px") - .style("top", "0px") - .style("bottom", "30px") - .style("left", (10 + margin.left) + "px") - .style("background", "#000"); - - let box = d3.select("#chart-container") - .append("div") - .attr("class", "remove") - .style("position", "absolute") - .style("z-index", "20") - .style("width", "150px") - .style("height", "44px") - .style("top", "10px") - .style("bottom", "30px") - .style("left", "0px") - .style("border", "1px solid grey") - .style("background", "rgba(255, 255, 255, 0.7)"); - - d3.select("#chart-container") - .on("mousemove", function(event){ - setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box); - }) - .on("mouseover", function(event){ - setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box); - - }); -} - - - -document.onreadystatechange = () => { - if (document.readyState === 'complete') { - let maxAttendeePercent = 100; - let maxEmissionsPercent = 100; - let svg = d3.select("#chart-container") - .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; - let rows = []; - d3.csv("2020-09-30_04_21_19_87a1.csv", function (data) { - let trainAttendee = parseInt(data["train trips_amount"]); - let planeAttendee = parseInt(data["plane trips_amount"]); - if(trainAttendee === 0 && planeAttendee === 0) - { - return; - } - let attendeeNumber = trainAttendee + planeAttendee; - let distance_km = data.distance_km / attendeeNumber; - let co2_kg = parseFloat(data.co2_kg); - if (co2_kg === "NaN" || distance_km === "NaN") - { - return; - } - rows.push(data); - }).then((() => { - rows.forEach((element, index) => { - let trainAttendee = parseInt(element["train trips_amount"]); - let planeAttendee = parseInt(element["plane trips_amount"]); - let attendeeNumber = trainAttendee + planeAttendee; - element["emissions_per_capita"] = parseFloat(element.co2_kg) / attendeeNumber; - }); - - rows.sort(function (a, b) { - if (a.emissions_per_capita > b.emissions_per_capita) { - return 1; - } - if (b.emissions_per_capita > a.emissions_per_capita) { - return -1; - } - return 0; - }); - console.log(rows); - let dataIndex = 0; - rows.forEach((element, index) => { - let trainAttendee = parseInt(element["train trips_amount"]); - let planeAttendee = parseInt(element["plane trips_amount"]); - let attendeeNumber = trainAttendee + planeAttendee; - let co2_kg = parseFloat(element.co2_kg); - 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", - "translate(" + (70 + margin.left) + ", -12)") - .style("text-anchor", "middle") - .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", - "translate(" + (width/2) + " ," + - (height + margin.top + 12) + ")") - .style("text-anchor", "middle") - .text("% of participants, sorted by per capita emission"); - - svg.append("text") - .attr("transform", "rotate(-90)") - .attr("y", 0 - margin.left) - .attr("x",0 - (height / 2)) - .attr("dy", "1em") - .style("text-anchor", "middle") - .text("% of total emissions"); - - let barSettings = []; - emissionsPerGroup.forEach((element, index) => { - let bottomBorder; - let leftBorder; - if(index === 0) - { - bottomBorder = 0; - leftBorder = 0; - } - else - { - bottomBorder = emissionsPerGroup[index-1] / emissionsSum * 100.0; - leftBorder = attendeeNumberPerGroup[index-1] /attendeeSum * 100.0; - } - barSettings[index]= - { - topBorder : emissionsPerGroup[index] / emissionsSum * 100.0, - bottomBorder: bottomBorder, - leftBorder : leftBorder, - rightBorder : attendeeNumberPerGroup[index] / attendeeSum * 100.0, - }; - // console.log(index); - // console.log(barSettings[index]); - }); - // console.log(barSettings); - svg.selectAll("rect") - .data(barSettings) - .enter() - .append("rect") - .attr("x", 1) - .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)); }) - .style("z-index", "500") - .style("fill", "#4444E5"); - addVerticalLineAndListenCursor(x, y, barSettings); - })); - - } -}; \ No newline at end of file diff --git a/flaskr/static/js/plots/sorted_emissions_inequality.js b/flaskr/static/js/plots/sorted_emissions_inequality.js new file mode 100644 index 0000000..b59064e --- /dev/null +++ b/flaskr/static/js/plots/sorted_emissions_inequality.js @@ -0,0 +1,341 @@ +function draw_sorted_emissions_inequality(containerSelector, csvUrl) { + + // set the dimensions and margins of the graph + let margin = {top: 30, right: 10, bottom: 62, left: 72}, + 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; + } + + 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 + }; + + } + }); + + + } + 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 + } + } + } + }); + return result; + + } + + function setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box) { + // mousex = d3.mouse(this); + const x = d3.pointer(event)[0]; + const y = d3.pointer(event)[1]; + // var y = d3.event.pageY - document.getElementById().getBoundingClientRect().y + 10 + // x += 5; + box.style("left", (x + 10) + "px"); + box.style("top", (y - 20) + "px"); + let xInGraph = xScale.invert(x - margin.left); + let yInGraph = yScale.invert(y - margin.top); + + + // 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 + ) { + vertical.style("width", 0); + horizontal.style("height", 0); + box.style("display", "none"); + } + else { + vertical.style("width", "2px"); + horizontal.style("height", "2px"); + box.style("display", "inherit"); + let sliceCollision = getSliceCollision(xInGraph, yInGraph, barSettings); + // console.log(sliceCollision); + if (sliceCollision) { + if (sliceCollision.isXDriving) { + vertical.style("left", x + "px"); + horizontal.style("top", yScale(sliceCollision.otherAxisLevel) + margin.top + "px"); + + box.text(xInGraph + " " + sliceCollision.otherAxisLevel); + } else { + horizontal.style("top", y + "px"); + vertical.style("left", xScale(sliceCollision.otherAxisLevel) + margin.right + "px"); + + box.text(sliceCollision.otherAxisLevel + " " + yInGraph); + } + } + + } + // box.text(attendeePercent + " % of attendees"); + // console.log(d3.selectAll("g.x.axis")._groups[0][0]); + // console.log(d3.selectAll("g.x.axis")._groups[0][0].getBoundingClientRect().x); + } + + function addVerticalLineAndListenCursor(xScale, yScale, barSettings) { + let vertical = d3.select(containerSelector) + .append("div") + .attr("class", "no-pointer-events") + .style("position", "absolute") + .style("z-index", "19") + .style("width", "2px") + .style("height", (height) + "px") + .style("top", (10 + margin.top) + "px") + .style("bottom", "30px") + .style("left", "0px") + .style("background", "#000"); + + let horizontal = d3.select(containerSelector) + .append("div") + .attr("class", "no-pointer-events") + .style("position", "absolute") + .style("z-index", "19") + .style("width", (width) + "px") + .style("height", "2px") + .style("top", "0px") + .style("bottom", "30px") + .style("left", (10 + margin.left) + "px") + .style("background", "#000"); + + let box = d3.select(containerSelector) + .append("div") + .attr("class", "no-pointer-events") + .style("position", "absolute") + .style("z-index", "20") + .style("width", "150px") + .style("height", "44px") + .style("top", "10px") + .style("bottom", "30px") + .style("left", "0px") + .style("border", "1px solid grey") + .style("background", "rgba(255, 255, 255, 0.7)"); + + d3.select(containerSelector) + .on("mousemove", function (event) { + setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box); + }) + .on("mouseover", function (event) { + setupCursorBoxes(event, xScale, yScale, barSettings, vertical, horizontal, box); + }); + } + + + document.addEventListener("DOMContentLoaded", () => { + width = Math.max(880, $(containerSelector).parent().width()); + width = width - margin.left - margin.right; + let maxAttendeePercent = 100; + let maxEmissionsPercent = 100; + let svg = d3.select(containerSelector) + .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; + 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) { + return; + } + let attendeeNumber = trainAttendee + planeAttendee; + let distance_km = datum.distance_km / attendeeNumber; + let co2_kg = parseFloat(datum.co2_kg); + if (co2_kg === "NaN" || distance_km === "NaN") { + return; + } + data.push(datum); + }).then((() => { + data.forEach((datum, index) => { + let trainAttendee = parseInt(datum["train trips_amount"]); + let planeAttendee = parseInt(datum["plane trips_amount"]); + let attendeeNumber = trainAttendee + planeAttendee; + datum["emissions_per_capita"] = parseFloat(datum.co2_kg) / attendeeNumber; + }); + + data.sort(function (a, b) { + if (a.emissions_per_capita > b.emissions_per_capita) { + return 1; + } + if (b.emissions_per_capita > a.emissions_per_capita) { + return -1; + } + return 0; + }); + console.log(data); + let dataIndex = 0; + data.forEach((datum, index) => { + let trainAttendee = parseInt(datum["train trips_amount"]); + let planeAttendee = parseInt(datum["plane trips_amount"]); + let attendeeNumber = trainAttendee + planeAttendee; + let co2_kg = parseFloat(datum.co2_kg); + 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", + "translate(" + (70 + margin.left) + ", -12)") + .style("text-anchor", "middle") + .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", + "translate(" + (width / 2) + " ," + + (height + margin.top + 12) + ")") + .style("text-anchor", "middle") + .text("% of participants, sorted by per capita emission"); + + svg.append("text") + .attr("transform", "rotate(-90)") + .attr("y", 0 - margin.left) + .attr("x", 0 - (height / 2)) + .attr("dy", "1em") + .style("text-anchor", "middle") + .text("% of total emissions"); + + let barSettings = []; + emissionsPerGroup.forEach((element, index) => { + let bottomBorder; + let leftBorder; + if (index === 0) { + bottomBorder = 0; + leftBorder = 0; + } + else { + bottomBorder = emissionsPerGroup[index - 1] / emissionsSum * 100.0; + leftBorder = attendeeNumberPerGroup[index - 1] / attendeeSum * 100.0; + } + barSettings[index] = + { + topBorder: emissionsPerGroup[index] / emissionsSum * 100.0, + bottomBorder: bottomBorder, + leftBorder: leftBorder, + rightBorder: attendeeNumberPerGroup[index] / attendeeSum * 100.0, + }; + // console.log(index); + // console.log(barSettings[index]); + }); + // console.log(barSettings); + svg.selectAll("rect") + .data(barSettings) + .enter() + .append("rect") + .attr("x", 1) + .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)); + }) + .style("z-index", "500") + .style("fill", "#4444E5"); + addVerticalLineAndListenCursor(x, y, barSettings); + })); + + + }); + +} \ No newline at end of file -- libgit2 0.21.2