Used d3 v5 with svg.
- path with curve lineGenerator
- mouse hover, scale invert
- legend clickable
- legend switch All
- color scale
- recalculating y-scale on change
- data sort without accents
Exported gdp data from http://www.ksh.hu/
Used d3 v5 with svg.
Exported gdp data from http://www.ksh.hu/
country | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Ausztria | 213.6 | 220.5 | 226.7 | 231.9 | 242.3 | 254.1 | 267.8 | 284.0 | 293.8 | 288.0 | 295.9 | 310.1 | 318.7 | 323.9 | 333.1 | 344.3 | 356.2 | 369.9 | 386.1 | |
Belgium | 258.2 | 265.8 | 275.1 | 282.6 | 298.7 | 311.5 | 326.7 | 344.7 | 354.1 | 348.8 | 365.1 | 379.1 | 387.5 | 392.3 | 400.1 | 411.1 | 424.6 | 439.2 | 450.5 | |
Bulgária | 14.3 | 15.8 | 17.3 | 18.7 | 20.9 | 23.9 | 27.2 | 32.4 | 37.2 | 37.3 | 38.2 | 41.3 | 41.9 | 41.9 | 42.8 | 45.3 | 48.1 | 51.7 | 55.2 | |
Ciprus | 10.8 | 11.6 | 12.1 | 12.9 | 13.9 | 15.0 | 16.3 | 17.6 | 19.0 | 18.7 | 19.3 | 19.7 | 19.5 | 18.1 | 17.6 | 17.7 | 18.5 | 19.6 | 20.7 | |
Csehország | 66.8 | 75.4 | 87.1 | 88.2 | 96.0 | 109.6 | 123.9 | 138.3 | 161.3 | 148.7 | 156.7 | 164.0 | 161.4 | 157.7 | 156.7 | 168.5 | 176.4 | 191.7 | 206.8 | |
Dánia | 178.0 | 184.0 | 189.8 | 193.4 | 202.4 | 212.8 | 225.5 | 233.4 | 241.6 | 231.3 | 243.2 | 247.9 | 254.6 | 258.7 | 265.8 | 273.0 | 282.1 | 292.8 | 297.6 | |
Egyesült Királyság | 1787.3 | 1816.2 | 1881.2 | 1809.1 | 1934.5 | 2030.9 | 2150.3 | 2252.5 | 1984.0 | 1725.4 | 1850.5 | 1894.9 | 2089.6 | 2074.0 | 2287.9 | 2611.9 | 2403.4 | 2338.0 | 2393.7 | |
Észtország | 6.2 | 7.0 | 7.8 | 8.7 | 9.7 | 11.3 | 13.5 | 16.2 | 16.5 | 14.1 | 14.7 | 16.7 | 17.9 | 18.9 | 20.1 | 20.7 | 21.7 | 23.6 | 25.7 | |
Finnország | 136.3 | 144.4 | 148.3 | 151.6 | 158.5 | 164.4 | 172.6 | 186.6 | 193.7 | 181.0 | 187.1 | 196.9 | 199.8 | 203.3 | 205.5 | 210.0 | 216.1 | 223.9 | 233.6 | |
Franciaország | 1478.6 | 1538.2 | 1587.8 | 1630.7 | 1704.0 | 1765.9 | 1848.2 | 1941.4 | 1992.4 | 1936.4 | 1995.3 | 2058.4 | 2088.8 | 2117.2 | 2149.8 | 2198.4 | 2234.1 | 2295.1 | 2353.1 | |
Görögország | 143.0 | 152.2 | 163.5 | 178.9 | 193.7 | 199.2 | 217.9 | 232.7 | 242.0 | 237.5 | 226.0 | 207.0 | 191.2 | 180.7 | 178.7 | 177.3 | 176.5 | 180.2 | 184.7 | |
Hollandia | 452.0 | 481.9 | 501.1 | 512.8 | 529.3 | 550.9 | 584.5 | 619.2 | 647.2 | 624.8 | 639.2 | 650.4 | 653.0 | 660.5 | 671.6 | 690.0 | 708.3 | 737.0 | 773.4 | |
Horvátország | 23.6 | 26.0 | 28.5 | 30.7 | 33.4 | 36.5 | 40.2 | 43.9 | 48.1 | 45.1 | 45.2 | 44.8 | 44.0 | 43.8 | 43.4 | 44.6 | 46.6 | 49.0 | 51.5 | |
Írország | 108.4 | 122.0 | 136.0 | 145.6 | 156.1 | 170.2 | 185.0 | 197.2 | 187.8 | 170.1 | 167.7 | 171.1 | 175.2 | 179.9 | 195.3 | 262.5 | 273.2 | 294.1 | 318.5 | |
Lengyelország | 186.4 | 212.4 | 210.1 | 192.3 | 206.1 | 246.2 | 274.6 | 313.9 | 366.2 | 317.1 | 361.8 | 380.2 | 389.4 | 394.7 | 411.2 | 430.3 | 426.5 | 467.3 | 496.5 | |
Lettország | 8.6 | 9.4 | 10.2 | 10.5 | 11.7 | 13.7 | 17.3 | 22.7 | 24.4 | 18.7 | 17.8 | 20.2 | 22.1 | 22.8 | 23.6 | 24.3 | 25.0 | 27.0 | 29.5 | |
Litvánia | 12.5 | 13.7 | 15.2 | 16.7 | 18.2 | 21.0 | 24.1 | 29.0 | 32.7 | 26.9 | 28.0 | 31.3 | 33.3 | 35.0 | 36.6 | 37.4 | 38.8 | 42.2 | 45.1 | |
Luxemburg | 23.1 | 23.8 | 25.1 | 26.2 | 27.9 | 30.0 | 33.8 | 37.2 | 38.1 | 37.0 | 40.2 | 43.2 | 44.1 | 46.5 | 49.8 | 51.6 | 53.3 | 55.3 | 58.9 | |
Magyarország | 51.3 | 60.1 | 71.9 | 75.5 | 83.8 | 90.9 | 91.8 | 102.2 | 108.1 | 94.3 | 98.8 | 101.3 | 99.5 | 101.9 | 105.5 | 110.9 | 113.9 | 124.1 | 131.9 | |
Málta | 4.4 | 4.5 | 4.7 | 4.8 | 4.9 | 5.1 | 5.4 | 5.8 | 6.1 | 6.1 | 6.6 | 6.8 | 7.2 | 7.6 | 8.5 | 9.6 | 10.3 | 11.3 | 12.3 | |
Németország | 2,116.5 | 2,179.9 | 2,209.3 | 2,220.1 | 2,270.6 | 2,300.9 | 2,393.3 | 2,513.2 | 2,561.7 | 2,460.3 | 2,580.1 | 2,703.1 | 2,758.3 | 2,826.2 | 2,938.6 | 3,048.9 | 3,159.8 | 3,277.3 | 3,386.0 | |
Olaszország | 1,239.3 | 1,298.9 | 1,345.8 | 1,390.7 | 1,448.4 | 1,489.7 | 1,548.5 | 1,609.6 | 1,632.2 | 1,572.9 | 1,604.5 | 1,637.5 | 1,613.3 | 1,604.6 | 1,621.8 | 1,652.1 | 1,689.8 | 1,727.4 | 1,757.0 | |
Portugália | 128.5 | 135.8 | 142.6 | 146.2 | 152.4 | 158.7 | 166.2 | 175.5 | 178.9 | 175.4 | 179.9 | 176.2 | 168.4 | 170.3 | 173.1 | 179.8 | 186.5 | 194.6 | 201.6 | |
Románia | 40.6 | 45.1 | 48.7 | 51.1 | 60.4 | 79.2 | 97.2 | 127.6 | 146.6 | 125.2 | 125.4 | 131.9 | 133.1 | 143.8 | 150.5 | 160.3 | 170.4 | 187.5 | 202.9 | |
Spanyolország | 646.3 | 699.5 | 749.3 | 803.5 | 861.4 | 930.6 | 1,008.0 | 1,080.8 | 1,116.2 | 1,079.1 | 1,080.9 | 1,070.4 | 1,039.8 | 1,025.7 | 1,037.8 | 1,081.2 | 1,118.7 | 1,166.3 | 1,208.2 | |
Svédország | 282.2 | 268.2 | 281.0 | 293.8 | 307.8 | 313.6 | 335.3 | 356.9 | 352.7 | 310.0 | 369.5 | 405.4 | 423.8 | 436.2 | 433.1 | 449.2 | 463.1 | 475.2 | 466.9 | |
Szlovákia | 22.3 | 23.9 | 26.3 | 30.1 | 34.7 | 39.3 | 45.5 | 56.2 | 66.0 | 64.0 | 67.6 | 70.6 | 72.7 | 74.2 | 76.1 | 79.1 | 81.2 | 84.9 | 90.2 | |
Szlovénia | 21.9 | 23.2 | 25.1 | 26.3 | 27.7 | 29.2 | 31.6 | 35.2 | 38.0 | 36.2 | 36.3 | 36.9 | 36.1 | 36.2 | 37.6 | 38.9 | 40.4 | 43.0 | 45.9 | |
Európai Unió–28 | 9,661.0 | 10,059.3 | 10,427.5 | 10,583.2 | 11,109.7 | 11,604.4 | 12,272.0 | 13,005.7 | 13,086.5 | 12,330.6 | 12,841.5 | 13,217.5 | 13,484.2 | 13,596.8 | 14,072.0 | 14,828.7 | 14,963.8 | 15,389.3 | 15,884.0 | |
Eurózóna–19 | 7,030.3 | 7,356.1 | 7,611.9 | 7,830.5 | 8,164.3 | 8,460.8 | 8,906.0 | 9,404.6 | 9,640.7 | 9,296.2 | 9,552.2 | 9,805.6 | 9,846.8 | 9,944.0 | 10,175.2 | 10,534.8 | 10,833.2 | 11,212.0 | 11,581.0 | |
Észak-Macedónia | 4.1 | 4.1 | 4.2 | 4.4 | 4.6 | 5.0 | 5.5 | 6.1 | 6.8 | 6.8 | 7.1 | 7.5 | 7.6 | 8.1 | 8.6 | 9.1 | 9.7 | 10.0 | 10.7 | |
Norvégia | 185.9 | 194.4 | 207.8 | 202.4 | 212.9 | 248.3 | 275.3 | 293.3 | 317.2 | 278.6 | 324.0 | 358.7 | 397.1 | 394.0 | 376.6 | 348.4 | 335.7 | 354.3 | 368.4 | |
Oroszország | 302.1 | 368.0 | 392.3 | 410.3 | 512.0 | 661.5 | 849.9 | 1,022.6 | 1,220.7 | 947.0 | 1,238.8 | 1,474.5 | 1,707.2 | 1,727.4 | 1,554.4 | 1,222.7 | 1,160.5 | .. | .. | |
Svájc | 294.9 | 311.3 | 320.2 | 312.4 | 317.5 | 328.7 | 343.5 | 350.7 | 378.2 | 390.2 | 441.1 | 504.0 | 519.7 | 518.4 | 534.9 | 612.7 | 605.8 | 601.4 | 597.3 | |
Szerbia | .. | .. | 17.1 | 18.7 | 20.0 | 22.3 | 25.9 | 31.6 | 35.7 | 32.5 | 31.5 | 35.4 | 33.7 | 36.4 | 35.5 | 35.7 | 36.7 | 39.2 | 42.8 | |
Törökország | 296.9 | 222.6 | 249.6 | 276.1 | 324.7 | 401.7 | 436.3 | 492.8 | 521.8 | 461.9 | 581.0 | 596.5 | 678.5 | 714.3 | 703.4 | 773.0 | 780.2 | 753.9 | .. | |
India | .. | 540.7 | 535.5 | 523.7 | 558.4 | 653.4 | 732.6 | 857.1 | 858.2 | 932.5 | 1,245.8 | 1,346.4 | 1,449.6 | 1,441.5 | 1,538.5 | 1,933.3 | 2,051.0 | 2,281.1 | .. | |
Izrael | .. | 145.9 | 128.0 | 112.5 | 108.9 | 114.5 | 122.7 | 130.5 | 147.4 | 149.2 | 176.7 | 188.1 | 200.4 | 220.6 | 233.8 | 270.8 | 288.7 | 313.0 | 312.9 | |
Japán | 5,295.1 | 4,812.3 | 4,370.5 | 3,935.3 | 3,875.1 | 3,830.0 | 3,608.3 | 3,297.3 | 3,415.6 | 3,755.6 | 4,304.5 | 4,428.7 | 4,829.3 | 3,880.7 | 3,662.4 | 3,955.9 | 4,459.1 | 4,302.1 | 4,209.4 | |
Kína | .. | 1,495.5 | 1,555.2 | 1,467.8 | 1,571.8 | 1,837.3 | 2,192.3 | 2,592.6 | 3,122.6 | 3,657.9 | 4,593.8 | 5,424.0 | 6,644.9 | 7,262.6 | 7,834.2 | 9,837.4 | 10,065.8 | 10,758.3 | 11,530.5 | |
Koreai Köztársaság | 608.7 | 595.9 | 648.2 | 602.1 | 615.8 | 722.2 | 806.0 | 819.5 | 687.7 | 649.6 | 826.0 | 864.7 | 951.5 | 983.2 | 1,062.9 | 1,244.8 | 1,278.5 | 1,355.3 | 1,372.0 | |
Dél-afrikai Köztársaság | 148.1 | 136.1 | 122.9 | 155.4 | 184.4 | 207.0 | 215.6 | 218.4 | 196.5 | 214.8 | 283.3 | 299.5 | 308.4 | 275.8 | 264.2 | 285.8 | 268.0 | 309.2 | 312.1 | |
Egyiptom | 113.4 | 114.2 | 95.5 | 75.3 | 66.6 | 75.7 | 89.9 | 100.0 | 116.1 | 142.2 | 173.5 | 178.0 | 217.0 | 216.9 | 230.0 | 299.3 | 300.4 | 209.4 | 211.3 | |
Brazília | .. | 624.5 | 533.7 | 495.1 | 538.4 | 714.9 | 881.5 | 1,021.4 | 1,163.1 | 1,204.4 | 1,666.7 | 1,881.1 | 1,919.5 | 1,858.5 | 1,851.6 | 1,620.3 | 1,625.3 | 1,817.8 | .. | |
Egyesült Államok | 11,100.4 | 11,815.3 | 11,565.6 | 10,129.3 | 9,818.9 | 10,478.8 | 11,002.4 | 10,545.0 | 10,003.3 | 10,359.1 | 11,308.8 | 11,165.6 | 12,606.6 | 12,638.2 | 13,189.1 | 16,421.2 | 16,900.5 | 17,248.3 | 17,353.2 | |
Kanada | 807.0 | 825.5 | 804.5 | 793.3 | 826.2 | 942.2 | 1,051.2 | 1,074.8 | 1,062.6 | 991.4 | 1,220.5 | 1,289.2 | 1,422.8 | 1,390.1 | 1,360.7 | 1,403.1 | 1,383.6 | 1,462.1 | 1,450.9 | |
Mexikó | 766.2 | 844.5 | 813.7 | 644.2 | 628.9 | 705.0 | 776.3 | 768.3 | 758.3 | 647.0 | 798.6 | 848.3 | 935.8 | 959.5 | 989.7 | 1,053.1 | 973.4 | 1,027.8 | 1,036.9 | |
Ausztrália | 443.7 | 435.5 | 461.0 | 495.4 | 545.6 | 610.6 | 651.9 | 720.2 | 723.6 | 734.0 | 982.2 | 1,112.0 | 1,238.3 | 1,160.3 | 1,103.6 | 1,124.9 | 1,185.6 | 1,254.2 | 1,227.3 | |
Új-Zéland | 59.1 | 60.4 | 66.4 | 74.3 | 82.5 | 92.3 | 88.8 | 100.3 | 91.3 | 87.8 | 110.7 | 121.2 | 137.1 | 143.6 | 151.4 | 159.5 | 169.9 | 179.4 | 173.6 |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font: 10px sans-serif; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.y.axis path { | |
display: none; | |
} | |
g.legend { | |
cursor: pointer; | |
} | |
</style> | |
<body> | |
<script src="https://d3js.org/d3.v5.min.js"></script> | |
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script> | |
<script> | |
const | |
title = "A GDP nagysága (folyó áron) – ESA2010 (2000–) [milliárd euró]", | |
legend = {width: 100, height: 16 * 50}, | |
margin = {top: 20, right: 20, bottom: 30, left: 40}, | |
width = document.body.clientWidth - margin.left - margin.right - legend.width, | |
height = Math.max(document.documentElement.clientHeight - margin.top - margin.bottom, legend.height - margin.top - margin.bottom), | |
y = d3.scaleLinear().range([height, 0]), | |
x = d3.scaleBand().range([0, width]), | |
colorScale = d3.scaleBand().range([0, 1]), | |
colors = x => d3.interpolateSinebow(colorScale(x)), | |
xAxis = d3.axisBottom().scale(x), | |
yAxis = d3.axisLeft().scale(y).tickFormat(d3.format(".2s")), | |
isNumber = v => Number.isFinite(Number(v)), | |
rowKeys = data => Object.keys(data).filter(isNumber), | |
sanitize = str => typeof str == 'string' ? str.replace(/,/g, '') : str, | |
rowVals = rowData => Object.values(rowData).map(sanitize).filter(isNumber), | |
countries = data => data.map(d => d.country).sort((a, b) => a.localeCompare(b, 'en', {sensitivity: 'base'})), | |
maxVal = data => { | |
const rowMaxArr = data.map(d => Math.max(...rowVals(d))); | |
return Math.max(...rowMaxArr); | |
}; | |
makeInvertable = (axis, t) => { | |
axis.invert = x => { | |
const domain = axis.domain(), | |
range = axis.range(), | |
invertScale = t ? t.domain(range).range(domain) : | |
d3.scaleQuantize().domain(range).range(domain); | |
return invertScale(x); | |
}; | |
}; | |
makeInvertable(x); | |
makeInvertable(y, d3.scaleLinear()); | |
const svgNode = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right + legend.width) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", `translate(${margin.left},${margin.top})`); | |
svgNode.append('text') | |
.text(title); | |
drawHower = d => { | |
hoverNode.attr('transform', `translate(${d.x || 0},${d.y || 0})`); | |
hoverNode.select('text.value').text(`${d.value ? d.value.toFixed(2) : ''}`); | |
hoverNode.select('text.country').text(`${d.country || ''}`); | |
hoverNode.selectAll('line') | |
.data([d]) | |
.join('line') | |
.attr('x1', 0) | |
.attr('x2', 0) | |
.attr('y1', 0) | |
.attr('y2', d.y ? height - d.y : 0) | |
.attr('style', d => `stroke:${colors(d.country)}`); | |
}; | |
// global data | |
let legendData = null; | |
let labels; | |
// fix nodes | |
let linesNode = svgNode.append('g'), | |
hoverNode = svgNode.append('g') | |
.attr('class', 'hover'), | |
legendNode; | |
hoverNode.append('text').attr('class', 'value'); | |
hoverNode.append('text').attr('class', 'country').attr('transform', `translate(0,10)`); | |
const selectedCountriesData = d => { | |
const selected = legendData.filter(l => l.selected).map(l => l.name); | |
return d.filter(d => selected.includes(d.country)); | |
}; | |
const draw = (data) => { | |
// Initially generate legendData | |
if (!legendData) { | |
legendData = countries(data).map(d => ({name: d, selected: true})); | |
legendData.push({name: 'All'}) | |
labels = rowKeys(data[0]); | |
x.domain(labels); | |
colorScale.domain(countries(data)); | |
legendNode = svgNode.append('g') | |
.attr('class', 'legend') | |
.attr('transform', `translate(${width},0)`); | |
} | |
// data -> all the countries | |
// filteredData -> countries selected on legend | |
const filteredData = selectedCountriesData(data); | |
y.domain([0, maxVal(filteredData)]); // always recalc | |
// Always redraw Y axis REMOVE + APPEND | |
svgNode.selectAll('g.axis').remove(); | |
svgNode.append("g") | |
.attr("class", "y axis") | |
.call(yAxis) | |
.append("text") | |
.attr("transform", "rotate(-90)") | |
.attr("y", 6) | |
.attr("dy", ".7em") | |
.style("text-anchor", "end"); | |
svgNode.append("g") | |
.attr("class", "x axis") | |
.attr("transform", `translate(${-x.bandwidth() / 2},${height})`) | |
.call(xAxis); | |
const linesJoin = linesNode | |
.selectAll('path') | |
.data(filteredData); | |
// JOIN lifecycle | |
linesJoin | |
.join('path') | |
.attr('style', d => `fill:none;stroke:${colors(d.country)};stroke-width:2`) | |
.attr('country', d => d.country) | |
.datum(d => rowVals(d).map(v => ({ | |
value: v | |
}) | |
)) | |
.attr('d', | |
d3.line() | |
.curve(d3.curveMonotoneX) | |
.x((v, i) => x(labels[i])) | |
.y(v => y(v.value))) | |
.on('mouseover', function (d) { | |
const [x1, y1] = d3.mouse(this); | |
drawHower({ | |
country: d3.select(this).attr('country'), | |
date: x.invert(x1), | |
value: y.invert(y1), | |
x: x1, | |
y: y1 | |
}); | |
}); | |
const drawLegend = legendData => { | |
const legendCountriesJoin = legendNode.selectAll('.country') | |
.data(legendData); | |
/* | |
* WHEN legendCountriesJoin ENTERS new data | |
* */ | |
const country = legendCountriesJoin | |
.enter() | |
.append('g') | |
.attr('class', 'country') | |
.attr('transform', (d, i) => `translate(0,${i * 15})`); | |
/** | |
* WHEN legendCountriesJoin UPDATES data | |
*/ | |
legendCountriesJoin | |
.join() | |
.select('polyline') | |
.attr('style', d => `fill:${d.selected ? colors(d.name) : 'none'};stroke:black;stroke-width:1`); | |
country.on('click', d => { | |
if (d.name == 'All') { | |
legendData.forEach(d => d.selected = !d.selected) | |
} else { | |
d.selected = !d.selected; | |
} | |
drawHower({}); | |
draw(data); | |
}); | |
country.append('polyline') | |
.attr('points', '5,0 10,5 5,10 0,5 5,0') | |
.attr('style', d => `fill:${d.selected ? colors(d.name) : 'none'};stroke:black;stroke-width:1`) | |
.attr('transform', 'translate(0,-8)'); | |
country.append('text') | |
.text(d => d.name) | |
.attr('transform', 'translate(15,0)'); | |
//https://stackoverflow.com/questions/30617719/why-d3-updates-entire-data | |
function key(d, i, j) { | |
console.log((Array.isArray(this) ? "data\t" : "node\t") + d); | |
return i; | |
} | |
}; | |
drawLegend(legendData); | |
}; | |
// Let's kick-off the party | |
d3.csv("gdp_world.csv").then(draw); | |
</script> | |
</body> |