1. Web Design
  2. HTML/CSS
  3. HTML

Building a Multi-Line Chart Using D3.js: Part 2

Scroll to top
6 min read
This post is part of a series called Building a Multi-Line Chart Using D3.js.
Building a Multi-Line Chart Using D3.js

In the previous part of this series, we saw how to get started with creating a multi-line chart using the D3.js JavaScript library. In this tutorial, we'll take it to the next level by making the multi-line chart respond to data dynamically, and we'll add some more features as the tutorial progresses.

Getting Started

Let's get started by cloning the first part of the tutorial from GitHub.

1
git clone https://github.com/jay3dec/MultiLineChart_D3.git

Navigate to MultiLineChart_D3 and browse index.html, and you should have a multi-line graph based on the sample data.

Setting the Domain Dynamically

In the previous tutorial, when we created xScale and yScale using Range and Domain, we hard-coded the minimum and maximum for the domain. To make our graph more flexible, we need to read the minimum and maximum values for the domain dynamically from the data source.

D3.js provides the d3.min and d3.max methods to get the minimum and maximum values from an array respectively. We'll make use of these functions to get the minimum and maximum values for the domain.

We can get the minimum value from an array as shown:

1
d3.min(data, function(d) {
2
    return d.value;
3
})

Similarly, in order to get the maximum value:

1
d3.max(data, function(d) {
2
    return d.value;
3
})

Simply replace the minimum and maximum values in the xScale domain as shown: 

1
xScale = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(data, function(d) {
2
    return d.year;
3
}), d3.max(data, function(d) {
4
    return d.year;
5
})]),

Similarly, replace the yScale domain:

1
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(data, function(d) {
2
    return d.sale;
3
}), d3.max(data, function(d) {
4
    return d.sale;
5
})]),

Save all the changes and browse index.html. Now you should have the graph working well, as it was earlier. The only difference is that it's picking up the domain maximum and minimum values dynamically.

Creating the Line Chart Dynamically

Keeping a single JSON object for the sample would make it easier to parse the data and plot it on the chart. So combine the two pieces of sample data into a single JSON data string as shown below: 

1
var data = [{
2
    "Client": "ABC",
3
    "sale": "202",
4
    "year": "2000"
5
}, {
6
    "Client": "ABC",
7
    "sale": "215",
8
    "year": "2002"
9
}, {
10
    "Client": "ABC",
11
    "sale": "179",
12
    "year": "2004"
13
}, {
14
    "Client": "ABC",
15
    "sale": "199",
16
    "year": "2006"
17
}, {
18
    "Client": "ABC",
19
    "sale": "134",
20
    "year": "2008"
21
}, {
22
    "Client": "ABC",
23
    "sale": "176",
24
    "year": "2010"
25
}, {
26
    "Client": "XYZ",
27
    "sale": "100",
28
    "year": "2000"
29
}, {
30
    "Client": "XYZ",
31
    "sale": "215",
32
    "year": "2002"
33
}, {
34
    "Client": "XYZ",
35
    "sale": "179",
36
    "year": "2004"
37
}, {
38
    "Client": "XYZ",
39
    "sale": "199",
40
    "year": "2006"
41
}, {
42
    "Client": "XYZ",
43
    "sale": "134",
44
    "year": "2008"
45
}, {
46
    "Client": "XYZ",
47
    "sale": "176",
48
    "year": "2013"
49
}];

Now we'll modify our code to make our graph scale dynamically as per the sample data set and its values. 

Next we'll split and organize the data based on Client so that we can draw a line graph for each Client in the data. D3 provides a method called d3.nest which helps to arrange data based on a particular key field. We'll use d3.nest to sort out the data based on Client as shown:

1
var dataGroup = d3.nest()
2
    .key(function(d) {
3
        return d.Client;
4
    })
5
    .entries(data);

Here is how the dataGroup would look: 

1
[{
2
    "key": "ABC",
3
    "values": [{
4
        "Client": "ABC",
5
        "sale": "202",
6
        "year": "2000"
7
    }, {
8
        "Client": "ABC",
9
        "sale": "215",
10
        "year": "2002"
11
    }, {
12
        "Client": "ABC",
13
        "sale": "179",
14
        "year": "2004"
15
    }, {
16
        "Client": "ABC",
17
        "sale": "199",
18
        "year": "2006"
19
    }, {
20
        "Client": "ABC",
21
        "sale": "134",
22
        "year": "2008"
23
    }, {
24
        "Client": "ABC",
25
        "sale": "176",
26
        "year": "2010"
27
    }]
28
}, {
29
    "key": "XYZ",
30
    "values": [{
31
        "Client": "XYZ",
32
        "sale": "100",
33
        "year": "2000"
34
    }, {
35
        "Client": "XYZ",
36
        "sale": "215",
37
        "year": "2002"
38
    }, {
39
        "Client": "XYZ",
40
        "sale": "179",
41
        "year": "2004"
42
    }, {
43
        "Client": "XYZ",
44
        "sale": "199",
45
        "year": "2006"
46
    }, {
47
        "Client": "XYZ",
48
        "sale": "134",
49
        "year": "2008"
50
    }, {
51
        "Client": "XYZ",
52
        "sale": "176",
53
        "year": "2013"
54
    }]
55
}]

Next, remove the svg line path code for line creation that we hard-coded previously.

1
vis.append('svg:path')
2
    .attr('d', lineGen(data))
3
    .attr('stroke', 'green')
4
    .attr('stroke-width', 2)
5
    .attr('fill', 'none');
6
vis.append('svg:path')
7
    .attr('d', lineGen(data2))
8
    .attr('stroke', 'blue')
9
    .attr('stroke-width', 2)
10
    .attr('fill', 'none');

Instead we'll iterate over the dataGroup and create a line graph for each Client as shown:

1
dataGroup.forEach(function(d, i) {
2
    vis.append('svg:path')
3
        .attr('d', lineGen(d.values))
4
        .attr('stroke', 'blue')
5
        .attr('stroke-width', 2)
6
        .attr('fill', 'none');
7
});

Save the changes and try to browse index.html. You should be able to see the multi-line chart as shown: 

Multi Line ChartMulti Line ChartMulti Line Chart

Let's also add some random colors to the graph lines. In order to add random colors, we'll be using the d3.hsl method. Modify the stroke attribute of the line graph as shown below to get random colors for the lines.

1
dataGroup.forEach(function(d, i) {
2
    vis.append('svg:path')
3
        .attr('d', lineGen(d.values))
4
        .attr('stroke', function(d, j) {
5
            return "hsl(" + Math.random() * 360 + ",100%,50%)";
6
        })
7
        .attr('stroke-width', 2)
8
        .attr('fill', 'none');
9
});

Save the changes and browse index.html. You should be seeing random colors for the lines on the graph.

Multi line chart with colored linesMulti line chart with colored linesMulti line chart with colored lines

Adding Legends

Next, we'll be adding legends for the Clients in the sample data. Once legends have been added, we'll attach a click event on the legends which would toggle the display of the respective line graphs.

First, in order to add the legend, we need to modify the margin bottom and margin top to 50 to accommodate the legends.

1
var vis = d3.select("#visualisation"),
2
    WIDTH = 1000,
3
    HEIGHT = 500,
4
    MARGINS = {
5
        top: 50,
6
        right: 20,
7
        bottom: 50,
8
        left: 50
9
    },

While iterating the dataGroup, we'll add the legends for the corresponding line graphs. Adding legends is quite simple. First, define the legend space based on the number of Clients or line graphs we'll be drawing:

1
lSpace = WIDTH/dataGroup.length;

Add a text to svg element with x and y coordinates while iterating the dataGroup after the line creation as shown:

1
vis.append("text")
2
    .attr("x", (lSpace / 2) + i * lSpace)
3
    .attr("y", HEIGHT)
4
    .style("fill", "black")
5
    .text(d.key);

We have adjusted the legend spacing (lSpace) based on the number of legends we have to show, so that all the legends are equally spaced from each other. We have divided the legend by 2 so that it's center aligned in its space and will be so as it progresses forward, as we add (i * lSpace) to upcoming legends.

Save all the changes and try to browse index.html and you should see the legends below the X axis.

Multi line chart with legendMulti line chart with legendMulti line chart with legend

Let's add a bit of styling on the legends to make them look bold. Add the following CSS to index.html:

1
.legend {
2
    font-size: 14px;
3
    font-weight: bold;
4
}

Add the class legend to the legend created.

1
vis.append("text")
2
    .attr("x", (lSpace / 2) + i * lSpace)
3
    .attr("y", HEIGHT)
4
    .style("fill", "black")
5
    .attr("class", "legend")
6
    .text(d.key);
Line Chart with legendLine Chart with legendLine Chart with legend

D3.js Events

Now, let's add click events on each of the legends displayed to toggle the display of the corresponding line on the multi-line graph.

First, we'll need add an id for each line graph created in order to toggle its display.

1
.attr('id', 'line_'+d.key)

Here is how the line creation code looks:

1
vis.append('svg:path')
2
    .attr('d', lineGen(d.values, xScale, yScale))
3
    .attr('stroke', function(d, j) {
4
        return "hsl(" + Math.random() * 360 + ",100%,50%)";
5
    })
6
    .attr('stroke-width', 2)
7
    .attr('id', 'line_' + d.key)
8
    .attr('fill', 'none');

Next, in the legend creation portion, add the click attribute:

1
.on('click', function() {
2
    alert(d.key);
3
})

Save the change and browse index.html. Click on the legends and you should see the legends' names as alerts. 

Next, let's add the code to toggle the line display. We simply need to check the current display state of the line graph and toggle the opacity to show and hide the line accordingly.

1
.on('click', function() {
2
    var active = d.active ? false : true;
3
    var opacity = active ? 0 : 1;
4
5
    d3.select("#line_" + d.key).style("opacity", opacity);
6
7
    d.active = active;
8
})

Save the changes and try to browse index.html. Try clicking on the legends and the display of the corresponding line graph should toggle.

Conclusion

In this tutorial, we saw how to make our multi-line chart dynamic. We also saw how to create D3.js events. For detailed information on various other D3.js methods and APIs, have a look at the official documentation.

Source code from this tutorial is available on GitHub.

Do let us know your thoughts in the comments below!

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.