This post describes how to build a very basic
circular packing with d3.js. In
this example, 8 nodes are represented by 8 circles of same size. You
can see many other examples in the
circular packing section of the
gallery. This example works with d3.js v4
and
v6
data
is pretty simple, each node
just have a name.
enter()
and append()
approach. All
circles are initialized with the same position: the center
of the svg
area.
d3.forceSimulation()
allows to
define the forces we want to apply to circles
forceCenter
), are slightly attracted one each
other (forceManyBody
), and overlapping is
avoided (forceCollide
).
tick
), node position is
updated
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v6.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var width = 450
var height = 450
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", 450)
.attr("height", 450)
// create dummy data -> just one element per circle
var data = [{ "name": "A" }, { "name": "B" }, { "name": "C" }, { "name": "D" }, { "name": "E" }, { "name": "F" }, { "name": "G" }, { "name": "H" }]
// Initialize the circle: all located at the center of the svg area
var node = svg.append("g")
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 25)
.attr("cx", width / 2)
.attr("cy", height / 2)
.style("fill", "#69b3a2")
.style("fill-opacity", 0.3)
.attr("stroke", "#69a2b2")
.style("stroke-width", 4)
// Features of the forces applied to the nodes:
var simulation = d3.forceSimulation()
.force("center", d3.forceCenter().x(width / 2).y(height / 2)) // Attraction to the center of the svg area
.force("charge", d3.forceManyBody().strength(0.5)) // Nodes are attracted one each other of value is > 0
.force("collide", d3.forceCollide().strength(.01).radius(30).iterations(1)) // Force that avoids circle overlapping
// Apply these forces to the nodes and update their positions.
// Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
simulation
.nodes(data)
.on("tick", function(d){
node
.attr("cx", function(d){ return d.x; })
.attr("cy", function(d){ return d.y; })
});
</script>
<script>
// set the dimensions and margins of the graph
const width = 450
const height = 450
// append the svg object to the body of the page
const svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", 450)
.attr("height", 450)
// create dummy data -> just one element per circle
const data = [{ "name": "A" }, { "name": "B" }, { "name": "C" }, { "name": "D" }, { "name": "E" }, { "name": "F" }, { "name": "G" }, { "name": "H" }]
// Initialize the circle: all located at the center of the svg area
const node = svg.append("g")
.selectAll("circle")
.data(data)
.join("circle")
.attr("r", 25)
.attr("cx", width / 2)
.attr("cy", height / 2)
.style("fill", "#69b3a2")
.style("fill-opacity", 0.3)
.attr("stroke", "#69a2b2")
.style("stroke-width", 4)
// Features of the forces applied to the nodes:
const simulation = d3.forceSimulation()
.force("center", d3.forceCenter().x(width / 2).y(height / 2)) // Attraction to the center of the svg area
.force("charge", d3.forceManyBody().strength(0.5)) // Nodes are attracted one each other of value is > 0
.force("collide", d3.forceCollide().strength(.01).radius(30).iterations(1)) // Force that avoids circle overlapping
// Apply these forces to the nodes and update their positions.
// Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
simulation
.nodes(data)
.on("tick", function(d){
node
.attr("cx", d => d.x)
.attr("cy", d => d.y)
});
</script>
Wondering what chart type you should use? Check my
Data To Viz project! It is a
comprehensive classification of chart types organized by data
input format. Get a high-resolution version of the decision tree in your
inbox now!