Let’s use D3 to create a very simple data-driven visualization to test your installation. This is a hands-on section, so you can code and view the results in real time as you read.
Although these steps assume you are using a local environment, you can also follow these examples in CodePen, JSFiddle, or by editing cells in an Observable notebook. All files created in this section are available from the book’s GitHub repository in the Chapter01/HelloWorld/ folder. There are also links in the HelloWorld/README.md file for the code on online platforms.
Adding the SVG container
The SVG container is created in an HTML page. Create a simple HTML file, as described in the previous section, and place an <svg> tag inside <body>, as shown here:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World D3</title>
</head>
<body>
<svg id="chart" width="600" height="200"></svg>
</body>
</html>
Quick tip: Enhance your coding experience with the AI Code Explainer and Quick Copy features. Open this book in the next-gen Packt Reader. Click the Copy button
(1) to quickly copy code into your coding environment, or click the Explain button
(2) to get the AI assistant to explain a block of code to you.
.png)
The next-gen Packt Reader is included for free with the purchase of this book. Scan the QR code OR go to packtpub.com/unlock, then use the search bar to find this book by name. Double-check the edition shown to make sure you get the right one.

If you are using an online editor, you don’t need to write the HTML code. Just include the following SVG tag in the HTML tab:
<svg id="chart" width="600" height="200"></svg>
In an Observable notebook, add the preceding line to a new HTML cell (see Figure 1.6).
This step produces a blank page. In the next step, we will start drawing something in it.
Drawing a dot with SVG
SVG is a web standard for creating line art with XML tags. D3 visualizations often use SVG extensively. The preceding code creates a 600x200 pixel SVG viewport where you can draw graphics. Let’s draw a circle in it by declaring a <circle> element inside the <svg> element like this:
<svg id="chart" width="600" height="200">
<circle r="10" cy="100" cx="100" />
</svg>
The <circle> element requires three attributes: cx and cy for the x,y position of its center (100,100), in pixels, starting at the top left, and r for the circle’s radius (10 pixels). Load the file in your browser, and you should see the black circle shown in Figure 1.7:
Figure 1.7 – A dot on a screen created with SVG. Code: HelloWorld/1-svg-circle.html
In an online editor or in an Observable notebook, you will see the result as soon as you finish typing or click a button to run your code.
If you want to draw many circles in different positions and diameters, all you need to do is repeat the <circle> tag with different attributes for r, cx, and cy. But this is much easier with programming. We will do this with D3, so let’s now load the D3 library.
Setting up an HTML page to use D3
In this step, we will draw that same circle using JavaScript and the D3 library.
First, remove the <circle> element from your <svg> block. It should now be empty. Then, add the following highlighted code to your HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World D3 </title>
</head>
<body>
<svg id="chart" width="600" height="200"></svg>
<script type="module">
import * as d3 from "https://cdn.skypack.dev/d3@7";
// type your code here
</script>
</body>
</html>
This will download the library from a public CDN URL, making it available in the script.
If you are using an online editor, add the import line to your JavaScript tab. In an Observable notebook, you don’t have to set up anything, since D3 is natively installed.
All the rest of the code in this section should be typed in the <script type="module"> block after the import line.
Now, let’s proceed and draw something using D3.
Drawing a dot with D3
To begin the process of drawing a dot with D3, add the following code in your <script>:
d3.select("#chart")
.append("circle")
.attr("r", 10)
.attr("cy", 100)
.attr("cx", 100); This is a single command that runs a sequence of operations (methods). The line d3.select("#chart") will select the <svg> identified by the ID #chart. The append() method attaches a child <circle> element to it, and the remaining lines set attributes for the circle’s radius ("r") and coordinates of its origin ("cx" and "cy").
If you are using an Observable notebook, create a new JavaScript cell for this code.
Important note
This is a single line of code. It’s broken into separate, indented lines to make it easier to read. Each indent represents a different context.
If your configuration is working correctly, when you preview the page containing this code in a browser (or in the preview tab, if you are using an online IDE), you should see the same circle that was previously created with SVG.
That’s it. Your D3 installation is working! The following sections will add a few more D3 features to this example. Don’t worry if you don’t understand all the details.
You will find this code in HelloWorld/2-d3-append.html with additional comments.
Now, let’s add more data and display a series of dots based on it.
Adding more data
Of course, you don’t need D3 to draw a single black dot on the screen, so let’s do something a bit more complex. Add the following line inside your <script> block, right after the import (before your code):
const values = [100, 200, 300, 350, 375, 400, 500];
If you are using an Observable notebook, create a JavaScript cell to add the preceding code without the const keyword.
This line declares a 7-element integer array. It will be used as data to generate a series of circles. Now, make the following highlighted changes in your previous code:
d3.select("#chart")
.selectAll("circle")
.data( values )
.join("circle")
.attr("r", 10)
.attr("cy", 100)
.attr("cx", d => d) Compare this to the code from the previous section: append() was replaced with three new methods, and the second parameter of the third attr() now contains an arrow function returning the received data. Here’s a quick description of what this code does:
- The first method,
selectAll(), creates an empty selection of <circle> objects.
- The
data() method receives the array created previously (values).
- The
join() method binds the data to the selection and creates an array of seven <circle> elements to be appended to the <svg> viewport (#chart).
- The
attr() methods set the circle’s attributes as before, but this time, it is applied to seven circles. Each circle will have a different cx attribute because of the d => d parameter (in case you are not familiar with arrow functions, this is the same as function(d) { return d; }).
When you run the code, you should now see seven dots on the screen (Figure 1.8): the same number of elements in the array.
Figure 1.8 – Dots with positions driven by the data. Code: HelloWorld/4-binding-data.html
Each dot is placed at a different horizontal position, defined by the cx property of the <circle>. Positions are data values from the array. We used the data array to drive the position of each circle. Try changing the values in the array (any values between 0 and 600) or add/remove values to see how this affects the displayed circles.
Our next step is to deal with data changes.
Updating data
Let’s see an example of how D3 updates the data bound to graphical elements. Still inside the <script> block (or tab, if you are using an online editor), skip a line and add the following code after the code you typed in the previous section:
function update(dataset) {
d3.select("#chart").selectAll("circle")
.data(dataset)
.attr("r", 5)
.attr("cx", d => d)
.style("fill", "red")
} In an Observable notebook, create a new JavaScript cell to add the preceding code.
This code declares a function that receives a dataset and passes it to the selection of all circles in the SVG. The data() method is now used to rebind the selection with this dataset. The two attr() methods that follow are applied to each circle, changing its attributes. The first reduces the r attribute to 5 pixels, and the second replaces the cx attribute of each circle with values from the dataset. There is one more method: style(), which changes the fill color using CSS.
Now, add this array declaration anywhere in your code (outside the update() function). A good place is in a line after the values array:
const newArray = [225, 425, 125, 50, 450, 75, 325]; // new data
In an Observable notebook, place it in a new JavaScript cell (and don’t use const).
Finally, include the following timeout at the end of your script. It calls update() after 2 seconds (2,000 milliseconds), passing the newArray dataset as the argument:
setTimeout(update, 2000, newArray);
When this code runs, the dots will be displayed as before, but two seconds later, the circles will shrink, become red, and move to different positions, as shown in Figure 1.9.
Figure 1.9 – Dots change color, size, and position. Code: HelloWorld/5-updating.html
When the function is called, the data() method in update() will bind the new array to the selection, updating the circles attributes. A join() command is not necessary here because there aren’t elements to be added or removed: all existing circles are reused.
See HelloWorld/5-updating.html for all the code we wrote so far.
Now, let’s make the transition to the new data smoother using an animation.
Animated transitions
A cool feature of D3 is how simple it is to animate transitions. You just need to chain a transition() command before changing attributes and styles. A default transition takes ¼ of a second, but you can make it a little longer by setting its duration.
Include the following line between the data() method and the first attr() of your update() function to add a 1-second transition (1,000 milliseconds):
.transition().duration(1000)
Your update() function should now look like this (see HelloWorld/6-transition.html). The code that was added is highlighted:
function update(dataset) {
d3.select("#chart")
.selectAll("circle")
.data(dataset)
.transition().duration(1000)
.attr("r", 5).attr("cx", d => d).style("fill", "red")
} Now, after two seconds, the dots will spend one more second changing color, shrinking, and moving to their new positions. Congratulations. You created a full D3 application, complete with data updates and animated transitions.
Before concluding this chapter, let’s briefly review the modules in the D3 library.