Created
October 21, 2017 16:31
-
-
Save darthmall/1346bca1b2d7011b267bd6cbf2ac24d2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
| <link rel="stylesheet" href="style.css"> | |
| <title>Simon-Ehrlich Wager</title> | |
| </head> | |
| <body> | |
| <figure id="wager-hx"></figure> | |
| <figure id="metals"></figure> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js"></script> | |
| <script src="main.js"></script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const betPeriod = 10; | |
| function flatMap(fn, arr) { | |
| return Array.prototype.concat.apply([], arr.map(fn)); | |
| } | |
| /** | |
| * Return an array containing the boundary data objects. | |
| */ | |
| function bounds(data, acc) { | |
| function f(res, val) { | |
| if (res.length < 1) return [val, val]; | |
| if (acc(val) < acc(res[0])) res[0] = val; | |
| if (acc(val) > acc(res[1])) res[1] = val; | |
| return res; | |
| } | |
| // Default the accessor to the identity function | |
| acc = acc || (d => d); | |
| return data.reduce(f, []); | |
| } | |
| /** | |
| * Render a line chart from data. | |
| */ | |
| function MetalPrices(el) { | |
| let _data = [], | |
| _highlight = [0, 1], | |
| _width = 960, | |
| _height = 500, | |
| _margin = { | |
| top: 8, | |
| right: 0, | |
| bottom: 16, | |
| left: 32 | |
| }, | |
| _seriesName = d => d.key, | |
| _seriesColor = () => "black"; | |
| // Initialize the chart in the element. | |
| el = d3.select(el).append("svg").classed("line-chart chart", true); | |
| const mask = el.append("defs") | |
| .append("clipPath").attr("id", "highlight") | |
| .append("rect"); | |
| // Create the layers in the chart. | |
| const margin = el.append("g").attr("class", "margin"), | |
| bg = margin.append("rect").attr("class", "bg"), | |
| xAxis = margin.append("g").attr("class", "x axis"), | |
| yAxis = margin.append("g").attr("class", "y axis"), | |
| series = margin.append("g").attr("class", "series"), | |
| seriesFade = series.append("g"), | |
| seriesHighlight = series.append("g").attr("clip-path", "url(#highlight)"), | |
| highlightBrush = seriesHighlight.append("rect").attr("class", "brush bg"), | |
| annotations = margin.append("g").attr("class", "annotations"), | |
| legend = annotations.append("g").attr("class", "legendOrdinal"); | |
| const x = d3.scaleLinear(), | |
| y = d3.scaleLinear(); | |
| function chart() { | |
| const w = _width - _margin.left - _margin.right, | |
| h = _height - _margin.top - _margin.bottom; | |
| el.attr("width", _width) | |
| .attr("height", _height); | |
| margin.attr("transform", `translate(${_margin.left}, ${_margin.top})`); | |
| el.selectAll(".bg").attr("width", w) | |
| .attr("height", h); | |
| x.domain(d3.extent(_data, d => d.year)).range([0, w]); | |
| y.domain(d3.extent(_data, d => d.price)).nice().range([h, 0]); | |
| const nest = d3.nest().key(d => d.type); | |
| const line = d3.line().x(d => x(d.year)).y(d => y(d.price)); | |
| const path = seriesFade.selectAll("path").data(nest.entries(_data)); | |
| path.exit().remove(); | |
| path.enter().append("path") | |
| .merge(path) | |
| .attr("d", d => line(d.values)) | |
| .attr("stroke-dasharray", "3,1") | |
| .style("stroke", d => _seriesColor(_seriesName(d))) | |
| .style("opacity", 0.6); | |
| const highlightPath = seriesHighlight.selectAll("path").data(nest.entries(_data)); | |
| highlightPath.exit().remove(); | |
| highlightPath.enter().append("path") | |
| .merge(highlightPath) | |
| .attr("d", d => line(d.values)) | |
| .style("stroke", d => _seriesColor(_seriesName(d))) | |
| .style("stroke-width", 2); | |
| mask.transition().attr("x", x(_highlight[0])) | |
| .attr("width", x(_highlight[1]) - x(_highlight[0])) | |
| .attr("height", _height); | |
| xAxis.call(d3.axisBottom() | |
| .scale(x) | |
| .tickSize(h) | |
| .tickPadding(8) | |
| .tickFormat(String)); | |
| yAxis.attr("transform", `translate(${w}, 0)`) | |
| .call(d3.axisLeft() | |
| .scale(y) | |
| .tickSize(w)); | |
| el.selectAll(".axis .domain").remove(); | |
| legend.call(d3.legendColor().scale(_seriesColor)) | |
| .attr("transform", function () { | |
| const bbox = this.getBoundingClientRect(); | |
| return `translate(${w - bbox.width - 8}, 8)`; | |
| }); | |
| } | |
| /** | |
| * Data rendered in the chart. | |
| * | |
| * The data should be a 2D array. The outer array contains each series | |
| * rendered as separate lines; each series is an array of points. | |
| */ | |
| chart.data = function (_) { | |
| if (arguments.length < 1) return _data; | |
| _data = _; | |
| return chart; | |
| }; | |
| /** | |
| * A range of years highlighted in the chart. | |
| */ | |
| chart.highlight = function (_) { | |
| if (arguments.length < 1) return _highlight; | |
| _highlight = _; | |
| return chart; | |
| }; | |
| chart.margin = function (_) { | |
| if (arguments.length < 1) return _margin; | |
| Object.assign(_margin, _); | |
| return chart; | |
| }; | |
| chart.seriesColor = function (_) { | |
| if (arguments.length < 1) return _seriesColor; | |
| _seriesColor = _; | |
| return chart; | |
| }; | |
| chart.height = function (_) { | |
| if (arguments.length < 1) return _height; | |
| _height = _; | |
| return chart; | |
| }; | |
| chart.width = function (_) { | |
| if (arguments.length < 1) return _width; | |
| _width = _; | |
| return chart; | |
| }; | |
| return chart; | |
| } | |
| function RugPlot(el) { | |
| var _data = [] | |
| _selected = 0, | |
| _width = 960, | |
| _height = 32, | |
| _margin = { | |
| top: 0, | |
| right: 0, | |
| bottom: 0, | |
| left: 32 | |
| }, | |
| _x = d => d.year, | |
| _xScale = d3.scaleLinear(), | |
| _y = d => d.winner, | |
| _yScale = d3.scaleBand(), | |
| _fringeWidth = 2; | |
| el = d3.select(el).append("svg").classed("rug-chart chart", true); | |
| const margin = el.append("g").attr("class", "margin"), | |
| yAxis = margin.append("g").attr("class", "y axis"), | |
| rug = margin.append("g"); | |
| function chart() { | |
| const w = _width - _margin.left - _margin.right, | |
| h = _height - _margin.top - _margin.bottom; | |
| el.attr("width", _width).attr("height", _height); | |
| margin.attr("transform", `translate(${_margin.left}, ${_margin.top})`); | |
| _xScale.domain(d3.extent(_data, _x)).range([0, w]); | |
| _yScale.domain(_data.map(_y)).range([h, 0]); | |
| const rect = rug.selectAll("rect").data(_data.filter(d => !!_y(d))); | |
| rect.exit().remove(); | |
| rect.enter().append("rect") | |
| .attr("width", _fringeWidth) | |
| .style("cursor", "pointer") | |
| .merge(rect) | |
| .attr("x", d => _xScale(_x(d)) - 1) | |
| .attr("y", d => _yScale(_y(d))) | |
| .attr("height", _yScale.bandwidth()) | |
| .style("fill", d => (d.year === _selected) ? "red" : "steelblue"); | |
| yAxis.call(d3.axisLeft().scale(_yScale)) | |
| .selectAll(".domain").remove(); | |
| } | |
| chart.data = function (_) { | |
| if (arguments.length < 1) return _data; | |
| _data = _; | |
| return chart; | |
| }; | |
| chart.margin = function (_) { | |
| if (arguments.length < 1) return _margin; | |
| Object.assign(_margin, _); | |
| return chart; | |
| }; | |
| chart.selected = function (_) { | |
| if (arguments.length < 1) return _selected; | |
| _selected = _; | |
| return chart; | |
| }; | |
| return chart; | |
| } | |
| function LineChart(el) { | |
| let _data = [], | |
| _width = 179, | |
| _height = _width * .618, | |
| _margin = { | |
| top: 0, | |
| right: 0, | |
| bottom: 0, | |
| left: 0 | |
| }, | |
| _x = d => d.year, | |
| _xScale = d3.scaleLinear(), | |
| _y = d => d.price, | |
| _yScale = d3.scaleLinear(), | |
| _seriesName = d => d.key, | |
| _seriesColor = () => "black"; | |
| el = d3.select(el).classed("line-chart chart", true); | |
| const margin = el.append("g").attr("class", "margin"), | |
| bg = margin.append("rect").attr("class", "bg"), | |
| yAxis = margin.append("g").attr("class", "y axis"), | |
| series = margin.append("g").attr("class", "series"), | |
| annotations = margin.append("g").attr("class", "annotation"); | |
| function chart() { | |
| const w = _width - _margin.left - _margin.right, | |
| h = _height - _margin.top - _margin.bottom; | |
| _xScale.domain(d3.extent(d3.merge(_data), _x)).range([0, w]); | |
| _yScale.domain(d3.extent(d3.merge(_data), _y)).nice().range([h, 0]); | |
| el.attr("width", _width).attr("height", _height); | |
| bg.attr("width", w).attr("height", h); | |
| const line = d3.line() | |
| .x(d => _xScale(_x(d))) | |
| .y(d => _yScale(_y(d))); | |
| const path = series.selectAll(".hx").data(_data); | |
| path.exit().remove(); | |
| path.enter().append("path") | |
| .attr("class", "hx") | |
| .attr("stroke-dasharray", "3,1") | |
| .style("opacity", 0.6) | |
| .merge(path) | |
| .attr("d", line) | |
| .style("stroke", d => _seriesColor(_seriesName(d))); | |
| const trend = series.selectAll(".trend") | |
| .data([bounds(d3.merge(_data), d => d.year)]); | |
| trend.exit().remove(); | |
| trend.enter().append("path") | |
| .attr("class", "trend") | |
| .merge(trend) | |
| .attr("d", line) | |
| .style("stroke", d => _seriesColor(_seriesName(d))); | |
| yAxis.attr("transform", `translate(0,0)`) | |
| .call(d3.axisRight() | |
| .scale(_yScale) | |
| .tickSize(w) | |
| .ticks(3)) | |
| .selectAll(".tick text") | |
| .attr("x", 4) | |
| .attr("dy", "-.35em") | |
| .style("fill", "#aaa"); | |
| yAxis.selectAll(".domain").remove(); | |
| } | |
| chart.data = function (_) { | |
| if (arguments.length < 1) return _data; | |
| _data = _; | |
| return chart; | |
| }; | |
| chart.seriesName = function (_) { | |
| if (arguments.length < 1) return _seriesName; | |
| _seriesName = _; | |
| return chart; | |
| }; | |
| chart.seriesColor = function (_) { | |
| if (arguments.length < 1) return _seriesColor; | |
| _seriesColor = _; | |
| return chart; | |
| }; | |
| return chart; | |
| } | |
| function BetPeriod(el) { | |
| let _data = [], | |
| _seriesName = d => d.key, | |
| _seriesColor = () => "black"; | |
| el = d3.select(el); | |
| function chart() { | |
| const div = el.selectAll("div").data(_data, d => d.key); | |
| div.exit().remove(); | |
| div.enter().append("div") | |
| .merge(div) | |
| .attr("class", "small-multiple") | |
| .each(function (d) { | |
| const el = d3.select(this); | |
| const p = el.selectAll("p").data([d.key]); | |
| p.exit().remove(); | |
| p.enter().append("p") | |
| .merge(p) | |
| .text(String); | |
| const svg = el.selectAll("svg").data([0]); | |
| svg.exit().remove(); | |
| LineChart(svg.enter().append("svg").merge(svg).node()) | |
| .data([d.values]) | |
| .seriesName(() => _seriesName(d)) | |
| .seriesColor(_seriesColor)(); | |
| }); | |
| } | |
| chart.data = function (_) { | |
| if (arguments.length < 1) return _data; | |
| _data = _; | |
| return chart; | |
| }; | |
| chart.seriesColor = function (_) { | |
| if (arguments.length < 1) return _seriesColor; | |
| _seriesColor = _; | |
| return chart; | |
| }; | |
| return chart; | |
| } | |
| function Wager(el, metals, winners) { | |
| const color = d3.scaleOrdinal(d3.schemeCategory10); | |
| const sharedMargin = {left: 64, right: 1}; | |
| const priceHx = MetalPrices("#wager-hx") | |
| .seriesColor(color) | |
| .margin(sharedMargin) | |
| .data(metals) | |
| .highlight([1980, 1990]); | |
| const winnerRug = RugPlot("#wager-hx") | |
| .margin(sharedMargin) | |
| .data(winners) | |
| .selected(1980); | |
| const betData = d3.nest() | |
| .key(d => d.type) | |
| .entries(metals.filter(d => d.year >= 1980 && d.year <= 1990)); | |
| const metalPrices = BetPeriod("#metals") | |
| .data(betData) | |
| .seriesColor(color); | |
| priceHx(); | |
| winnerRug(); | |
| metalPrices(); | |
| d3.selectAll("#wager-hx rect") | |
| .on("click", function (d) { | |
| const start = d.year, | |
| end = start + betPeriod; | |
| const betData = d3.nest() | |
| .key(d => d.type) | |
| .entries(metals.filter(d => d.year >= start && d.year <= end)); | |
| priceHx.highlight([start, end])(); | |
| winnerRug.selected(d.year)(); | |
| metalPrices.data(betData)(); | |
| }); | |
| } | |
| /** | |
| * Convert all properties in row to numbers. | |
| */ | |
| function parse(row) { | |
| for (const k in row) { | |
| row[k] = +row[k]; | |
| } | |
| return row; | |
| } | |
| d3.tsv("metals.tsv", parse, function (data) { | |
| function pivotRow(row) { | |
| const pivot = []; | |
| for (const k in row) { | |
| if (k === "Year") continue | |
| pivot.push({year: row["Year"], type: k, price: row[k]}); | |
| } | |
| // Return an array of observations. This will result in a nested array that | |
| // needs to be flattened. | |
| return pivot | |
| } | |
| // Pivot the columns containing the metal prices into a tidy format where | |
| // each row represents a price observation that contains the year, metal, | |
| // and price | |
| let metals = flatMap(pivotRow, data); | |
| // Sort the array by year | |
| data.sort((a, b) => a.Year - b.Year); | |
| // For each 10 year period in the array, calculate the winner of the bet if it | |
| // had started in that year. | |
| const winners = []; | |
| for (let i = 0, n = data.length; i < n; i++) { | |
| const start = data[i], | |
| end = data[i + betPeriod]; | |
| // Fill out entries for years where there isn't enough data to construct a | |
| // 10-year period, just so that the x scales on the line chart and the rug | |
| // plot have matching domains. | |
| if (!end) { | |
| winners.push({year: start.Year}); | |
| continue; | |
| } | |
| // Skip a 10-year period if we're missing data for that period | |
| if (end.Year - start.Year !== betPeriod) { | |
| console.warn("Missing year", start.Year + betPeriod) | |
| continue; | |
| } | |
| // Track the score for the bettors | |
| let ehrlich = 0, | |
| simon = 0; | |
| // Check each metal for this year | |
| for (const k in start) { | |
| if (k === "Year") continue; | |
| if (end[k] - start[k] > 0) { | |
| ++ehrlich; | |
| } else { | |
| ++simon; | |
| } | |
| } | |
| winners.push({ | |
| year: start.Year, | |
| winner: (ehrlich > simon) ? "Ehrlich" : "Simon" | |
| }); | |
| } | |
| Wager(document.body, metals, winners); | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Year | Tin (98$/t) | Copper (98$/t) | Nickel (98$/t) | Tungsten (98$/t) | Chromium (98$/t) | |
|---|---|---|---|---|---|---|
| 1900 | 12900 | 7000 | 22000 | 11000 | 1090 | |
| 1901 | 7220 | 7000 | 24000 | 7000 | 1160 | |
| 1902 | 11200 | 4800 | 19000 | 8000 | 882 | |
| 1903 | 11300 | 5300 | 16000 | 6300 | 765 | |
| 1904 | 11200 | 5100 | 16000 | 10000 | 836 | |
| 1905 | 12600 | 6300 | 16000 | 14000 | 769 | |
| 1906 | 15900 | 7700 | 16000 | 16000 | 738 | |
| 1907 | 14800 | 7700 | 17000 | 22000 | 652 | |
| 1908 | 11800 | 5300 | 18000 | 14000 | 731 | |
| 1909 | 11900 | 5300 | 16000 | 16000 | 685 | |
| 1910 | 13200 | 5000 | 15000 | 18700 | 608 | |
| 1911 | 16400 | 4900 | 15000 | 15000 | 603 | |
| 1912 | 17200 | 6200 | 15000 | 14800 | 498 | |
| 1913 | 16100 | 5630 | 15300 | 16600 | 501 | |
| 1914 | 12300 | 4760 | 14700 | 16600 | 449 | |
| 1915 | 13700 | 6180 | 14600 | 65800 | 526 | |
| 1916 | 14300 | 9360 | 13800 | 70700 | 660 | |
| 1917 | 17400 | 8190 | 11800 | 32600 | 750 | |
| 1918 | 21100 | 5890 | 9760 | 34900 | 1280 | |
| 1919 | 13200 | 3780 | 8320 | 23600 | 680 | |
| 1920 | 8660 | 3140 | 7530 | 8910 | 333 | |
| 1921 | 5990 | 2540 | 8420 | 10900 | 232 | |
| 1922 | 6980 | 2900 | 8140 | 12600 | 255 | |
| 1923 | 8960 | 3100 | 7560 | 13300 | 265 | |
| 1924 | 10500 | 2790 | 6300 | 11200 | 280 | |
| 1925 | 11900 | 2920 | 6800 | 13700 | 239 | |
| 1926 | 13200 | 2840 | 7280 | 14200 | 232 | |
| 1927 | 13300 | 2690 | 7220 | 13500 | 235 | |
| 1928 | 10600 | 3110 | 7770 | 13800 | 240 | |
| 1929 | 9490 | 3850 | 7350 | 17400 | 255 | |
| 1930 | 6850 | 2860 | 7570 | 16400 | 334 | |
| 1931 | 5790 | 1980 | 8270 | 16400 | 498 | |
| 1932 | 5770 | 1520 | 9190 | 15200 | 635 | |
| 1933 | 10800 | 2020 | 9670 | 16700 | 503 | |
| 1934 | 14000 | 2330 | 9390 | 24600 | 480 | |
| 1935 | 13200 | 2330 | 9190 | 22100 | 530 | |
| 1936 | 12000 | 2520 | 9050 | 24200 | 529 | |
| 1937 | 13600 | 3350 | 8740 | 30700 | 482 | |
| 1938 | 10800 | 2610 | 8930 | 27800 | 494 | |
| 1939 | 13000 | 2900 | 9050 | 27900 | 477 | |
| 1940 | 12800 | 2960 | 8990 | 33400 | 486 | |
| 1941 | 12700 | 2930 | 8560 | 36100 | 455 | |
| 1942 | 11500 | 2650 | 7050 | 33500 | 562 | |
| 1943 | 10800 | 2500 | 6650 | 32900 | 617 | |
| 1944 | 10600 | 2450 | 6530 | 30100 | 651 | |
| 1945 | 10400 | 2410 | 6410 | 29200 | 634 | |
| 1946 | 10000 | 2580 | 6430 | 23400 | 434 | |
| 1947 | 12500 | 3420 | 5640 | 23800 | 466 | |
| 1948 | 14800 | 3320 | 5370 | 24700 | 513 | |
| 1949 | 15000 | 2940 | 6040 | 25100 | 522 | |
| 1950 | 14200 | 3210 | 6700 | 26600 | 503 | |
| 1951 | 17500 | 3400 | 7440 | 53200 | 501 | |
| 1952 | 16300 | 3310 | 7730 | 54300 | 580 | |
| 1953 | 12900 | 3910 | 8050 | 53000 | 669 | |
| 1954 | 12300 | 4000 | 8180 | 52800 | 516 | |
| 1955 | 12700 | 5040 | 8900 | 52300 | 523 | |
| 1956 | 13400 | 5540 | 8560 | 48300 | 577 | |
| 1957 | 12300 | 3840 | 9480 | 19900 | 652 | |
| 1958 | 11800 | 3280 | 9210 | 13800 | 631 | |
| 1959 | 12600 | 3820 | 9110 | 16000 | 756 | |
| 1960 | 12300 | 3920 | 8960 | 17100 | 476 | |
| 1961 | 13700 | 3630 | 9400 | 16200 | 379 | |
| 1962 | 13700 | 3670 | 9510 | 17300 | 673 | |
| 1963 | 13700 | 3640 | 9260 | 15700 | 619 | |
| 1964 | 18300 | 3750 | 9160 | 14800 | 652 | |
| 1965 | 20400 | 4020 | 9020 | 19700 | 670 | |
| 1966 | 18200 | 3990 | 8740 | 23300 | 609 | |
| 1967 | 16500 | 4100 | 9460 | 20000 | 644 | |
| 1968 | 15300 | 4260 | 9810 | 23200 | 645 | |
| 1969 | 16100 | 4650 | 10300 | 23300 | 614 | |
| 1970 | 16100 | 5380 | 11900 | 23700 | 538 | |
| 1971 | 14800 | 4620 | 11800 | 26200 | 755 | |
| 1972 | 15300 | 4420 | 12100 | 22100 | 767 | |
| 1973 | 18400 | 4810 | 12400 | 22000 | 774 | |
| 1974 | 28900 | 5630 | 12700 | 34800 | 1060 | |
| 1975 | 22700 | 4290 | 13800 | 35400 | 1780 | |
| 1976 | 24000 | 4390 | 14200 | 40100 | 1440 | |
| 1977 | 31700 | 3960 | 13400 | 54300 | 1340 | |
| 1978 | 34700 | 3630 | 11300 | 45300 | 1150 | |
| 1979 | 36400 | 4570 | 13200 | 41600 | 1310 | |
| 1980 | 36900 | 4420 | 12300 | 36600 | 1260 | |
| 1981 | 29000 | 3330 | 10700 | 31500 | 1270 | |
| 1982 | 24400 | 2710 | 8130 | 23700 | 1150 | |
| 1983 | 23600 | 2760 | 7650 | 17000 | 1060 | |
| 1984 | 21600 | 2310 | 7490 | 17900 | 1140 | |
| 1985 | 19900 | 2240 | 7540 | 14100 | 1160 | |
| 1986 | 12600 | 2170 | 5770 | 10500 | 1010 | |
| 1987 | 13200 | 2610 | 6940 | 9110 | 944 | |
| 1988 | 13400 | 3660 | 19000 | 10300 | 1440 | |
| 1989 | 15100 | 3800 | 17500 | 13900 | 1630 | |
| 1990 | 10600 | 3380 | 11100 | 10600 | 1110 | |
| 1991 | 9600 | 2890 | 9760 | 11800 | 1080 | |
| 1992 | 10300 | 2750 | 8130 | 10800 | 1020 | |
| 1993 | 8700 | 2280 | 5970 | 7690 | 777 | |
| 1994 | 8950 | 2690 | 6970 | 10400 | 764 | |
| 1995 | 9800 | 3260 | 8800 | 13200 | 1300 | |
| 1996 | 9450 | 2500 | 7790 | 10800 | 970 | |
| 1997 | 8540 | 2400 | 7040 | 9810 | 1040 | |
| 1998 | 8230 | 1730 | 4630 | 8300 | 909 | |
| 1999 | 7900 | 1640 | 5880 | 6920 | 694 | |
| 2000 | 7730 | 1840 | 8180 | 7840 | 721 | |
| 2001 | 6390 | 1560 | 5470 | 11500 | 786 | |
| 2002 | 5830 | 1510 | 6130 | 8230 | 721 | |
| 2003 | 6640 | 1670 | 8530 | 7720 | 790 | |
| 2004 | 10400 | 2550 | 11900 | 10000 | 1190 | |
| 2005 | 8850 | 3200 | 12300 | 24900 | 1260 | |
| 2006 | 10100 | 5610 | 19600 | 29900 | 1140 | |
| 2007 | 15600 | 5680 | 29300 | 28200 | 1580 | |
| 2008 | 18900 | 5330 | 16000 | 26600 | 2640 | |
| 2009 | 14100 | 4040 | 11100 | 19500 | 1540 | |
| 2010 | 20400 | 5740 | 16300 | 20200 | 1980 | |
| 2011 | 25100 | 6490 | 16600 | 33900 | 1970 | |
| 2012 | 20100 | 5750 | 12400 | 40200 | 1810 | |
| 2013 | 16000 | 5240 | 10500 | 32600 | 1650 | |
| 2014 | 15600 | 4830 | 11600 | 31100 | 1670 | |
| 2015 | 11500 | 3890 | 8120 | 26000 | 1540 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| html { | |
| font-family: sans-serif; | |
| } | |
| svg { | |
| font-family: sans-serif; | |
| } | |
| .small-multiple { | |
| display: inline-block; | |
| } | |
| .small-multiple + .small-multiple { | |
| margin-left: 16px; | |
| } | |
| path { | |
| fill: none; | |
| stroke: black; | |
| } | |
| .chart .bg { | |
| fill: #f4f7fa; | |
| } | |
| .chart .brush { | |
| mix-blend-mode: multiply; | |
| } | |
| .tick line { | |
| stroke: white | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment