D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
danaoira
Full window
Github gist
nations-line-v1
Built with
blockbuilder.org
<!DOCTYPE html> <head> <script src="https://d3js.org/d3.v4.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> body { margin: 0; position: fixed; top: 0; right: 0; bottom: 0; left: 0; } .title { font-family: "Georgia"; font-size: 32px; fill: #000; } .axis { font-family: "Arial"; font-size: 11px; fill: #808080; } .circle { fill-opacity: 0.75; stroke: #c0c0c0; } .domain { stroke: #c0c0c0; } .tick > line { stroke: #c0c0c0; } .line1 { fill: none; stroke: pink; stroke-width: 3px; } .line2 { fill: none; stroke: darkseagreen; stroke-width: 3px; } </style> </head> <body> <div class="container" style="width: 960px;"> <div class="row"> <div class="col-md-4 col-xs-4"> <p>Country 1</p> <select id="x-menu"></select> </div> <div class="col-md-4 col-xs-4"> <p>Country 2</p> <select id="y-menu"></select> </div> <div class="col-md-4 col-xs-4"> <form id="series"> <input type="radio" id="income" name="series" value="income" checked /> Income<br/> <input type="radio" id="lifeExpectancy" name="series" value="lifeExpectancy" /> Life Expectancy<br/> <input type="radio" id="population" name="series" value="population" /> Population<br/> </form> </div> </div> <div class="row"> <div class="col-md-12 col-xs-12 graph"> </div> </div> </div> <script> var scales = {}; var series = ["income", "lifeExpectancy", "population"]; var populateMenus = function(data, menuID, defaultVal) { var dropdown = d3.select(menuID); dropdown.selectAll("option") .data(data) .enter() .append("option") .attr("value", function(d) { return d.name }) .attr("selected", function(d) { if (d.name == defaultVal) { return "selected"; } }) .text(function(d) { return d.name }); } var appendRadioButtons = function(input) { var form = d3.select("#series"); form.selectAll("input") .data(input) .enter() .append("input") .attr("type", "radio") .attr("id", function(d) { return d }) .attr("value", function(d) { return d }) .attr("name", "series") .attr("checked", function(d, i) { if (i === 0) { return "checked" } }) .text(function(d) { return d }); } var processData = function(data, yrExtent) { var result = []; for (yr = yrExtent[0]; yr <= yrExtent[1]; yr++) { var yrResult = []; data.forEach(function(d) { var nation = { income: null, lifeExpectancy: null, name: null, population: null, region: null } var incomeData = getAttrByYear(d, nation, yr, "income"); var lifeExpData = getAttrByYear(d, nation, yr, "lifeExpectancy"); var populationData = getAttrByYear(d, nation, yr, "population"); nation.name = d.name; nation.region = d.region; yrResult.push(nation); }); result[yr] = yrResult; } return result; } var getMinMax = function(input, attr) { var min = 99999999; var max = 0; input.forEach(function(d) { d[attr].forEach(function(i) { if (i[1] < min) { min = i[1]; } if (i[1] > max) { max = i[1]; } }); }); return [min, max]; } var update = function(data, svg, nation1, nation2, series) { var selection = svg.selectAll("circle") .data(newData); selection.enter() .append("circle") .merge(selection) .transition() .attr("cx", function(d) { if (d.income != null) { return scales.xSca(d.income) }}) .attr("cy", function(d) { if (d.lifeExpectancy != null) { return scales.ySca(d.lifeExpectancy) } }) .attr("r", function(d) { if ((d.income && d.lifeExpectancy && d.population) != null) { return scales.rSca(d.population) } }) .attr("id", function(d) { return d.name }) .attr("fill", function(d) { return scales.cSca(d.region) }) .attr("class", "circle"); d3.select(".year").text(year); selection.exit().remove(); } var getExtent = function(data, offset) { var minYear; var maxYear; data.forEach(function(d) { var inc = d.income.sort(); var incMin = inc.slice(0)[0][offset]; if (minYear > incMin | !(minYear)) { minYear = incMin; } var incMax = inc.slice(-1)[0][offset]; if (maxYear < incMax | !(maxYear)) { maxYear } var life = d.lifeExpectancy.sort(); var lifeMin = inc.slice(0)[0][offset]; if (minYear > lifeMin | !(minYear)) { minYear = lifeMin; } var lifeMax = inc.slice(-1)[0][offset]; if (maxYear < lifeMax | !(maxYear)) { maxYear = lifeMax; } var pop = d.population.sort(); var popMin = inc.slice(0)[0][offset]; if (minYear > popMin | !(minYear)) { minYear = popMin; } var popMax = inc.slice(-1)[0][offset]; if (maxYear < popMax | !(maxYear)) { maxYear = popMax; } }) return [minYear, maxYear]; } var getAttrByYear = function(input, output, year, attr) { input[attr].forEach(function(d) { if (d[0] === year) { return output[attr] = d[1]; } }); } d3.json("nations.json", function(error, data) { if (error) return error; console.log(data); // original data // input: old data => output: min/max years of all data yrExtent = getExtent(data, 0); newData = processData(data, yrExtent); minData = newData[1800]; console.log(newData); // filtered data // populate menus populateMenus(minData, "#x-menu", "United States"); populateMenus(minData, "#y-menu", "Canada"); // refactor to getNationData() var nation1Data = d3.nest() .key(function(d) { return d.name == "United States" }) .object(data); var nation2Data = d3.nest() .key(function(d) { return d.name == "Canada" }) .object(data); var nation1Series = nation1Data["true"][0].income; var nation2Series = nation2Data["true"][0].income; console.log("nation1Series", nation1Series); console.log("nation2Series", nation2Series); // vars ----------------------------------------------------------- var margin = { top: 20, right: 20, bottom: 20, left: 50 }; var width = 930 - margin.left - margin.right; var height = 430 - margin.top - margin.bottom; // min-max var xExtent = yrExtent; var yExtent = getExtent(data, 1); // var rExtent = getMinMax(data, "population"); var colorDomain = d3.nest().key(function(d) { return d.region }).object(minData); // console.log("colorDomain", colorDomain); // console.log("xExtent = ", xExtent, "yExtent = ", yExtent); // scales var xScale = d3.scaleTime() .domain([new Date(1800), new Date(2009)]) .range([0, width]); var yScale = d3.scaleLinear() .domain(yExtent) .range([height, 0]); // var rScale = d3.scaleSqrt() // .domain(rExtent) // .range([0,90]); var colorScale = d3.scaleOrdinal() .domain(colorDomain) .range(["Pink", "LightCyan", "Gainsboro", "Thistle", "MintCream", "LemonChiffon"]); // axes var x = d3.axisBottom() .scale(xScale) .tickFormat(d3.timeFormat("%Y")); var y = d3.axisLeft() .scale(yScale); // graph ---------------------------------------------------------- // svg var svg = d3.select(".graph") .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 + ")"); // axes var xAxis = svg.append("g") .call(x) .attr("transform", "translate(0, " + height + ")"); var yAxis = svg.append("g") .call(y); // labels var yLabel = yAxis.append("text") .text("income (dollars)") .attr("class", "axis") .attr("transform", "translate(15, 0) rotate(-90)") .attr("text-anchor", "end"); var gNation1 = svg.append("g") .attr("id", "nation1"); var gNation2 = svg.append("g") .attr("id", "nation2"); var line = d3.line() .x(function(d) { return xScale(d[0]) }) .y(function(d) { return yScale(d[1]) }); var path1 = svg .append("path") .attr("class", "line1") .datum(nation1Series) .attr("d", line); var path2 = svg .append("path") .attr("class", "line2") .datum(nation2Series) .attr("d", line); }); </script> </body> </html>
https://d3js.org/d3.v4.min.js