Skip to content

Instantly share code, notes, and snippets.

@LemoNode
Last active May 21, 2020 13:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save LemoNode/a9dc1a454fdc80ff2a738a9990935e9d to your computer and use it in GitHub Desktop.
Save LemoNode/a9dc1a454fdc80ff2a738a9990935e9d to your computer and use it in GitHub Desktop.
Multiline chart
license: gpl-3.0
date New York_1 San Francisco_1 Austin_1 New York_2 San Francisco_2 Austin_2
20120101 46 53 55 8 12 13
20120102 43 53 48 6 12 9
20120103 30 49 41 -1 9 5
20120104 19 52 48 -7 11 9
20120105 32 52 54 0 11 12
20120106 41 49 61 5 9 16
20120107 47 51 59 8 11 15
20120108 46 56 52 8 13 11
20120109 34 52 54 1 11 12
20120110 39 51 47 4 11 8
20120111 40 49 49 4 9 9
20120112 45 51 48 7 11 9
20120113 40 53 40 4 12 4
20120114 30 52 43 -1 11 6
20120115 23 49 45 -5 9 7
20120116 22 45 65 -6 7 18
20120117 39 43 68 4 6 20
20120118 43 45 47 6 7 8
20120119 26 47 57 -3 8 14
20120120 32 51 61 0 11 16
20120121 27 53 54 -3 12 12
20120122 25 48 56 -4 9 13
20120123 39 52 54 4 11 12
20120124 48 49 52 9 9 11
20120125 43 52 61 6 11 16
20120126 37 53 55 3 12 13
20120127 48 50 50 9 10 10
20120128 43 50 52 6 10 11
20120129 40 53 44 4 12 7
20120130 38 51 49 3 11 9
20120131 43 50 62 6 10 17
20120201 50 50 64 10 10 18
20120202 45 51 61 7 11 16
20120203 37 51 70 3 11 21
20120204 40 52 61 4 11 16
20120205 36 53 48 2 12 9
20120206 39 54 44 4 12 7
20120207 43 54 51 6 12 11
20120208 36 51 49 2 11 9
20120209 36 53 45 2 12 7
20120210 38 53 54 3 12 12
20120211 36 52 44 2 11 7
20120212 29 50 36 -2 10 2
20120213 33 49 44 1 9 7
20120214 39 48 52 4 9 11
20120215 42 49 68 6 9 20
20120216 39 52 54 4 11 12
20120217 46 49 53 8 9 12
20120218 41 51 56 5 11 13
20120219 39 47 50 4 8 10
20120220 38 48 53 3 9 12
20120221 37 49 61 3 9 16
20120222 45 53 68 7 12 20
20120223 50 54 69 10 12 21
20120224 42 55 59 6 13 15
20120225 42 51 47 6 11 8
20120226 36 47 47 2 8 8
20120227 40 45 61 4 7 16
20120228 45 47 67 7 8 19
20120229 40 49 70 4 9 21
20120301 41 48 62 5 9 17
20120302 36 48 72 2 9 22
20120303 47 50 59 8 10 15
20120304 44 55 51 7 13 11
20120305 38 48 55 3 9 13
20120306 32 48 61 0 9 16
20120307 43 49 67 6 9 19
20120308 51 49 72 11 9 22
20120309 47 51 46 8 11 8
20120310 37 49 46 3 9 8
20120311 42 50 56 6 10 13
20120312 48 48 61 9 9 16
20120313 52 53 68 11 12 20
20120314 60 55 71 16 13 22
20120315 47 55 72 8 13 22
20120316 44 54 72 7 12 22
20120317 48 48 71 9 9 22
20120318 48 47 71 9 8 22
20120319 53 45 73 12 7 23
20120320 57 49 63 14 9 17
20120321 57 51 60 14 11 16
20120322 57 51 62 14 11 17
20120323 61 48 61 16 9 16
20120324 55 49 62 13 9 17
20120325 48 46 64 9 8 18
20120326 49 49 66 9 9 19
20120327 39 54 65 4 12 18
20120328 49 54 69 9 12 21
20120329 56 52 69 13 11 21
20120330 46 54 73 8 12 23
20120331 42 56 73 6 13 23
20120401 45 51 75 7 11 24
20120402 48 50 75 9 10 24
20120403 51 52 77 11 11 25
20120404 61 50 67 16 10 19
20120405 50 47 71 10 8 22
20120406 48 47 70 9 8 21
20120407 51 49 73 11 9 23
20120408 55 50 71 13 10 22
20120409 58 51 70 14 11 21
20120410 55 53 69 13 12 21
20120411 49 52 69 9 11 21
20120412 51 53 74 11 12 23
20120413 53 50 73 12 10 23
20120414 55 50 76 13 10 24
20120415 62 51 74 17 11 23
20120416 62 51 63 17 11 17
20120417 69 53 67 21 12 19
20120418 59 53 65 15 12 18
20120419 54 55 67 12 13 19
20120420 56 55 68 13 13 20
20120421 58 58 65 14 14 18
20120422 52 52 65 11 11 18
20120423 51 55 70 11 13 21
20120424 49 57 67 9 14 19
20120425 52 57 75 11 14 24
20120426 50 55 77 10 13 25
20120427 51 53 77 11 12 25
20120428 47 54 77 8 12 25
20120429 54 54 77 12 12 25
20120430 51 53 77 11 12 25
20120501 57 52 77 14 11 25
20120502 53 50 77 12 10 25
20120503 53 52 79 12 11 26
20120504 57 53 80 14 12 27
20120505 57 53 82 14 12 28
20120506 56 56 79 13 13 26
20120507 54 55 79 12 13 26
20120508 57 52 70 14 11 21
20120509 59 52 69 15 11 21
20120510 61 53 71 16 12 22
20120511 59 53 69 15 12 21
20120512 64 49 72 18 9 22
20120513 65 52 72 18 11 22
20120514 64 56 72 18 13 22
20120515 62 53 67 17 12 19
20120516 63 51 69 17 11 21
20120517 64 51 72 18 11 22
20120518 61 52 73 16 11 23
20120519 62 52 77 17 11 25
20120520 66 54 75 19 12 24
20120521 62 52 76 17 11 24
20120522 63 53 78 17 12 26
20120523 66 56 77 19 13 25
20120524 64 54 80 18 12 27
20120525 65 52 81 18 11 27
20120526 69 52 82 21 11 28
20120527 71 52 80 22 11 27
20120528 74 52 80 23 11 27
20120529 75 52 82 24 11 28
20120530 72 52 81 22 11 27
20120531 72 53 82 22 12 28
20120601 67 54 77 19 12 25
20120602 68 54 81 20 12 27
20120603 67 52 82 19 11 28
20120604 61 55 81 16 13 27
20120605 58 53 83 14 12 28
20120606 61 54 83 16 12 28
20120607 66 53 82 19 12 28
20120608 68 54 77 20 12 25
20120609 72 55 77 22 13 25
20120610 72 60 82 22 16 28
20120611 69 57 86 21 14 30
20120612 66 55 85 19 13 29
20120613 66 53 76 19 12 24
20120614 67 53 84 19 12 29
20120615 68 54 84 20 12 29
20120616 67 57 83 19 14 28
20120617 64 55 82 18 13 28
20120618 61 52 82 16 11 28
20120619 66 53 82 19 12 28
20120620 77 55 81 25 13 27
20120621 88 53 80 31 12 27
20120622 82 54 81 28 12 27
20120623 77 55 83 25 13 28
20120624 75 55 85 24 13 29
20120625 70 56 87 21 13 31
20120626 65 57 88 18 14 31
20120627 73 57 89 23 14 32
20120628 77 56 86 25 13 30
20120629 79 56 85 26 13 29
20120630 84 58 81 29 14 27
20120701 81 58 78 27 14 26
20120702 82 56 83 28 13 28
20120703 80 56 83 27 13 28
20120704 77 55 84 25 13 29
20120705 86 54 84 30 12 29
20120706 79 54 84 26 12 29
20120707 83 54 86 28 12 30
20120708 81 52 84 27 11 29
20120709 77 53 83 25 12 28
20120710 76 53 77 24 12 25
20120711 76 52 77 24 11 25
20120712 75 52 80 24 11 27
20120713 77 53 81 25 12 27
20120714 79 54 80 26 12 27
20120715 78 54 81 26 12 27
20120716 79 54 77 26 12 25
20120717 83 56 80 28 13 27
20120718 84 57 81 29 14 27
20120719 75 57 80 24 14 27
20120720 68 58 83 20 14 28
20120721 68 57 85 20 14 29
20120722 72 56 83 22 13 28
20120723 75 56 84 24 13 29
20120724 82 57 83 28 14 28
20120725 78 57 84 26 14 29
20120726 77 56 84 25 13 29
20120727 79 55 84 26 13 29
20120728 77 55 83 25 13 28
20120729 72 55 85 22 13 29
20120730 72 55 84 22 13 29
20120731 73 55 86 23 13 30
20120801 75 55 86 24 13 30
20120802 77 54 85 25 12 29
20120803 79 53 85 26 12 29
20120804 79 54 86 26 12 30
20120805 81 57 84 27 14 29
20120806 80 58 81 27 14 27
20120807 75 58 86 24 14 30
20120808 77 57 86 25 14 30
20120809 78 55 86 26 13 30
20120810 77 54 88 25 12 31
20120811 78 53 85 26 12 29
20120812 78 52 87 26 11 31
20120813 78 53 88 26 12 31
20120814 76 53 88 24 12 31
20120815 76 56 87 24 13 31
20120816 75 57 86 24 14 30
20120817 77 55 86 25 13 30
20120818 72 56 84 22 13 29
20120819 70 54 76 21 12 24
20120820 71 53 80 22 12 27
20120821 73 53 80 23 12 27
20120822 74 54 78 23 12 26
20120823 74 55 79 23 13 26
20120824 76 54 81 24 12 27
20120825 76 53 84 24 12 29
20120826 73 56 83 23 13 28
20120827 74 58 82 23 14 28
20120828 79 58 84 26 14 29
20120829 74 57 85 23 14 29
20120830 73 55 87 23 13 31
20120831 77 55 82 25 13 28
20120901 80 55 84 27 13 29
20120902 75 53 83 24 12 28
20120903 73 53 85 23 12 29
20120904 73 52 86 23 11 30
20120905 77 54 85 25 12 29
20120906 74 56 85 23 13 29
20120907 76 56 85 24 13 29
20120908 77 56 81 25 13 27
20120909 69 56 74 21 13 23
20120910 67 55 71 19 13 22
20120911 64 56 75 18 13 24
20120912 68 55 82 20 13 28
20120913 69 54 80 21 12 27
20120914 70 55 70 21 13 21
20120915 69 54 71 21 12 22
20120916 66 52 70 19 11 21
20120917 67 54 72 19 12 22
20120918 72 54 73 22 12 23
20120919 67 56 72 19 13 22
20120920 62 55 71 17 13 22
20120921 64 55 72 18 13 22
20120922 65 55 73 18 13 23
20120923 65 52 75 18 11 24
20120924 60 54 78 16 12 26
20120925 63 53 78 17 12 26
20120926 68 53 79 20 12 26
20120927 69 52 76 21 11 24
20120928 68 52 77 20 11 25
20120929 62 53 75 17 12 24
20120930 62 55 71 17 13 22
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
body {
margin:auto;
width: 885px;
font: 10px arial;
padding: 25px;
}
.y-axis line {
opacity:.2;
}
.y-axis path {
display:none;
}
.line {
fill: none;
stroke-width: 1.5px;
opacity:.75;
}
.overlay {
fill: none;
pointer-events: all;
}
.lineHoverText {
text-shadow:
-2px -2px 0 #fff,
2px -2px 0 #fff,
-2px 2px 0 #fff,
2px 2px 0 #fff;
}
.hoverCircle {
opacity: .75;
}
</style>
</head>
<body>
<font style="font-size:11px;">Change metric:</font>
<select id="selectbox">
<option value="_1">Fahrenheit</option>
<option value="_2">Celsius</option>
</select>
<svg id="chart" width="850" height="410"></svg>
<script>
d3.csv("data.csv").then(d => chart(d))
function chart(data) {
var keys = data.columns.slice(1);
var parseTime = d3.timeParse("%Y%m%d"),
formatDate = d3.timeFormat("%Y-%m-%d"),
bisectDate = d3.bisector(d => d.date).left,
formatValue = d3.format(",.0f");
data.forEach(function(d) {
d.date = parseTime(d.date);
return d;
})
var svg = d3.select("#chart"),
margin = {top: 15, right: 35, bottom: 15, left: 35},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleTime()
.rangeRound([margin.left, width - margin.right])
.domain(d3.extent(data, d => d.date))
var y = d3.scaleLinear()
.rangeRound([height - margin.bottom, margin.top]);
var z = d3.scaleOrdinal(d3.schemeCategory10);
var line = d3.line()
.curve(d3.curveCardinal)
.x(d => x(d.date))
.y(d => y(d.degrees));
svg.append("g")
.attr("class","x-axis")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b")));
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + margin.left + ",0)");
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line").attr("class", "lineHover")
.style("stroke", "#999")
.attr("stroke-width", 1)
.style("shape-rendering", "crispEdges")
.style("opacity", 0.5)
.attr("y1", -height)
.attr("y2",0);
focus.append("text").attr("class", "lineHoverDate")
.attr("text-anchor", "middle")
.attr("font-size", 12);
var overlay = svg.append("rect")
.attr("class", "overlay")
.attr("x", margin.left)
.attr("width", width - margin.right - margin.left)
.attr("height", height)
update(d3.select('#selectbox').property('value'), 0);
function update(input, speed) {
var copy = keys.filter(f => f.includes(input))
var cities = copy.map(function(id) {
return {
id: id,
values: data.map(d => {return {date: d.date, degrees: +d[id]}})
};
});
y.domain([
d3.min(cities, d => d3.min(d.values, c => c.degrees)),
d3.max(cities, d => d3.max(d.values, c => c.degrees))
]).nice();
svg.selectAll(".y-axis").transition()
.duration(speed)
.call(d3.axisLeft(y).tickSize(-width + margin.right + margin.left))
var city = svg.selectAll(".cities")
.data(cities);
city.exit().remove();
city.enter().insert("g", ".focus").append("path")
.attr("class", "line cities")
.style("stroke", d => z(d.id))
.merge(city)
.transition().duration(speed)
.attr("d", d => line(d.values))
tooltip(copy);
}
function tooltip(copy) {
var labels = focus.selectAll(".lineHoverText")
.data(copy)
labels.enter().append("text")
.attr("class", "lineHoverText")
.style("fill", d => z(d))
.attr("text-anchor", "start")
.attr("font-size",12)
.attr("dy", (_, i) => 1 + i * 2 + "em")
.merge(labels);
var circles = focus.selectAll(".hoverCircle")
.data(copy)
circles.enter().append("circle")
.attr("class", "hoverCircle")
.style("fill", d => z(d))
.attr("r", 2.5)
.merge(circles);
svg.selectAll(".overlay")
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select(".lineHover")
.attr("transform", "translate(" + x(d.date) + "," + height + ")");
focus.select(".lineHoverDate")
.attr("transform",
"translate(" + x(d.date) + "," + (height + margin.bottom) + ")")
.text(formatDate(d.date));
focus.selectAll(".hoverCircle")
.attr("cy", e => y(d[e]))
.attr("cx", x(d.date));
focus.selectAll(".lineHoverText")
.attr("transform",
"translate(" + (x(d.date)) + "," + height / 2.5 + ")")
.text(e => e + " " + "º" + formatValue(d[e]));
x(d.date) > (width - width / 4)
? focus.selectAll("text.lineHoverText")
.attr("text-anchor", "end")
.attr("dx", -10)
: focus.selectAll("text.lineHoverText")
.attr("text-anchor", "start")
.attr("dx", 10)
}
}
var selectbox = d3.select("#selectbox")
.on("change", function() {
update(this.value, 750);
})
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment