Data visualization with D3.js
Creating Bar Chart with D3js
The essence of Bar Chart
A bar chart is one great tool to visualize quantitative data. A bar graph divides quantitative data down by group and represents these amounts of each group by using bars of different lengths, using either the number of individuals in each group (also called the frequency) or the percentage in each group (called the relative frequency) (Deborah J. Rumsey). In the simplest words, the graph shows a comparison between different categories or classes. Visually, the bars (each representing certain class/group) is plotted vertically (bars standing up) or horizontally (bars laying flat from left to right). The horizontal (x) axis represents the categories meanwhile the vertical (y) axis represents value for those categories.
Furthermore, in statistics, there is another type of bar chart which is so-called histograms. The main difference between a bar chart and histogram is on the data shown by each type. With bar charts, each column represents a group defined by a categorical variable; meanwhile, with histograms, each column represents a group defined by a continuous, quantitative variable. A histogram is used mostly in the scientific field meanwhile a bar chart is broadly used for general purposes.
D3.js, a data visualization tool for a web interface
D3 is a handy tool for programmers to provide a graphical illustration of data with the purpose of giving a better understanding of certain topics. Regarding data visualization, the library allows coders to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to in the form of Scalable Vector Graphics (SVG). Executed with OOP style programming in Javascript environment, D3 also offers a flexible and fully customizable way of manipulating DOM and its style to adjust the needs of the end-user. Built upon Jquery, D3 also inherits the same style and mechanism of conducting a broad array of Html operation.
Creating bar chart components with D3.js
In this writing, we will try to elaborate on the components of a bar chart (or histogram) and how to create each component using D3.js. For this purpose, let us breakdown a bar chart model into few components: setting layout, data entry, axis lines & tickmarks, drawing bars.
- Setting Layout
Lets us start with coding the layout. This part is the layer where we will put our chart title and as well as our x-axis and y-axis lines.
Referring to the code snippet below, firstly we need to decide the dimension of our chart ( layer constant) and margin (margin constant). Next, we inject our SVG layout into our div (with an id called “chart”) and keep it inside our layout constant. This way, it creates a shortcut for us to easily call the SVG background component for later usage. It is a common practice in D3 and Jquery in general with the intention to ease the Html DOM manipulation. Next, we add another group inside our layout SVG and add some more styling and formatting.
// =================================================================const margin = {top: 50, right: 50, bottom: 50, left: 50};
const layer = {width: 600,height:400 };const layout = d3.select('#chart')
.append('svg')
.style("background-color", "white")
.attr("width", layer.width+margin.right+margin.left)
.attr("height", layer.height+margin.top+margin.bottom)layout.append("g")
.append("text")
.text("Bar Chart")
.style("stroke-width", "1.5px")
.style("fill", "black")
.style("alignment-baseline", "middle")
.attr("x", margin.left)
.attr("y", 30)
.attr("text-anchor", "left")
.attr("font-family", "Poppins")
.attr("font-size", "20px");
Another basic part is to set up the background. This is the part where we will add our bars later. For the background, we do not embed the SVG background with the layout. We simply embed it to our #chart div instead. It is important to note that the dimension of our background is smaller than the layout and we need to place it in a proportional way. In that sense, we translate our background and position it on the left-bottom, on top of our layout.
// =================================================================const background = d3.select('#chart')
.append('svg')
.style("background-color", "grey")
.attr("width", layer.width)
.attr("height", layer.height)
.attr("transform", `translate(-${layer.width+margin.right},-${margin.top})`);
2. Data Entry
For this writing, we are using dummy hard-coded data about EPL Clubs and their respective number of trophies (data constant). In this part, it is good practice to know what is the highest value that will be projected on our diagram. Here, the highest value is obtained by returning the map of our data values and evaluating these values with d3.max function (maxValue constant). This value will be used to give color to our chart (will be explained later).
// =================================================================const data = [
{team:"Chelsea",trophy: 31},
{team:"Manchester United",trophy: 66},
{team:"Arsenal",trophy: 46},
{team:"Liverpool",trophy: 63},
{team:"Manchester City",trophy: 25}]const teams = data.map(function(object){
return object.team;// creating array of keys
});const trophiesNum = data.map(function(object){
return object.trophy;// creating array of values
});const maxValue = d3.max(trophiesNum);// defining max value
3. Scaling Method
This is the most important part of visualizing data with D3js. Scaling is calibrating the data of interest (continuous, interval-ration, nominal or ordinal data type) with the unit of scale that we use in our SVG diagram. With D3.js, most likely we are calibrating the real data with a defined length of x-a-axis or y-axis (depends on which axis the data will be plotted). In our case, the y-axis is scaled with the linear method (continuous data) meanwhile the x-axis is scaled with the band method (nominal data). Thus, we could assume that scaling is a function. So, for it to be ready to be called later, we need to embed the functions inside variables (yScale and xScale). Further material on the D3js scaling method can be seen on this link.
In addition, in this part, we also write the codes for coloring the chart. Embed in the color constant, we make use of the d3.scaleLinear() method to create a coloring function that takes ‘blue’ as the lowest value and “red’ as the highest value. Notice that we make use of the maxValue constant that holds the highest value of our data to be used in our coloring function.
// =================================================================const yScale = d3.scaleLinear() // projecting continuous data into the diagram
.domain([100,0])
.range([0,layer.height]);const xScale = d3.scaleBand() // projecting discrete data into the diagram
.domain(teams)
.range([0,layer.width])
.paddingInner(0.05);const barColors = d3.scaleLinear() // projecting continuous data into the diagram
.domain([0,maxValue])
.range(["blue","red"])
4. Axis lines and tickmarks
The next step is to draw the axis lines and also the tickmarks. This is important for readability and to give a proper sense of the data scaled in the chart. To do this, D3js has a special tool to draw the axis lines which we will use for the exercise: d3.axisLeft (draws the y-axis, embed in yAxis constant) and d3.axisBottom (draws the x-axis, embed in xAxis constant). Next, we append the axis lines into our layout constant.
// =================================================================const yAxis = d3.axisLeft(yScale);
const xAxis = d3.axisBottom(xScale);const yCartesian = layout.append("g")
.call(yAxis)
.attr("transform", `translate(${margin.right},${margin.top})`);
const xCartesian = layout.append("g")
.call(xAxis)
.attr("transform", `translate(${margin.right},${layer.height+margin.top})`);
5. Drawing the Bars
To draw the bars, first, we set a “bars” constant that holds a “rect” element. Then we insert our data into this element as well as appending an SVG group. To give the dimension of the bars with respect to our data of interest, we append an SVG “rect” element to our bars constant and add width and height attribute to it. The width attribute sets the width of our bars and for that, we use our xScale.bandwith() function. On the other hand, the height attribute sets the height of our bars. For this part, we want it to be customed according to the number of trophies of the EPL Team. Thus, we use a function in our height attribute: layer.height — yScale(d.trophy). Notice that we return the value of our layer height subtracted by the result of our yScale method on the number of trophies of each team.
Next, to set the placement of each bar, we add the “x” and “y” attribute. The “x” attribute denotes the x-axis location of the bar and we set it by returning the value of xScale towards the team name. Meanwhile, the “y” attribute denotes the y-axis location of the bar which is set by returning the value of or yScale method towards the number of trophies.
/ =========================================================== Drawing the barsconst bars = background
.selectAll("rect")
.data(data) //insert data into bars element
.enter()
.append("g")bars.append("rect")
.attr("width", xScale.bandwidth())
.attr("height", function(d){
return layer.height - yScale(d.trophy)
})
.attr("x", function (d) {
return xScale(d.team)
})
.attr("y", function(d){
return yScale(d.trophy)
})
.style("fill", function(d){
return barColors(d.trophy)
})
The final result of the bar chart can be seen in the picture below.