How to make a Bar Chart in D3

Basic Bar Chart

A basic bar chart

Step 1: Prepare your data as a CSV file

Make sure your data are real numbers, and have no commas or symbols in them (decimals are OK).

Convert currency dollars to real numbers

Note, that the headers of your spreadsheet will become properties of your data when you bring it in.

Google Spreadsheet Headers

To access each piece of data, the following notation would be used:

data[0]["Age Group"] //will return "Less than 35"
data[1]["Age Group"] //will return "35-44"
data[2]["Age Group"] //will return "45-54"
data[3]["Age Group"] //will return "55-64"
//...and so on

data[0]["Median Price"] //will return "7100"
data[1]["Median Price"] //will return "23000"
data[2]["Median Price"] //will return "44000"
data[3]["Median Price"] //will return "59200"
//...and so on

Save your spreadsheet as a .csv file in a folder where you will put the html for your bar chart.

Step 2: Create your HTML file

Here is a basic boilerplate template with the D3 library included to start you off. Save this with the .html file extension in the same folder as your .csv file.

<!DOCTYPE html>
    <meta charset="utf-8">
    <title>Basic Bar Chart</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
    /* custom css styles will go here */


    <script src=""></script>
        //your d3 code will go here


Step 3: Setup your size variables and your SVG

Next, setup some basic size variables for our SVG container.

var margin = {top:0, right:0, bottom:20, left:50},
    width  = 800,
    height = 500;

var svg ="body")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("viewBox", "0 0 " + width + " " + height);

The viewBox attribute specifies the internal coordinate system for your chart using an x y width height format. This way you can set the width and height to 100%, and your chart will become responsive.

Step 4: Set your scales

Next, set the scales for the X and Y axis. For a column bar chart chart, your X scale will be determined the number of elements you have, and your Y scale will be determined the maximum value of your data.

We also subtract the margins, since these will add space for our axes and any labels we decide to add.

var yScale = d3.scale.linear()
    .range([height - - margin.bottom, 0]);

var xScale = d3.scale.ordinal()
    .rangeRoundBands([0, width - margin.right - margin.left], .1);

As a reminder, .rangeRoundBands is a special bar-chart function to make the bars clean and spaced properly.

Step 5: Add functions for axes

Axes are pretty straight forward. Use the scale functions to determine the tick values of the axes.

var xAxis = d3.svg.axis()

var yAxis = d3.svg.axis()

Step 6: Running a Python SimpleHTTPServer

For Macs, you can launch the Terminal program, navigate to the folder where your project is using terminal commands cd (tutorial here), then run the following command:

python -m SimpleHTTPServer 8000

Step 7: Loading in the CSV file using D3

Next, we load in the CSV file.

d3.csv("stockowners.csv", function(error, data){

    //code in next sections will go here.

Step 8: Coercing the strings as numbers

D3 pulls in data as strings, even when they’re numbers. You can convert your data so that the strings will be recast as numbers.

//map function goes through every element, then returns a number for median price
data ={ 
    d["Median Price"] = +d["Median Price"]; 
    return d;

Step 9: Setting the domains for the X and Y scales

Since we are loading in our data via CSV, we can’t set the domains until the data is loaded in. After we load in the data and coerce as numbers, we can set our domains. Our X scale simply needs unique strings for each element in the data (in our case, Age Group), and our Y scale need a domain from zero to the maximum value.

In each situation, we map the data from the array of objects.

//yscale's domain is from zero to the maximum "Median Price" in your data
yScale.domain([0, d3.max(data, function(d){ return d["Median Price"]; })]);

//xscale is unique values in your data (Age Group, since they are all different)
xScale.domain({ return d["Age Group"]; }));

Step 10: Creating the Bar Chart

Next, we run through our data and build the bar chart. We will add the bar chart to a grouping “g” element so that we can account for margins. It’s important to add a class name to each bar so that we can style it with CSS.

    .attr("transform", "translate(" + margin.left + "," + + ")")
    .attr("class", "bar")
    .attr("x", function(d){ return xScale(d["Age Group"]); })
    .attr("y", function(d){ return yScale(d["Median Price"]); })
    .attr("height", function(d){ return height - - margin.bottom - yScale(d["Median Price"]); })
    .attr("width", function(d){ return xScale.rangeBand(); });

Step 11: Adding the axes

To add the axes, append a “g” group element, and use the transform attribute to position it in the correct location accounting for the margins. Then call either the xAxis or yAxis functions you created earlier.

We also add two class names so we can style each axis individually.

//adding y axis to the left of the chart
    .attr("class", "y axis")
    .attr("transform", "translate(" + margin.left + "," + + ")")

//adding x axis to the bottom of chart
    .attr("class", "x axis")
    .attr("transform", "translate(" + margin.left + "," + (height - margin.bottom) + ")")

In addition, when working with currency, you may want to add the dollar symbol to the front of each number. You can do this by going back to where you created the yAxis variable, and setting a tickFormat.

//go back to where you created yAxis
var yAxis = d3.svg.axis()
    .tickFormat(d3.format("$,"));//...then add this line, a tickFormat for currency

Step 12: Add CSS for styling

If you looked at your chart at this point, it might appear somewhat ugly. To improve the appearance, add some CSS styling based on the class names you’ve assigned.

    .axis text{
      font-family: Helvetica, Arial, sans-serif;
      font-size: 12px;
      text-anchor: end;
    .axis path{
      stroke-width: 0.5px;
      shape-rendering: crispEdges;
        stroke: none;
        fill: steelblue;
        font-family: Helvetica, Arial, sans-serif;
        text-anchor: middle;

Step 13 (Optional): Make adjustments

Once your data is in and you see your chart, you may wish to make some adjustments so that the graph can communicate effectively. You can make adjustments to your domain on your yScale, for example, so that the maximum value isn’t all the way at the top.

//increasing domain to static 140000, so it's more than maximum value in your data
yScale.domain([0, 140000]);

It’s also possible to add labels at the top of each bar by running through the data again. (Another more efficient way would have been to create a grouping for each bar then append text to that).

Here we use the same X and Y scales to place each text label above the bars.

//add text labels to the top of each bar
    .attr("transform", "translate(" + margin.left + "," + + ")")
    .attr("class", "textlabel")
    .attr("x", function(d){ return xScale(d["Age Group"]) + (xScale.rangeBand()/2); })
    .attr("y", function(d){ return yScale(d["Median Price"]) - 3; })
    .text(function(d){ return d3.format("$,")(d["Median Price"]); });
    //more info about d3 format method:

You can also adjust the padding to account for a label at the top.

//add additional top margin to make room for label
var margin = {top:50, right:0, bottom:20, left:50}

Then add the title at the top. We use width divided by 2, to center (make sure the text-anchor is set to middle for the CSS styling to properly center the text).

//adding a label at the top of the chart
    .attr("transform", "translate(" + (width/2) + ", 15)")
    .text("Stock Wealth by Age")
    .style({"text-anchor":"middle", "font-family":"Arial", "font-weight":"800"});