Simple Bubble Charts Using D3.js

Jay Raj
Jay Raj
Share

At my workplace, I was assigned the task to visualize some data. That was when I bumped into D3.js, a JavaScript library for manipulating documents based on data in an interactive way. It makes use of HTML5, JavaScript, SVG and CSS3. In this tutorial, we’ll use D3 to visualize our data in the form of abubble chart. Before getting started, download the D3 source.

Creating the X and Y Axes

Let’s begin by drawing some axes using D3. To get started, we’ll need SVG in our HTML page. SVG is a XML based vector image format that offers support for interaction and animation. The following code sample shows what our HTML page should look like. Notice the reference to D3 and the svg tag in the body.
<html>
  <head>
    <script src="jquery.js"></script>
    <script src="d3.v3.js"></script>
    <script>
      $(function() {
        InitChart();
      });

      function InitChart() {
        // Chart creation code goes here
      }
    </script>
  </head>
  <body>
    <svg id="svgVisualize" width="500" height="500"></svg>
  </body>
</html>
D3.js has a set of APIs which we’ll be using to draw our axes. One of the APIs that we’ll be using is d3.scale.linear()
, which is used to create a quantitative scale. Using this API, we can define the range and domain of each axis. The domain defines the minimum and maximum values displayed on the graph, while the range is the amount of the SVG we’ll be covering. Our svg is 500×500 so, let’s define our range as 40×400.
var xRange = d3.scale.linear().range([40, 400]).domain([0,100]);
var yRange = d3.scale.linear().range([40, 400]).domain([0,100]);
Next, we need to scale to two axes. For this we’ll be using axis.scale():
var xAxis = d3.svg.axis().scale(xRange);
var yAxis = d3.svg.axis().scale(yRange);
Next, append the x and y axes to the SVG element via JavaScript:
vis.append("svg:g").call(xAxis);
vis.append("svg:g").call(yAxis);
At this point, our InitChart()
function looks like this:
function InitChart() {
  var vis = d3.select("#svgVisualize");
  var xRange = d3.scale.linear().range([40, 400]).domain([0,100]);
  var yRange = d3.scale.linear().range([40, 400]).domain([0,100]);
  var xAxis = d3.svg.axis().scale(xRange);
  var yAxis = d3.svg.axis().scale(yRange);
  vis.append("svg:g").call(xAxis);
  vis.append("svg:g").call(yAxis);
}
You can view a demo of the code up to this point. You should see a bold black line. Actually, there are two lines overlapping each other. To separate the axes, modify the code where we appended the y-axis as shown below:
vis.append("svg:g").call(yAxis).attr("transform", "translate(0,40)");
The updated code is available here. Now, you can see both axes because we have moved our y-axis by 40 units. Next, we need to do two things: 1.) move the y-axis 40 units from the x-axis and 0 units from the y-axis and 2.) change its orientation to left. The updated InitChart()
is shown below, with the updated demo available here.
function InitChart() {
  var vis = d3.select("#svgVisualize");
  var xRange = d3.scale.linear().range([40, 400]).domain([0,100]);
  var yRange = d3.scale.linear().range([40, 400]).domain([0,100]);
  var xAxis = d3.svg.axis().scale(xRange);
  var yAxis = d3.svg.axis().scale(yRange).orient("left");
  vis.append("svg:g").call(xAxis);
  vis.append("svg:g").call(yAxis).attr("transform", "translate(40,0)");
}
Now, our y-axis looks good, but the x-axis needs to be moved down. Let’s use transform to bring it down:
vis.append("svg:g").call(xAxis).attr("transform", "translate(0,400)");
Now, if we have a look at the chart, we see that the y-axis scale goes from 100 to 0. We need to invert it like so:
var yRange = d3.scale.linear().range([400, 40]).domain([0,100]);
The modified InitChart() function looks like this:
function InitChart() {
  var vis = d3.select("#svgVisualize");
  var xRange = d3.scale.linear().range([40, 400]).domain([0,100]);
  var yRange = d3.scale.linear().range([400, 40]).domain([0,100]);
  var xAxis = d3.svg.axis().scale(xRange);
  var yAxis = d3.svg.axis().scale(yRange).orient("left");
  vis.append("svg:g").call(xAxis).attr("transform", "translate(0,400)");
  vis.append("svg:g").call(yAxis).attr("transform", "translate(40,0)");
}
And here is the updated demo.

Bubble Chart

Now that the axes are setup, it’s time to create the bubble chart. The first thing we’re going to need is some data:
var sampleData = [{
  "x": 1,
  "y": 5
}, {
  "x": 20,
  "y": 20
}, {
  "x": 40,
  "y": 10
}, {
  "x": 60,
  "y": 40
}, {
  "x": 80,
  "y": 5
}, {
  "x": 100,
  "y": 60
}];
Earlier, we hard coded our domain for each axis from 0 to 100. Now that we have data, we can set the domain dynamically. D3 has min() and max() functions to make our lives easier. Simply modify the xRange and yRange variable as shown below.
var xRange = d3.scale.linear()
                .range([40, 400])
                .domain([d3.min(sampleData, function(d) {
                  return (d.x);
                }), d3.max(sampleData, function(d) {
                  return d.x;
                })]);
var yRange = d3.scale.linear()
                .range([400, 40])
                .domain([d3.min(sampleData, function(d) {
                  return d.y;
                }), d3.max(sampleData, function(d) {
                  return d.y;
                })]);

Creating Circles

Now, we need to plot circles based on the x and y values from sampleData. First, we need to bind the sampleData to circles:
var circles = vis.selectAll("circle").data(sampleData);

circles.enter();
The above code selects circle
from the document and returns a placeholder. Now, we need to apply xRange and yRange to the coordinates to tranform them into the plotting space:
var circles = vis.selectAll("circle").data(sampleData);

circles
    .enter()
    .insert("circle")
    .attr("cx", function(d) { return xRange (d.x); })
    .attr("cy", function(d) { return yRange (d.y); })
    .attr("r", 10)
    .style("fill", "red");

Conclusion

D3.js is an awesome library for data visualization. In this tutorial, we focused on creating a bubble chart. Our chart is fairly simple, but the visualization can be made more interactive with the use of transitions, which we’ll discuss and implement in a future tutorial. A demo of this article’s finished product is available here
.

Frequently Asked Questions (FAQs) about Creating Simple Bubble Charts Using D3.js

How can I customize the color of the bubbles in my D3.js bubble chart?

Customizing the color of the bubbles in your D3.js bubble chart can be achieved by using the .style() method. This method allows you to set CSS properties for the bubbles. For instance, you can set the “fill” property to change the color of the bubbles. Here’s an example:

var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.style("fill", "blue");
In this example, all the bubbles in the chart will be blue. If you want to use different colors for each bubble, you can use a color scale. D3.js provides several color scales, such as d3.scaleOrdinal(d3.schemeCategory10), which can be used to assign a different color to each bubble based on its data.

How can I add labels to the bubbles in my D3.js bubble chart?

Adding labels to the bubbles in your D3.js bubble chart can be done by appending text elements to the SVG container. You can use the .text() method to set the text content of the labels. Here’s an example:

var labels = svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) { return d.name; })
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
In this example, each bubble will have a label displaying its name, positioned at its center. You can customize the appearance of the labels by using the .style() method to set CSS properties, such as “font-size” and “text-anchor”.

How can I make the size of the bubbles in my D3.js bubble chart proportional to my data?

Making the size of the bubbles in your D3.js bubble chart proportional to your data can be achieved by using a scale for the radius of the bubbles. D3.js provides several types of scales, such as d3.scaleLinear(), which can be used to map your data values to a range of radii. Here’s an example:

var radiusScale = d3.scaleLinear()
.domain([d3.min(data), d3.max(data)])
.range([minRadius, maxRadius]);

var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", function(d) { return radiusScale(d.value); });
In this example, the radius of each bubble is determined by its value, scaled between minRadius and maxRadius. You can adjust these values to control the size of the bubbles.

How can I animate the bubbles in my D3.js bubble chart?

Animating the bubbles in your D3.js bubble chart can be done by using the .transition() method. This method allows you to smoothly change the attributes of the bubbles over a specified duration. Here’s an example:

var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 0)
.transition()
.duration(2000)
.attr("r", function(d) { return radiusScale(d.value); });
In this example, each bubble starts with a radius of 0 and grows to its final size over 2 seconds. You can animate other attributes, such as the position and color of the bubbles, in a similar way.

How can I add interactivity to the bubbles in my D3.js bubble chart?

Adding interactivity to the bubbles in your D3.js bubble chart can be achieved by using event listeners. D3.js provides several methods for handling events, such as .on(), which can be used to specify a function to be executed when a certain event occurs. Here’s an example:

var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.on("mouseover", function(d) {
d3.select(this)
.style("fill", "red");
})
.on("mouseout", function(d) {
d3.select(this)
.style("fill", "blue");
});
In this example, when the mouse pointer is over a bubble, the color of the bubble changes to red. When the mouse pointer is moved away from the bubble, the color of the bubble changes back to blue. You can add other types of interactivity, such as click and drag events, in a similar way.