Skip to main content




For today's tutorial we are going to start designing and creating bar charts using D3.js, read on so you know how to do it

First of all, what is D3.js?

D3.js is a data-driven JavaScript library for manipulating DOM elements.

“D3 helps you bring your data to life using HTML, SVG, and CSS. D3's emphasis on web standards gives you all the capabilities of modern browsers without being tied to a proprietary framework, combining powerful display components and a data-driven approach to DOM manipulation. - d3js.org

Why should you create charts with D3.js? Why not just show an image?

Well, the charts are based on information from third party resources that require dynamic display during processing time. Also, SVG is a very powerful tool that is well suited to this application case.

Let's take a detour to see what benefits we can get from using SVG.

The benefits of SVG

SVG stands for Scalable Vector Graphics, which is technically an XML-based markup language.

It is commonly used to draw vector graphics, specify lines and shapes, or modify existing images.

Pros:

  • Compatible with all major browsers
  • Has DOM interface, does not require third party lib
  • Scalable, can maintain high resolution
  • Reduced size compared to other image formats.

Cons:

  • It can only display two-dimensional images;
  • Long learning curve
  • Rendering can be time consuming with compute intensive operations.
  • Despite its drawbacks, SVG is a great tool for displaying icons, logos, illustrations, or in this case graphics.

Starting with D3.js

I chose the bar chart to start with because it represents a low complexity visual while teaching the basic D3.js application itself. This shouldn't fool you, D3 provides a great set of tools for visualizing data.

A bar chart can be horizontal or vertical depending on its orientation. I'll go with the column chart aka vertical.

In this diagram, I am going to show the 10 most popular programming languages based on the result of the 2018 Stack Overflow Developer Survey.

Time to draw!

SVG has a coordinate system that starts from the upper left corner (0; 0). The positive x-axis goes to the right, while the positive y-axis goes to the bottom. Therefore, the height of the SVG must be taken into account when calculating the y coordinate of an element.

I want to create a graphic that is 1000 pixels wide and 600 pixels high.




In the above code snippet, I select the created element in the HTML file with D3 select. This selection method accepts all types of selection strings and returns the first matching element. Use selectAll if you want to get all of them.

I also define a margin value that gives a little extra padding to the chart. Fill can be applied with an element translated by the desired value. From now on, I use this group to keep a good distance from any other content on the page.

const chart = svg.append ('g') .attr ('transform', `translate ($ {margin}, $ {margin})`);

Adding attributes to an element is as easy as calling the attr method. The first parameter of the method takes an attribute that I want to apply to the selected DOM element. The second parameter is the value or a callback function that returns its value. The above code simply moves the start of the chart to position (60; 60) of the SVG.

D3.js input formats supported

To start drawing, I need to define the data source that I am working from. For this tutorial I use a simple JavaScript array that contains objects with the name of the languages and their percentages, but it is important to mention that D3.js supports various data formats.

The library has built-in functionality to load from XMLHttpRequest, .csv files, text files, etc. Each of these sources can contain data that D3.js can use, the only important thing is to build an array from it. Note that as of version 5.0, the library uses promises instead of callbacks to load data, which is not a backward-compatible change.

Scaling and axes

Let's continue with the axes of the graph. To draw the axis and, I need to set the lowest and highest value limit, which in this case are 0 and 100.

I'm working with percentages in this tutorial, but there are utility functions for data types other than numbers that I'll explain later.

I have to divide the height of the graph between these two values in equal parts. For this, I create something called a scaling function.

const yScale = d3.scaleLinear () .range ([height, 0]) .domain ([0, 100]);

The linear scale is the most popular type of scale. Converts a continuous input domain to a continuous output range. Look at the rangey domain method. The first takes the length that must be divided by the limits of the domain values.

Remember, the SVG coordinate system starts from the upper left corner, so the range takes the height as the first parameter and not zero.

Creating a left axis is as simple as adding another group and calling D3's axisLeft method with the scale function as a parameter.

chart.append ('g') .call (d3.axisLeft (yScale));

Now, continue with the x-axis.

const xScale = d3.scaleBand () .range ([0, width]) .domain (sample.map ((s) => s.language)) .padding (0.2) chart.append ('g') .attr ( 'transform', `translate (0, $ {height})`) .call (d3.axisBottom (xScale)); d3-js-tutorial-bar-chart-labels

Note that I use scaleBand for the x-axis, which helps to divide the range into bands and calculate the coordinates and widths of the bars with additional padding.

D3.js is also capable of handling the date type among many others. scaleTime is really similar to scaleLinear, except the domain here is a set of dates.

Drawing bars in D3.js

Think about what kind of input we need to draw the bars. Each represents a value that is illustrated with simple shapes, specifically rectangles. In the following code snippet, I attach them to the created group item.

chart.selectAll () .data (goals) .enter () .append ('rect') .attr ('x', (s) => xScale (s.language)) .attr ('y', (s) => yScale (s.value)) .attr ('height', (s) => height - yScale (s.value)) .attr ('width', xScale.bandwidth ())

First, you use selectAll to select the elements in the chart that returns with an empty result set. Then the data function that indicates how many elements the DOM should be updated based on the length of the array. enter identifies missing items if the data entry is longer than the selection. This returns a new selection representing the items to be added. Usually this is followed by an append element that adds elements to the DOM.

Basically I tell D3.js to add a rectangle for each member of the array.

Now this just adds rectangles on top of each other that have neither height nor width. These two attributes have to be calculated and that is where scaling functions come in handy again.

Look, I add the coordinates of the rectangles with the attr called. The second parameter can be a callback that takes 3 parameters: the actual member of the input data, its index, and the entire input.

.attr ('x', (actual, index, array) => xScale (actual.value))

The scale function returns the coordinate for a given domain value. Calculating the coordinates is a piece of cake, the trick is with the height of the bar. The calculated y-coordinate must be subtracted from the height of the graph to get the correct representation of the value as a column.

I define the width of the rectangles with the scaling function also scaleBand has a bandwidth function that returns the calculated width for an element based on the padding set.

d3-js-tutorial-bar-chart-drawn-out-with-javascript

Nice work, but not so fancy, right?

To prevent our audience from getting bored, let's add information and enhance the images to make your graphic look much better!

R Marketing Digital