D3 Notes (outdated version)
Intro
Notes while learning D3
D3 Bar Chart
Bind Data To Rectangles
Let's work on making a simple bar chart, given a very simple dataset. Remember that all these D3 methods can be view in the D3 API Documentation
let w = 500
let h = 100
let padding = 2
let dataset = [5, 10, 15, 20, 25]
let svg = d3
.select("body") // create svg
.append("svg")
.attr("width", w)
.attr("height", h)
svg
.selectAll("rect") // select multiple descendants for each selected element.
.data(dataset) // bind elements to data
.enter() // get the enter selection (data missing elements).
.append("rect") // create rectangles
.attr("x", 0) // x co-ordinate
.attr("y", 0) // y co-ordinate
.attr("width", 20)
.attr("height", 100)
So now we have created a rectangle in our svg for each piece of data in our dataset. However we have hard coded the x and y co-ordinates, and width and height for each of them. Therefore they are all stacked on top of each other.
Dynamic Co-ordinates
Things get interesting when we start to change these positioning and size elements dynamically. Let's start by changing the rectangles x-coordinates dynamically.
let w = 500
let h = 100
let padding = 2
let dataset = [5, 10, 15, 20, 25]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * 21
})
.attr("y", 0)
.attr("width", 20)
.attr("height", 100)
We have put in a little inline function that takes d
and i
as arguments. In D3 we use d
to refer to the dataset, and then i
as is typical, refers to the iteration or item. So we are looping over the dataset and for each item returning an x coordinate that is 21px larger than the one before it. We chose 21 for this number because each rectangle has a width of 20 and we are leaving them a 1px margin for visibility. That gives us this.
Which is a start, but we actually want to space the bars evenly according to the width of the svg. So we can take the width of the svg and divide it by the number of items in the dataset.
let w = 500
let h = 100
let padding = 2
let dataset = [5, 10, 15, 20, 25]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (w / dataset.length) // highlight-line
})
.attr("y", 0)
.attr("width", 20)
.attr("height", 100)
which give us this.
Dynamic Shape
Now we can adjust the width of the bars to fill the space more evenly.
let w = 500
let h = 100
let padding = 5
let dataset = [5, 10, 15, 20, 25]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (w / dataset.length)
})
.attr("y", 0)
.attr("width", w / dataset.length - padding) // highlight-line
.attr("height", 100)
Now if we try to set the height of each bar to it's own number we hit a bit of a snag
let w = 500
let h = 100
let padding = 5
let dataset = [10, 40, 30, 15, 60, 80, 100]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (w / dataset.length)
})
.attr("y", 0)
.attr("width", w / dataset.length - padding)
.attr("height", function (d) {
return d
})
The bars are hanging from the ceiling.
This is because of the way the coordinate system in svg works, starting in the top left. So we need to change the y-coordinate for each rectangle.
let w = 500
let h = 100
let padding = 5
let dataset = [10, 40, 30, 15, 60, 80, 100]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (w / dataset.length)
})
.attr("y", function (d) {
return h - d
})
.attr("width", w / dataset.length - padding)
.attr("height", function (d) {
return d
})
It's starting to look like we've got something here!
Dynamic Color
We can add a bit of dynamic color easily
let w = 500
let h = 100
let padding = 5
let dataset = [10, 40, 30, 15, 60, 80, 100]
let svg = d3.select("body").append("svg").attr("width", w).attr("height", h)
svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (w / dataset.length)
})
.attr("y", function (d) {
return h - d
})
.attr("width", w / dataset.length - padding)
.attr("height", function (d) {
return d
})
.attr("fill", function (d) {
return `rgb(0,${d * 2},0)`
})
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.