##Great, but…
80 lines & 2284 characters of js
Reuse conventions with copy/paste
##d3-jetpack
##appending with class Before
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
After
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g.legend")
##appending with class Works with ids and multiple classes
Before
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
After
svg.append("g.y.axis")
.call(yAxis)
.append("text.label")
##translate Before
svg.append("g.x.axis")
.attr("transform", "translate(0," + height + ")")
After
svg.append("g.x.axis")
.translate([0, height])
##translate Functions called w/ bound data and index
Before
legend
.attr("transform", function(d, i){
return "translate(0," + i * 20 + ")" })
After
legend
.translate(function(d, i){ return [0, i*20] })
##ƒIELD ACCESSOR Turns a string into a function
function ƒ(str){
return function(object){
return object[str]
}
}
Returns properties from objects
var collie = {color: 'brown', legs: 4}
var spider = {color: 'black', legs: 8}
ƒ('color')(collie) //'brown'
ƒ('color')(spider) //'black'
ƒ('legs')(spider) //8
##ƒIELD ACCESSOR
Before
x.domain(d3.extent(data, function(d) { return d.sepalWidth; }))
y.domain(d3.extent(data, function(d) { return d.sepalLength; }))
After
x.domain(d3.extent(data, ƒ('sepalWidth')))
y.domain(d3.extent(data, ƒ('sepalLength')))
##Compose Combines two funtions together
function compose(g, h){
return function(object){
return h(g(object))
}
}
function add10 (n){ return 10 + n }
function double(n){ return 2 * n }
compose(ƒ('legs'), add10) (collie) //4 + 10 = 14
compose(ƒ('legs'), add10) (spider) //8 + 10 = 18
compose(ƒ('legs'), double)(spider) //8 * 2 = 16
##ƒIELD ACCESSOR
Before
dots
.attr("cx", function(d) { return x(d.sepalWidth); })
.attr("cy", function(d) { return y(d.sepalLength); })
.style("fill", function(d) { return color(d.species); })
After
dots
.attr("cx", compose(ƒ('sepalWidth'), x))
.attr("cx", compose(ƒ('sepalLength'), y))
.style("fill", compose(ƒ('species'), color))
##ƒIELD ACCESSOR Converts strings to functions and composes
ƒ('legs', add10) (collie) //4 + 10 = 14
ƒ('legs'), double)(spider) //8 * 2 = 16
ƒ(add10, double, add10)(3) //((3 + 10) * 2 ) + 10 = 36
ƒ()(3) //3
##ƒIELD ACCESSOR Before
dots
.attr("cx", compose(ƒ('sepalWidth'), x))
.attr("cx", compose(ƒ('sepalLength'), y))
.style("fill", compose(ƒ('species'), color))
After
dots
.attr("cx", ƒ('sepalWidth', x))
.attr("cx", ƒ('sepalLength', y))
.style("fill", ƒ('species', color))
##ƒIELD ACCESSOR Also works as an identity function
Before
legend.append("text")
.text(function(d) { return d })
After
legend.append("text")
.text(ƒ())
##d3-starterkit Snippets and conventions for starting a new d3 project
github.com/1wheel/d3-starterkit
##dataAppend Before
svg.selectAll(".dot")
.data(data)
.enter().append("circle.dot")
After
svg.dataAppend(data, "circle.dot")
##dataAppend
d3.selection.prototype.dataAppend = function(data, name){
return this.selectAll(name)
.data(data).enter()
.append(name)
##dataAppend Before
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g.legend")
After
legend = svg.dataAppend(color.domain(), "g.legend")
##d3.conventions - margins Before
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")")
After
var c = d3.conventions({
margin: {top: 20, right: 20, bottom: 30, left: 40},
width: 900,
height: 450,
})
c.svg.dataAppend(data, "circle.dot")
##d3.conventions - scales Creates and sets the domain for x and y scales
Before
var x = d3.scale.linear()
.range([0, width])
.domain(d3.extent(data, ƒ('sepalWidth')))
var y = d3.scale.linear()
.range([height, 0])
.domain(d3.extent(data, ƒ('sepalLength')))
After
c.x.domain(d3.extent(data, ƒ('sepalWidth')))
c.y.domain(d3.extent(data, ƒ('sepalLength')))
##d3.conventions - axis Creates and configures x and y axis
Before
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
After
console.log(c.xAxis.orient()) //"bottom"
##d3.conventions - axis Draws x and y axis
Before
svg.append("g.x.axis")
.translate([0, height])
.call(xAxis)
.append("text.label")
.attr("x", width)
After
c.drawAxis()
c.svg.select('.x.axis')
.append("text.label")
.attr("x", c.width)
##Significantly shorter Scatter II
##Minimally viable (scatter) plot Scatter III
d3.tsv("data.tsv", function(data) {
var c = d3.conventions()
c.x.domain(d3.extent(data, ƒ('sepalWidth')))
c.y.domain(d3.extent(data, ƒ('sepalLength')))
c.drawAxis()
c.svg.dataAppend(data, "circle.dot")
.attr("r", 3.5)
.attr("cx", ƒ('sepalWidth', c.x))
.attr("cy", ƒ('sepalLength', c.y))
.style("fill", ƒ('species', c.color))
})
##There’s more!
##Tutorials
roadtolarissa.com/stacked-bump
roadtolarissa.com/data-exploration