Skip to content

Instantly share code, notes, and snippets.

@jqadrad
Last active May 17, 2017 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jqadrad/a58719d82741b1642a2061c071ae2375 to your computer and use it in GitHub Desktop.
Save jqadrad/a58719d82741b1642a2061c071ae2375 to your computer and use it in GitHub Desktop.
Multi-line chart
[
{
"Time": "2017-05-03 23:17",
"BTC": 19.7,
"DOGE": 0,
"ETH": 78.88,
"LTC": 20.81,
"REP": 0
},
{
"Time": "2017-05-04 20:18",
"BTC": 21.21,
"DOGE": 0,
"ETH": 90.45,
"LTC": 24.91,
"REP": 0
},
{
"Time": "2017-05-05 19:11",
"BTC": 20.1,
"DOGE": 11.58,
"ETH": 91.73,
"LTC": 24.06,
"REP": 0
},
{
"Time": "2017-05-06 18:56",
"BTC": 20.28,
"DOGE": 12.37,
"ETH": 92.78,
"LTC": 25.91,
"REP": 0
},
{
"Time": "2017-05-09 0:50",
"BTC": 21.77,
"DOGE": 20.34,
"ETH": 89.27,
"LTC": 28.45,
"REP": 0
},
{
"Time": "2017-05-09 2:15",
"BTC": 21.99,
"DOGE": 20.58,
"ETH": 88.62,
"LTC": 28.49,
"REP": 34.7
},
{
"Time": "2017-05-09 23:59",
"BTC": 22.46,
"DOGE": 17.51,
"ETH": 87.45,
"LTC": 30.14,
"REP": 32.45
},
{
"Time": "2017-05-11 0:57",
"BTC": 23.15,
"DOGE": 18.83,
"ETH": 86.94,
"LTC": 32.18,
"REP": 34.36
},
{
"Time": "2017-05-11 22:17",
"BTC": 24.17,
"DOGE": 17.48,
"ETH": 87.87,
"LTC": 29.62,
"REP": 34.36
},
{
"Time": "2017-05-12 1:55",
"BTC": 24.13,
"DOGE": 17.99,
"ETH": 88.05,
"LTC": 30.02,
"REP": 36.08
},
{
"Time": "2017-05-13 1:57",
"BTC": 22.41,
"DOGE": 17.48,
"ETH": 85.25,
"LTC": 27,
"REP": 33.72
},
{
"Time": "2017-05-14 15:32",
"BTC": 23.67,
"DOGE": 17.04,
"ETH": 89.19,
"LTC": 28.9,
"REP": 34.24
},
{
"Time": "2017-05-14 23:34",
"BTC": 23.47,
"DOGE": 17.51,
"ETH": 88.6,
"LTC": 28.01,
"REP": 33.72
}
]
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke-width: 1;
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
}
circle {
stroke-width: 1;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.legend, .label, .hover-text{
font-size: x-small;
background-color: white;
}
</style>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
// Draw a line chart
var svg = d3.select('svg'),
margin = { top: 20, right: 50, bottom: 30, left: 50 },
width = +svg.attr('width') - margin.left - margin.right,
height = +svg.attr('height') - margin.top - margin.bottom,
g = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Graph title
g.append('text')
.attr('x', (width / 2))
.attr('y', 0 - (margin.top / 3))
.attr('text-anchor', 'middle')
.style('font-size', '16px')
.text('Wallet chart');
// Function to convert a string into a time
var parseTime = d3.time.format('%Y-%m-%d %H:%M').parse;
// Function to show specific time format
var formatTime = d3.time.format('%e %B');
// Set the X scale
var x = d3.time.scale().range([0, width], 0.5);
// Set the Y scale
var y = d3.scale.linear().range([height, 0]);
// Set the color scale
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
// .interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.worth);
});
// load the data
d3.json("data.json", function(error, data) {
// Select the important columns
color.domain(d3.keys(data[0]).filter(function(key) {
return key !== "Time" && key !== "_id";
}));
// Correct the types
data.forEach(function(d) {
d.date = parseTime(d.Time);
});
console.log(data);
var currencies = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.date,
worth: +d[name]
};
})
};
});
console.log(currencies)
// Set the X domain
x.domain(d3.extent(data, function(d) {
return d.date;
}));
// Set the Y domain
y.domain([
d3.min(currencies, function(c) {
return d3.min(c.values, function(v) {
return v.worth;
});
}),
d3.max(currencies, function(c) {
return d3.max(c.values, function(v) {
return v.worth;
});
})
]);
// Set the X axis
g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Set the Y axis
g.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Value (USD)");
// Draw the lines
var currency = g.selectAll(".currency")
.data(currencies)
.enter().append("g")
.attr("class", "currency");
currency.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return color(d.name);
});
// Add the circles
currency.append("g").selectAll("circle")
.data(function(d){return d.values})
.enter()
.append("circle")
.attr("r", 2)
.attr("cx", function(dd){return x(dd.date)})
.attr("cy", function(dd){return y(dd.worth)})
.attr("fill", "none")
.attr("stroke", function(d){return color(this.parentNode.__data__.name)});
// Add label to the end of the line
currency.append("text")
.attr("class", "label")
.datum(function (d) {
return {
name: d.name,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function (d) {
return "translate(" + x(d.value.date) + "," + y(d.value.worth) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});
// Add the mouse line
var mouseG = g.append("g")
.attr("class", "mouse-over-effects");
mouseG.append("path")
.attr("class", "mouse-line")
.style("stroke", "black")
.style("stroke-width", "1px")
.style("opacity", "0");
var lines = document.getElementsByClassName('line');
var mousePerLine = mouseG.selectAll('.mouse-per-line')
.data(currencies)
.enter()
.append("g")
.attr("class", "mouse-per-line");
mousePerLine.append("circle")
.attr("r", 7)
.style("stroke", function (d) {
return color(d.name);
})
.style("fill", "none")
.style("stroke-width", "2px")
.style("opacity", "0");
mousePerLine.append("text")
.attr("class", "hover-text")
.attr("dy", "-1em")
.attr("transform", "translate(10,3)");
// Append a rect to catch mouse movements on canvas
mouseG.append('svg:rect')
.attr('width', width)
.attr('height', height)
.attr('fill', 'none')
.attr('pointer-events', 'all')
.on('mouseout', function () { // on mouse out hide line, circles and text
d3.select(".mouse-line")
.style("opacity", "0");
d3.selectAll(".mouse-per-line circle")
.style("opacity", "0");
d3.selectAll(".mouse-per-line text")
.style("opacity", "0");
})
.on('mouseover', function () { // on mouse in show line, circles and text
d3.select(".mouse-line")
.style("opacity", "1");
d3.selectAll(".mouse-per-line circle")
.style("opacity", "1");
d3.selectAll(".mouse-per-line text")
.style("opacity", "1");
})
.on('mousemove', function () { // mouse moving over canvas
var mouse = d3.mouse(this);
d3.selectAll(".mouse-per-line")
.attr("transform", function (d, i) {
var xDate = x.invert(mouse[0]),
bisect = d3.bisector(function (d) { return d.date; }).left;
idx = bisect(d.values, xDate);
d3.select(this).select('text')
.text(y.invert(y(d.values[idx].worth)).toFixed(2));
d3.select(".mouse-line")
.attr("d", function () {
var data = "M" + x(d.values[idx].date) + "," + height;
data += " " + x(d.values[idx].date) + "," + 0;
return data;
});
return "translate(" + x(d.values[idx].date) + "," + y(d.values[idx].worth) + ")";
});
});
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment