A bubble chart is a typical visualization capable of displaying three data dimensions. Every data entity with its three data points is visualized as a bubble (or disk) on Cartesian coordinates, with two different variables represented using x axis and y axis, similar to the scatter plot chart. While the third dimension is represented using the radius of the bubble (size of the disk). Bubble chart is particularly useful when used to facilitate understanding of relationships between data entities.
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter8/bubble-chart.html
In this recipe we will explore techniques and ways of implementing a typical bubble chart using D3. The following code example shows the important implementation aspects of a bubble chart with accessors and peripheral graphic implementation details omitted.
... var _width = 600, _height = 300, _margins = {top: 30, left: 30, right: 30, bottom: 30}, _x, _y, _r, // <-A _data = [], _colors = d3.scale.category10(), _svg, _bodyG; _chart.render = function () { if (!_svg) { _svg = d3.select("body").append("svg") .attr("height", _height) .attr("width", _width); renderAxes(_svg); defineBodyClip(_svg); } renderBody(_svg); }; ... function renderBody(svg) { if (!_bodyG) _bodyG = svg.append("g") .attr("class", "body") .attr("transform", "translate(" + xStart() + "," + yEnd() + ")") .attr("clip-path", "url(#body-clip)"); renderBubbles(); } function renderBubbles() { _r.range([0, 50]); // <-B _data.forEach(function (list, i) { _bodyG.selectAll("circle._" + i) .data(list) .enter() .append("circle") // <-C .attr("class", "bubble _" + i); _bodyG.selectAll("circle._" + i) .data(list) .style("stroke", function (d, j) { return _colors(j); }) .style("fill", function (d, j) { return _colors(j); }) .transition() .attr("cx", function (d) { return _x(d.x); // <-D }) .attr("cy", function (d) { return _y(d.y); // <-E }) .attr("r", function (d) { return _r(d.r); // <-F }); }); } ...
This recipe generates the following visualization:
Overall, bubble chart implementation follows the same pattern as other chart implementations introduced in this chapter so far. However, since in bubble chart we want to visualize three different dimensions (x, y, and radius) instead of two, therefore a new scale _r
was added in this implementation (line A).
var _width = 600, _height = 300, _margins = {top: 30, left: 30, right: 30, bottom: 30}, _x, _y, _r, // <-A _data = [], _colors = d3.scale.category10(), _svg, _bodyG;
Most of the bubble chart related implementation details are handled by the renderBubbles
function. It starts with setting the range on the radius scale (line B). Of course we can also make the radius range configurable in our chart implementation; however, for simplicity we chose to set it explicitly here:
function renderBubbles() { _r.range([0, 50]); // <-B _data.forEach(function (list, i) { _bodyG.selectAll("circle._" + i) .data(list) .enter() .append("circle") // <-C .attr("class", "bubble _" + i); _bodyG.selectAll("circle._" + i) .data(list) .style("stroke", function (d, j) { return _colors(j); }) .style("fill", function (d, j) { return _colors(j); }) .transition() .attr("cx", function (d) { return _x(d.x); // <-D }) .attr("cy", function (d) { return _y(d.y); // <-E }) .attr("r", function (d) { return _r(d.r); // <-F }); }); }
Once the range is set, then we iterated through our data series and for each series we created a set of svg:circle
elements (line C). Finally we handled the newly created bubble as well as its update in the last section, where svg:circle
elements are colored and placed to the correct coordinates using its cx
and cy
attributes (line D and E). In the end, the bubble size is controlled using its radius attribute r
mapped using the _r
scale we defined earlier (line F).