Current Graph
Master the fundamentals of D3 with this interactive tutorial
Current Graph
This tutorial will help you learn the major principles of D3 so you can easily build custom graphs.
Picking up D3 can be very challenging. It relies on a novel challenge for developers- converting an array or object into a dynamic data visualization with specific properties.
This tutorial aims to make D3 so simple that you can explain it to a friend. We will build a basic bar graph using a gardening analogy so you can see the principles play out in front of you.
You must know HTML/CSS, and have at least a beginner's understanding of Javascript. You must understand concepts like "for" loops, objects and arrays.
D3 uses SVG (Scalable Vector Graphics) to draw its elements.
We need to declare an area to create our visualization. Drag the resizable box to create your bounded area. You will want a big garden!
Please make your box at least 410 x 410
Learn how to create the SVG in D3
var svg = d3.select('div.foo').append('svg')
.attr('width' , 'Xpx' ).attr('height' , 'Ypx' );
d3.select('div.foo')= Equivalent of jQuery $(), select the container with class foo
.append('svg')= Append an SVG element to the DOM
.attr('width' , 'Xpx' )= Declare an attribute for your SVG, then set value
var svg =
Your container div has class 'gardenDiv'
Append the svg
Declare a width of 0px
Declare a height of 0px
Docs
Please enter all fields and correct pixel amounts
selectAll() declares a more specific group where you will be adding elements
selectAll() creates an empty set that will later be filled with elements. It is technically infinite, but we will portray it as finite for the sake of visualizing it.
selectAll() creates holes that you will be filling with seeds of a specific type. You cannot dig holes where other elements have already been created, so this must be a new set of elements
Docs
Dig those holes!
svg.selectAll('rect.bar')
This statement looks for all rect elements (from SVG specification) with class 'bar'. If there are none, it creates an empty set.
svg
Create an empty set of rect elements with class 'colorBar'
Docs
Please use selectAll() with rect elements of class 'colorBar'
data() declares the object or array you will use for the visualization
data() determines the data that you will then iterate through in order to create a series of elements
data() is the type of seeds you will be using- each seed type has unique properties that will determine its features when it grows into a plant
Docs
Tomatoes
Cucumbers
Peppers
Check out the properties
svg.selectAll('rect.bar').data(data)
Data() declares the object or array you will be iterating through. Pretty straightforward.
svg.selectAll('rect.bar')
Add the data contained in the variable tomatoes
Docs
Please make sure the variable matches the object above
Enter() performs the data join
svg.selectAll('rect.bar').data(data).enter()
enter() combines your data with the empty set from selectAll() and creates a set of elements that can then be accessed one by one in D3
This adds the seeds you selected in the past step to the garden, and matches the number of holes with number of plants. There are now 20 seeds in holes ready to be structured.
svg.selectAll('rect.bar').data(data)
Add your enter statement, that is it!
Docs
Show Full Array
Please make sure you used the enter statement
Append() determines the type of visualization
Append() allows you to choose from the 7 basic SVG elements or a 'g' element. In this case, we want a 'rect' element to build a bar graph.
You want the seeds you planted to grow in a defined way. We will add complementary structures like trellises to the garden to help our plants grow vertically.
svg.selectAll('rect.bar').data(data)
.enter().append('rect')
svg.selectAll('rect.bar').data(data).enter()
Append a rect element for each item in your data
Docs
Show Full Array
Please make sure you appended a 'rect' element
We are close to building a bar graph!
svg.selectAll('rect.bar').data(data)
.enter().append('rect')
svg.selectAll('rect.bar')= Creates an empty set of rect elements with class 'bar'
.data(data)= Adds object or array of data to be turned into elements in the DOM
.enter()= Join your data with the empty set defined in selectAll, can iterate through this set
.append('rect')= Append a 'rect' element for every item in data
Attr() statements define the properties of each bar
.attr('width' , function (d,i) { return d.width })
Attr() statements define what you want your bars to look like. Most importantly, they can use properties from each item in data.
We will do the width first, so this will define the width of each plant.
Write out the statement above, which defines the width based on the 'width' property of each item in the data object
Docs
Show Full Array
Please make sure you copied the statement above
Define each element's attributes
.attr('height' , function (d,i) { return d.height })
In the statement 'function(d,i)', d stands for each item in data while i is the index, beginning at 0 for the first element
Now each plant will have a different height based on the object's properties
Write out the statement above, which defines the height based on the 'height' property of each item in the data object
Docs
Show Full Array
Please make sure you copied the statement above
Separate bars from each other
.attr('x' , function (d,i) { return i * d.width })
In last statement we ended up with... a bunch of plants stacked on top of one another. That was disappointing. We also need to define x values for each bar so that they do not stack on top of each other, like they did in the last step.
Using the index of each bar, we can move them right to spread them out. We can multiply this index by the width of each bar to spread them out.
Now each plant will align with the appropriate structure as opposed to being stacked on top of each other in the first position.
Write out the statement above, which defines the x-position based on the index and separates based on bar width
Docs
Show Full Array
Please make sure you copied the statement above
The origin is the top left corner... which means your bars may be pointing the wrong direction!
.attr('y' , function (d,i) { return divHeight - d.height })
The origin i.e. start point for D3 is the top left corner of the div. This means that when you set the height of a bar... it is growing downwards from the top left! Not good. So, we need to reverse this.
We need to set a new start point for the bar to grow from. We subtract the bar height from the overall height of the div. We start from the bottom of the containing div, and draw the bar starting from there!
Write out the statement above, which defines the y-position based on the height of the svg.
Please make sure you copied the statement above
var w= 535;
var h= 250;
var svg= d3.select('.gardenDiv')
.append('svg')
.attr('width', w)
.attr('height', h);
svg.selectAll('rect.colorBar')
.data(data)
.enter()
.append('rect')
.attr('width', function(d,i){
return d.width
})
.attr('height', function(d,i){
return d.height*2
})
.attr('x', function(d,i){
return i * (d.width+2)
})
.attr('y', function(d,i){
return h - d.height*2
})
.attr('fill', 'white')
Before we add an axis to the graph, we need to define the start and end point.
var xScale = d3.scale.linear()
.domain( [0, data.length] )
.range( [0, width] );
d3.scale.linear()= Indicates your scale will be linear across the range you specify, as opposed to exponential etc.
.domain( [0, data.length] )= Specifies that the scale ranges from 0 to the count of total number of items in the array
.range( [0, width] )= Maps the specified domain to corresponding spots on the SVG. In this case, extends the full width of the SVG.
var xScale =
Add a linear scale
Add a domain that spans from 0 to the count of numbers in data
Add a range that spans the width of the SVG
Docs
Please make sure you specified domain and range correctly
Before we add an axis to the graph, we need to define the start and end point.
var yScale = d3.scale.linear()
.domain( [0, d3.max(data, function(d) { return d.height; })] )
.range( [0, height] );
d3.scale.linear()= Indicates your scale will be linear across the range you specify, as opposed to exponential etc.
.domain( [0, d3.max(data, function(d) { return d.height; })] )= Specifies that the scale ranges from 0 to the tallest bar, which d3.max will find based on the height attribute
.range( [0, height] )= Maps the specified domain to corresponding spots on the SVG. In this case, extends the full height of the SVG.
var yScale =
Add a linear scale
Add a domain that spans from 0 to the tallest bar
Add a range that spans the height of the SVG
Docs
Please make sure you specified domain and range correctly
Now that we have scales, we can turn them into elements in the DOM
var xAxis = d3.svg.axis().scale(xScale)
d3.svg.axis()= Indicates that we want to create an element with the characteristics of an axis i.e. can have labels and tick marks
.scale(xScale)= Specifies that we want to use the xScale we already specified
var xAxis =
Add an axis
Add a scale called xScale
Docs
Please make sure you specified the scale correctly
Now we can use an append statement to get this axis on the graph
svg.append("g").call(xAxis);
.append("g")= An axis is not just a line. It can also include ticks and labels. So we will need a "g" element, not a path.
.call(xAxis)= The characteristics of this axis will be based on the axis we defined
We can now add a fence to our garden
svg
Append a g element
Call xAxis
Docs
Please make sure you called the correct variable
Now that we have scales, we can turn them into elements in the DOM
var yAxis = d3.svg.axis().scale(yScale)
.orient("left")
d3.svg.axis()= Indicates that we want to create an element with the characteristics of an axis i.e. can have labels and tick marks
.scale(yScale)= Specifies that twe wantto use the xScale we already specified
.orient("left")= Specifies that this will be a vertical axis, from bottom to top
var yAxis =
Add an axis
Add a scale called yScale
Docs
Please make sure you specified the scale correctly
Now we can use an append statement to get this axis on the graph
svg.append("g").call(yAxis);
.append("g")= An axis is not just a line. It can also include ticks and labels. So we will need a "g" element, not a path.
.call(yAxis)= The characteristics of this axis will be based on the axis we defined
We can now add a fence to our garden
svg
Append a g element
Call yAxis
Docs
Please make sure you called the correct variable
The x axis needs to be at the bottom of the graph
So obviously, you would not want the x axis at the top of your graph! Let's use transform to move it to the bottom.
svg.append("g")
.attr("transform", "translate(0," + (height) + ")").call(xAxis);
.attr("transform", "translate(0," + (height) + ")")= Translate takes two arguments: right and down. This statement moves the axis 0 units right, and moves it downward bythe entire height of the svg. In other words, the bottom
svg.append("g")
Move the axis to the bottom of the SVG
Docs
Please make sure you called the transform/translate command
var w= 535;
var h= 250;
var svg= d3.select('.gardenDiv')
.append('svg')
.attr('width', w)
.attr('height', h);
svg.selectAll('rect.colorBar')
.data(data)
.enter()
.append('rect')
.attr('width', function(d,i){
return d.width
})
.attr('height', function(d,i){
return d.height*2
})
.attr('x', function(d,i){
return i * (d.width+2)
})
.attr('y', function(d,i){
return h - d.height*2
})
.attr('fill', 'white')
var xScale = d3.scale.linear()
.domain( [0, data.length] )
.range( [0, w] );
var yScale = d3.scale.linear()
.domain(
[0,
d3.max(data, function(d) {
return d.height; })
])
.range( [0, h] );
var xAxis = d3.svg.axis()
.scale(xScale)
.ticks(0)
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(0)
svg.append("g")
.attr("transform",
"translate(5,0)")
.call(yAxis);
svg.append("g")
.attr("transform",
"translate(0," + (h-5) + ")")
.call(xAxis);