D3 js : Bar Chart 1

In this post we would be making a bar chart using svg . Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation. It has many advantages over the other formats like jpeg etc and flash. Svg images are zoomable without any degradation. It is scalable and can be printed in high quality at any resolution. SVG images can be created and edited with any text editor and can be searched, indexed, scripted, and compressed.

Lets start : index.html


<!DOCTYPE html>
<html>
<head>
<title>D3 Bar Chart</title>
 <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
 <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
 <script>
 var data=[10,30,50,34,65,87,65,23,45,14];
 var width=800;
 var height=450;
 var svg=d3.select("body").append("svg")
 .attr("id","chart")
 .attr("width",width)
 .attr("height",height)
 </script>
</body>
</html>

As you can see we created an svg element programatically if id ‘chart’ using d3 and appended it to body. Its link to a style.css


body.html{
 margin: 0;
 padding:0;
 font-family:'Arial';
 text-align: center;
}

#chart{
 background-color: lightyellow;
 border: 1px solid #ccc;
}

d3BarChart1-1

Lets draw bars in this svg


var data=[10,30,50,34,65,87,65,23,45,14];
var width=800;
var height=450;
var svg=d3.select("body").append("svg")
.attr("id","chart")
.attr("width",width)
.attr("height",height);

svg.selectAll(".bar") //empty selection
.data(data) //for each item
.enter() // first time we are telling d3 to bind data
.append("rect")
.attr("class","bar")
.attr("x",0)
.attr("y",0)
.attr("width",20)
.attr("height",20);

d3BarChart1-2

As you can see a bar at top left corner. All the data is lying on top of each other and we have harcoded the width and height of the bar to 20.

Note :  x=0 and y=0 starts from the top left corner and y axis increases as we go down in svg. x-axis increases as we go right in svg. This is a bit different from the cartisian system.

Lets make the bar according to our data. We want the height to be same as 20 but width values to change according to the data in array.


var data=[10,30,50,34,65,87,65,23,45,14];
var width=800;
var height=450;
var svg=d3.select("body").append("svg")
.attr("id","chart")
.attr("width",width)
.attr("height",height);

svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class","bar")
.attr("x",0)
.attr("y",function(d,i){  // incrementing y axis
return i*20;
})
.attr("width",function(d,i){ // bars width according to the data
return d;
})
.attr("height",19); //To have a little space between the bars

d3BarChart1-3

Note that the width is the actual px in the data. We have currently lot of empty space available. What if we want to scale our data according to the available area. For this we need a scaling function for both x and y axis.


var data=[10,30,50,34,65,87,65,23,45,14];
var width=800;
var height=450;
var x=d3.scale.linear()
.domain([0,d3.max(data)])
.range([0,width]);
var y=d3.scale.linear()
.domain([0,data.length])
.range([0,height]);
var svg=d3.select("body").append("svg")
.attr("id","chart")
.attr("width",width)
.attr("height",height);

svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class","bar")
.attr("x",0)
.attr("y",function(d,i){
return y(i);
})
.attr("width",function(d,i){
return x(d);
})
.attr("height",function(d,i){
return y(1)-1;
});

d3BarChart1-4

Right now our chart takes up the full space of our svg element. It would be nice to have some magin from all sides.  This can be achieved by a specific element in svg called the group. Its bit like a div i.e a container that hold other elements so that the whole group of elements can be moved as a group.


var data=[10,30,50,34,65,87,65,23,45,14];
var width=800;
var height=450;
var margin = {
top: 20,
bottom: 20,
left: 20,
right: 20
};
var widthBar = width - margin.left - margin.right;
var heightBar = height - margin.top - margin.bottom;
var x=d3.scale.linear()
.domain([0,d3.max(data)])
.range([0,widthBar]);
var y=d3.scale.linear()
.domain([0,data.length])
.range([0,heightBar]);
var svg=d3.select("body").append("svg")
.attr("id","chart")
.attr("width",width)
.attr("height",height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class","bar")
.attr("x",0)
.attr("y",function(d,i){
return y(i);
})
.attr("width",function(d,i){
return x(d);
})
.attr("height",function(d,i){
return y(1)-1;
});

Here we first changed our ordinal to the new width and height. Then we added the ‘g‘ element to the svg and used the ‘transform‘ attribute to have padding. Also notice that we .classed(“bar”,true), The first argument is the class name. The second argument is a boolean which if true will add the class and if false, will remove the class. (If we use .attr(“class”,”bar”), it will always remove any existing class present and replace all by class bar.) Adding bar class in our style.css


.bar{
fill: teal;
shape-rendering: crispEdges;
}

d3BarChart1-5

Advertisements
%d bloggers like this: