DEV Community

Cover image for Creating visualizations with D3 and TypeScript
Matt Angelosanto for LogRocket

Posted on • Edited on • Originally published at blog.logrocket.com

Creating visualizations with D3 and TypeScript

Written by Rosario De Chiara✏️

This article will chronicle my experiences studying D3.js, a JavaScript framework that produces high-quality diagrams and graphics fueled by data.

Although D3 is a JavaScript library, we will use TypeScript because it handles data and data types more efficiently than plain old JavaScript.

This tutorial will show you how to create visualizations using D3 and TypeScript. First, we’ll create a simple boilerplate project, add data, and then build a fully interactive example. We will host the code on CodePen for maximum interactivity as a stylistic decision.

Each example will run in the browser, saving you the fuss of installing anything onto your computer. Of course, you’ll be able to fork a Pen and work on your code version.

Jump ahead:

Creating and exporting the boilerplate project in D3

We will mainly focus on adding dependencies and getting acquainted with the environment with the boilerplate Pen. There will be HTML on the left, CSS in the middle, and TypeScript on the right. This is where most of the action will take place. Example of the boilerplate project visualization

Next, ensure that the JavaScript pane is set to TypeScript and add D3 as a dependency. You can do this by selecting the gear icon on the top right.

Here’s an interactive example of the code:

See the Pen Typescript + D3 Boilerplate by rosdec (@rosdec) on CodePen.

The code is straightforward, so we will only focus on TypeScript because the HTML and CSS are irrelevant.

import * as d3 from "https://cdn.skypack.dev/d3@7.6.1";

const svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 500);

svg
  .append("text")
  .attr("x", 100)
  .attr("y", 100)
  .text("Hello d3js");

svg
  .append("circle")
  .attr("r", 30)
  .attr("cx", 60)
  .attr("cy", 50);
Enter fullscreen mode Exit fullscreen mode

The import addresses the D3 library dependency. In the following block of code, we added the svg component to the body tag to accommodate our graphics in each code example.

The last two lines of code add the text and circle to produce the results seen in the Pen. That is everything we need to set up the environment to play with D3.

Adding data to D3

To stay true to the D3 philosophy, we have to add data to our graphics. To do this, we’ll use the code below. This downloads a CSV file and manipulates it to visualize it as a scatter plot.

See the Pen Typescript + D3 Interactive by rosdec (@rosdec) on CodePen.

import * as d3 from "https://cdn.skypack.dev/d3@7.6.1";

// set the dimensions and margins of the graph
const margin = { top: 10, right: 30, bottom: 30, left: 60 },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
const svg = d3
  .select("body")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`);

// Read the data
d3.csv(
"https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/iris.csv"
).then(function (csvdata) {
  // Add X axis
  const x = d3.scaleLinear().domain([3, 9]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));

  // Add Y axis
  const y = d3.scaleLinear().domain([0, 9]).range([height, 0]);
  svg.append("g").call(d3.axisLeft(y));

  // Add dots
  svg.append("g")
     .selectAll("circle")
     .data(csvdata)
     .join("circle")
     .attr("cx", function (d) {
       return x(d.Sepal_Length);
    })
    .attr("cy", function (d) {
       return y(d.Petal_Length);
    })
    .attr("r", 5);
});
Enter fullscreen mode Exit fullscreen mode

After we’ve done the import, we will define the surface to draw our graphics on. We can do this by calculating the area's width and height along with the margins. These values add svg to the HTML body and specify a transformation. In this case, it’s a translate operation to place g under svg.

Our last operation is to map the points in the scatterplot. The data is directly downloaded from a URL as a CSV file. D3 can manipulate CSV data, which comes in handy most of the time. Once the data is available, three operations are performed: adding the x-axis, adding the y-axis, and plotting the data.

The first two operations are performed consecutively to define the x and y-axes as scaleLinear. Then, for each axis, the range is specified by the number of pixels that such axes will occupy. The x-axis will have a domain of 3 to 9, and the y-axis will be 0 to 9.

Binding data to graphics using D3

Adding the dots to the scatter plot may appear a little convoluted, but we can do it with a specific sequence of operations. The idea is to bind a graphic component — a circle, a point, and a line — to data. Then, the data will modify some aspects of the graphic component, such as color, thickness, pattern, and position. In the source code above, we:

  • Use .selectAll to define the type of element that will join each element of the data
  • Use .data to define the array
  • Use .join to join the data and the graphics elements. This is where HTML or SVG are dynamically added and removed

Now, we define how the value of the data influences the graphics element. In the example above, you can see that we .selectAll circle elements, we call .data to assign the csvdata as the data source of the join, and then we .join the data to the graphics element.

Our final and most creative step is defining how the data influence graphics. At this point, we only have a circle for each entry in the csvdata. To modify the circles, we use .attr. The first two will modify the attributes cx and cy at the center of the circle coordinates, then modify the radius by setting it to 5.

Interacting with the visualizations with D3

Next, let's add an interaction to explore the real possibilities of D3. First, let’s look at the final result:

See the Pen Typescript + D3 Interactive by rosdec (@rosdec) on CodePen.

Together with the scatterplot, we have a button to remove one circle from the data. This is done in D3 without access to external sources. The button is added in HTML but is bound to the code it will execute in the TypeScript source.

The interaction occurs in popCircle() and will remove the last element from the csvdata array. This will then join the circles in the scatterplot to data, but with a little addition — the .exit operation. This defines what happens when a datum exits the graphics array.

The semantics of the code is simple: everything after .exit() will apply to the graphics elements exiting from the array. Here, we ask D3 to apply a transition on the circle radius specified by .attr that will become 0 before removing graphics from the representation.

The final effect is visually satisfying. Once you click the button, the scatterplot circles disappear, and the transition alerts the user to where modifications are happening. GIF of the final effect of creating visualizations with D3 and TypeScript

Conclusion

In this tutorial, we learned how to set up a stripped-down project based on TypeScript and D3. We also saw how to go from a basic representation to an advanced and interactive data-driven one. Although the example is simple, I hope it clearly shows where to intervene to produce data-driven graphical representations.


LogRocket: Full visibility into your web and mobile apps

LogRocket signup

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

Try it for free.

Top comments (0)