Original chart created by Charles Boutaud, based on DStruths's block "d3.js Multi-series line chart interactive" and mbostock's block, "Scatterplot with Multiple Series".
Data Source: U.S. Energy Information Administration.
Built with blockbuilder.org.
forked from renecnielsen's block: Biofuels Production and Consumption
xxxxxxxxxx
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,800" rel="stylesheet" type="text/css">
<style>
body {
font: 11px "Open Sans";
margin: 0;
fill: #5d6263;
font-weight: 300;
}
.axis path,
.axis line {
fill: none;
stroke: #5d6263;
shape-rendering: crispEdges;
}
.legend-box {
cursor: pointer;
}
line.regressionLine {
stroke: #5d6263;
stroke-width: 0.7px;
stroke-dasharray: 4px 6px;
}
/*.teamLabel{font-weight:bold;fill:#74736c;}*/
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {
top: 130,
right: 145,
bottom: 30,
left: 45
},
width = 850 - margin.left - margin.right,
height = 820 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").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("data.csv", function(error, data) {
data.forEach(function(d) {
if (d.pays == "United Kingdom") {
return d.visible = true;
d.prod = +d.prod;
d.cons = +d.cons;
} else {
return d.visible = false;
d.prod = +d.prod;
d.cons = +d.cons;
};
});
var dataNest = d3.nest()
.key(function(d) {
return d.pays;
})
.entries(data);
var categories = dataNest.map(function(d, i) {
return {
name: d.key,
values: dataNest[i].values.map(function(d) {
return {
prod: +d.prod,
cons: +d.cons,
year: d.year
};
}),
visible: (d.key === "United Kingdom" ? true : false)
};
});
x.domain([0, 31]);
y.domain([0, 31]);
svg.append("foreignObject")
.attr("width", 600)
.attr("height", 200)
.attr("x", 50)
.attr("y", -110)
.append("xhtml:body")
.style("font-size", "12px")
.html("<h2>Daily Biofuels Production and Consumption, 2010-2012</h2><p>Explore the connections between consumption and production for the top-40 highest consumers and producers of biofuels in the world. Countries below the dashed line consume more biofuels than they produce. Countries above the line produce more than they consume. For example, United Kingdom and Germany consume more than they produce, whereas Argentina and Indonesia produce more than they consume.</p>");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.style("font-weight", 800)
.text("Daily Biofuels Consumption (1,000 Barrels)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style("font-weight", 800)
.text("DailyBiofuels Production (1,000 Barrels)");
var agencies = svg.selectAll(".agencies")
.data(categories) // Select nested data and append to new svg group elements
.enter().append("g")
.attr("class", "agencies");
var dots = svg.selectAll(".dot")
.data(data).enter().append("g").attr("class", "dot")
dots.append("circle")
.attr("id", function(d) {
return d.pays.replace(/\s+/g, "");
})
.attr("class", "circles")
.attr("opacity", 1)
.attr("r", 3.5)
.attr("cx", function(d) {
return d.visible ? x(d.cons) : x(-100 * 100);
})
.attr("cy", function(d) {
return d.visible ? y(d.prod) : y(-100 * 100);
})
.style("fill", function(d) {
return color(d.pays);
});
// begin of drawing lines
var line = d3.svg.line()
.x(function(d) {
return x(d.cons);
})
.y(function(d) {
return y(d.prod);
})
.interpolate("linear");
var fitLine = svg.append("line")
.attr({
"class": "regressionLine",
"x1": x(0),
"x2": x(31),
"y1": y(0),
"y2": y(31)
})
svg.append("foreignObject")
.attr("class", "label")
.attr("text-anchor", "start")
.attr("x", -510)
.attr("y", 88)
.attr("transform", "rotate(-45) translate(333, 353)")
.append("xhtml:body")
.html("↑");
svg.append("text")
.attr("class", "label")
.attr("text-anchor", "start")
.attr("x", -500)
.attr("y", -65)
.attr("dy", "165px")
.attr("transform", "rotate(-45) translate(333, 353)")
.text("Production higher than consumption");
svg.append("foreignObject")
.attr("class", "label")
.attr("text-anchor", "start")
.attr("x", -510)
.attr("y", 123)
.attr("transform", "rotate(-45) translate(333, 353)")
.append("xhtml:body")
.html("↓");
svg.append("text")
.attr("class", "label")
.attr("text-anchor", "start")
.attr("x", -500)
.attr("y", -60)
.attr("dy", "195px")
.attr("transform", "rotate(-45) translate(333, 353)")
.text("Consumption higher than production");
agencies.append("path")
.attr("d", function(d) {
return d.visible ? line(d.values) : null; // If array key "visible" = true then draw line, if not then don't
})
.attr("id", function(d) {
return d.name.replace(/\s+/g, "")
})
.attr("class", "linkcircles")
.attr("transform", "translate(0,0)")
.attr("opacity", 1)
.style("stroke-width", 1.5)
.style("stroke", function(d) {
return color(d.name);
})
.style("fill", "none");
// end of drawing lines
dots.append("text").attr("id", function(d) {
return d.pays.replace(/\s+/g, "");
}).attr("class", "labels").attr("x", function(d) {
return d.visible ? x(d.cons) : -1000;
}).attr("y", function(d) {
return d.visible ? y(d.prod) - 7 : -100 * 100;
}).text(function(d) {
return (d.year)
}).attr("text-anchor", "middle");
agencies.append("rect")
.attr("width", 10)
.attr("height", 10)
.attr("x", (width + 15))
.attr("y", function(d, i) {
return i * 13
})
.attr("fill", function(d) {
return d.visible ? color(d.name) : "#F1F1F2"; // If array key "visible" = true then color rect, if not then make it grey
})
.attr("class", "legend-box")
.on("click", function(d) { // On click make d.visible
d.visible = !d.visible; // If array key for this data selection is "visible" = true then make
data.forEach(function(data) {
if (data.pays == d.name) {
return data.visible = !data.visible; // If array key for this data selection is "visible" = true then make
}
});
maxX = findMaxX(categories); // Find max X rating value categories data with "visible"; true
maxY = findMaxY(categories); // Find max Y rating value categories data with "visible"; true
if (maxX > maxY) {
maxY = maxX;
} else {
maxX = maxY;
}
x.domain([0, maxX]); // Redefine xAxis domain based on highest y value of categories data with "visible"; true
svg.select(".x.axis")
.transition()
.call(xAxis);
y.domain([0, maxY]); // Redefine yAxis domain based on highest y value of categories data with "visible"; true
svg.select(".y.axis")
.transition()
.call(yAxis);
dots.selectAll(".circles")
.transition()
.attr("cx", function(d) {
return d.visible ? x(d.cons) : x(-(100 * 100)); // Replace dots with new scale
})
.attr("cy", function(d) {
return d.visible ? y(d.prod) : y(-(100 * 100)); // Replace dots with new scale
});
agencies.selectAll(".linkcircles")
.transition()
.attr("d", function(d) {
return d.visible ? line(d.values) : null; // If d.visible is true then draw line for this d selection
});
agencies.select("rect")
.transition()
.attr("fill", function(d) {
return d.visible ? color(d.name) : "#F1F1F2";
});
dots.selectAll(".labels")
.transition()
.attr("x", function(d) {
return d.visible ? x(d.cons) : x(-(100 * 100)); // Replace labels with new scale
})
.attr("y", function(d) {
return d.visible ? y(d.prod) - 7 : y(-(100 * 100)); // Replace labels with new scale
});
svg.selectAll("line.regressionLine")
.transition()
.attr("x1", x(0))
.attr("x2", function(d) {
if (maxX < maxY) {
return x(maxX);
} else {
return x(maxY);
}
})
.attr("y1", y(0))
.attr("y2", function(d) {
if (maxX < maxY) {
return y(maxX);
} else {
return y(maxY);
}
});
})
.on("mouseover", function(d) {
d3.select("#" + d.name.replace(/\s+/g, "")).transition().style("stroke-width", 2.5)
})
.on("mouseout", function(d) {
d3.select("#" + d.name.replace(/\s+/g, "")).transition().style("stroke-width", 1.5)
});
agencies.append("text")
.attr("x", (width + 30)) // space legend
.attr("y", function(d, i) {
return i * 13 + 9
})
.attr("class", "legend") // style the legend
.text(function(d) {
return d.name
});
function findMaxX(data) { // Define function "findMaxY"
var maxXValues = data.map(function(d) {
console.log(d);
if (d.visible) {
return d3.max(d.values, function(value) { // Return max rating value
return value.cons * 1.05;
})
}
});
return d3.max(maxXValues);
};
function findMaxY(data) { // Define function "findMaxY"
var maxYValues = data.map(function(d) {
if (d.visible) {
return d3.max(d.values, function(value) { // Return max rating value
return value.prod * 1.05;
})
}
});
return d3.max(maxYValues);
};
});
</script>
https://d3js.org/d3.v3.min.js