Reputation: 39
I want to draw a multi-line chart using d3.js. I print my data structure in console and it look like this:
0:
key: student1
value: Array(50)
0: {date : 2017-09-11 11:51,score:50}
1: {date : 2017-09-11 12:53,score:90}
...
0:
key: student2
value: Array(50)
0: {date : 2017-09-11 11:51,score:20}
1: {date : 2017-09-11 12:53,score:30}
...
And put all student in same chart represented by different line. X axis is date, Y axis is student score.
But seems I have problem define my X and Y domain, I can't get the date and score value by d.value.date.
Upvotes: 1
Views: 864
Reputation: 667
You can't get date
and value
score by saying d.value.date
because those values are in nested in another object. You could flatten these object to try to get the domains. Going off of this example, if you represent you structure like this:
data = [
{student: 'student1', date : '2017-09-11 11:51', score: 50},
{student: 'student1', date : '2017-09-11 12:53', score: 90},
...
{student: 'student2', date : '2017-09-11 11:51', score: 20},
{student: 'student2', date : '2017-09-11 12:53', score: 30},
...
]
You could try define the axis like this:
var parseDate = d3.timeParse("%Y-%m-%d %H:%M");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
data.forEach(function(d) {
d.date = parseDate(d.date);
d.score = +d.score;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.score; })]);
I've modified d3noob's example a bit to go with this data (added a few more datapoints):
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 70,
left: 50
},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.timeParse("%Y-%m-%d %H:%M");
// Set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// Define the line
var priceline = d3.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.score);
});
// Adds the svg canvas
var svg = d3.select("body")
.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 + ")");
// Get the data
var data = [
{
student: 'student1',
date: '2017-09-11 11:45',
score: 60
},
{
student: 'student1',
date: '2017-09-11 11:51',
score: 50
},
{
student: 'student1',
date: '2017-09-11 12:53',
score: 90
},
{
student: 'student1',
date: '2017-09-11 12:57',
score: 97
},
{
student: 'student2',
date: '2017-09-11 11:22',
score: 10
},
{
student: 'student2',
date: '2017-09-11 11:31',
score: 15
},
{
student: 'student2',
date: '2017-09-11 11:33',
score: 20
},
{
student: 'student2',
date: '2017-09-11 11:38',
score: 30
},
{
student: 'student2',
date: '2017-09-11 12:51',
score: 45
},
{
student: 'student2',
date: '2017-09-11 12:59',
score: 40
}
]
data.forEach(function(d) {
d.date = parseDate(d.date);
d.price = +d.price;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.score;
})]);
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {
return d.student;
})
.entries(data);
// set the colour scale
var color = d3.scaleOrdinal(d3.schemeCategory10);
legendSpace = width / dataNest.length; // spacing for the legend
// Loop through each symbol / key
dataNest.forEach(function(d, i) {
svg.append("path")
.attr("class", "line")
.style("stroke", function() { // Add the colours dynamically
return d.color = color(d.key);
})
.attr("id", 'tag' + d.key.replace(/\s+/g, '')) // assign an ID
.attr("d", priceline(d.values));
// Add the Legend
svg.append("text")
.attr("x", (legendSpace / 2) + i * legendSpace) // space legend
.attr("y", height + (margin.bottom / 2) + 5)
.attr("class", "legend") // style the legend
.style("fill", function() { // Add the colours dynamically
return d.color = color(d.key);
})
.on("click", function() {
// Determine if current line is visible
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements based on the ID
d3.select("#tag" + d.key.replace(/\s+/g, ''))
.transition().duration(100)
.style("opacity", newOpacity);
// Update whether or not the elements are active
d.active = active;
})
.text(d.key);
});
// Add the X Axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y));
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.legend {
font-size: 16px;
font-weight: bold;
text-anchor: middle;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
Hope this helps
Upvotes: 2