D3.js

Data-Driven Documents

Slides : bit.ly/sfhtml5-d3

Aysegul Yonet / @AysegulYonet

AnnieCannons.com

What is D3?

What d3 is not?

Google Charts Example

D3 Scatterplot Example

Examples

  • SVG
  • Selections
  • Update Pattern
  • Scales
  • Loading External Data
  • Working with Data

Web Standards

  • HTML
  • CSS
  • SVG

SVG

  • Another HTML element, except you can not put another HTML element inside an SVG.
  • Does not support common HTML attributes or styles such as position, left, top, right, bottom or float.
  • Default svg size is browser-dependant.

Circle




						

Rectangle




						

Group



	
	
	
	

						

jsFiddle

Line




						

Path




										
						
  • M - move.
  • L - line.
  • z - close path.

Text



	
		Look at me, I am a text.
	

						

Selection

jQuery


						var paragraphs = $("div p");
					

D3


						var paragraphs = d3.select("div").selectAll("p");
					
jsFiddle

var p = d3.select("body").append('p');
p.html('Hello SFHTML5!').attr('style', 'color: red;');
					

jsFiddle

Data


d3.selectAll("p")
	.data([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
					

JSFiddle

Enter()


d3.select("body").selectAll("p")
	.data([3, 7, 21, 31, 35, 42])
	.enter();
					

Append()


d3.select("body").selectAll("p")
	.data([3, 7, 21, 31, 35, 42])
	.enter().append("p")
	.text(function(d) { return "I’m number " + d + "!"; });
					

JSFiddle

Exit() and Remove()


var bars = d3.select('body').selectAll('p').data(newData);

//if we have more data, add new 'p' for those data items
bars.enter().append('p')

//if we have less data points, remove the 'p' that no longer have a data pairing. 
bars.exit().remove();
					

Update Pattern


// Update…
var p = d3.select("body").selectAll("p")
	.data([3, 7, 21, 31, 35, 42]);

// Enter…
p.enter().append("p")

// Exit…
p.exit().remove();
					

JSFiddle

Chaining


d3.select("body").selectAll("p")
	.data([3, 7, 21, 31, 35, 42])
	.enter().append("p")
	.exit().remove();
					

jsFiddle

Operating on selection

  • Setting attributes or styles
  • Registering event listeners
  • Adding, removing or sorting nodes
  • Changing HTML or text content

JSFiddle

Transition


circles.attr("r", "0")
	.attr({
			'cx': function(d) {return (d * 2); },
			'cy': 10
	})
	.transition()
	.duration(750)
	.delay(function(d, i) { return i * 100; })
	.attr("r", 10);
					

JSFiddle

Scales


var scale = d3.scale.linear();
					

Quantitative Scale

  • Linear scales
  • Logarithmic scales
  • Power scales

var xScale = d3.scale.linear()
		.domain([0, d3.max(data)])// your data minimum and maximum
		.range([0, 420]);//the pixels to map to
d3.select(".chart")
	.selectAll("div")
		.data([3, 7, 21, 31, 35, 42])
	.enter().append("div")
		.style("width", function(d) { return xScale(d) + "px"; })
						
JSFiddle

var xScale = d3.scale.linear()
			.domain([0, 1000])
			.range([0, 200]);
console.log(xScale(500)); //100
console.log(xScale.domain());//[0, 1000]
						

Ordinal Scale

Ordinal Scale have a discrete domain, such as a set of names or categories.


var xScale = d3.scale.ordinal()
	.domain(["Bob", "Stuart", "Kevin", "Scarlet"])
	.rangePoints([0, 100]);
console.log(xScale("Stuart"));//33.333333333333336

xScale.range(); // [0, 33.333333333333336, 66.66666666666667, 100]
					

JSFiddle

Color Categories

d3.scale.category10()

JSFiddle

Scatterplot


var svg = d3.select('body').append('svg')
	.attr({
				'width': 250,
				'height': 250
		});

var xScale = d3.scale.linear()
	.domain([0, 5])
	.range([0, 200]);

						


var render = function(data, r, color){
	//Bind data
	var circles = svg.selectAll('circle').data(data);
	
	//Enter and update
	circles.enter().append('circle')
		.attr({
			'cx': function(d){return xScale(d)},
				'cy': 30,
				'r': r,
				'fill': function(){return color || 'red'} 
		});
}
						

var oldData = [1, 2, 3];
var newData = [1, 2, 3, 4, 5];
render(oldData, 10);
render(newData, 15, 'blue');
						

jsFiddle


var render = function(data, r, color){
		//Bind Data
		var circles = svg.selectAll('circle').data(data);
		//Enter
		circles.enter().append('circle')
		
		//Update
		circles.attr({
				'cx': function(d){return xScale(d)},
					'cy': 30,
					'r': r,
					'fill': function(){return color || 'red'} 
			})
}
						

jsFiddle


var oldData = [1, 2, 3, 4, 5];
var newData = [1, 2, 3];
render(oldData, 10);
render(newData, 15, 'blue');
						

jsFiddle


var render = function(data, r, color){
		//Bind Data
		var circles = svg.selectAll('circle').data(data);

		//Enter
		circles.enter().append('circle')
		
		//Update
		circles.attr({
				'cx': function(d){return xScale(d)},
					'cy': 30,
					'r': r,
					'fill': function(){return color || 'red'} 
			})

		//Remove
		circles.exit().remove();
}
						

jsFiddle

Recap

  • Bind Data.
  • Enter and Append.
  • Update the attributes.
  • Exit and Remove.

Loading External Resources

  • d3.json(url[, callback])
  • d3.csv(url[, accessor][, callback])
  • d3.tsv(url[, accessor][, callback])

CSV


day,donut
Monday,91
Tuesday,23
Wednesday,7
Thursday,4
Friday,82
Saturday,39
Sunday,27

						


var x = "day";
var y = "donut";

var accessor = function(d) {
	d[y] = parseInt(d[y]); 
	return d;
}

d3.csv("data/data.csv", accessor, function(d) {
	console.log(d);//Array of objects [{day: "Monday", donut: 91},...]
	render(d);
});
						

jsFiddle

Working with Arrays

  • d3.min/d3.max
  • d3.reduce
  • d3.keys - lists the keys of an associative array.
  • d3.merge - merges multiple arrays into one array.
  • d3.nest - groups array elements hierarchically.
  • d3.quantile(numbers, p)
  • d3.deviation(array[, accessor]) - returns the standard deviation

jsFiddle

Reduce


[0, 1, 2, 3].reduce(function(a, b) {
	return a - b;
});//-6

[0, 1, 2, 3].reduceRight(function(a, b) {
	return a - b;
});//0
						

d3.nest


var donutData = [
	{day: 'Monday', donut: 34, variety: "plain"},
	{day: 'Tuesday', donut: 41, variety: "glazed"}
];

						


var nestedData = d3.nest()
	.key(function(d){ return d.day;})
	.entries(donutData);

[{
	key: "Monday",
	values: [
		{day: 'Monday', donut: 34, variety: "plain"}
	]},
	{
	key: "Tuesday",
	values: [
		{day: 'Tuesday', donut: 41, variety: "glazed"}
	]}
]

						


var nestedData = d3.nest()
	.key(function(d){ return d.day;})
	.key(function(d){ return d.variety;})
	.entries(donutData);

[{
		key: "Monday",
		values: [
			{ key: "plain", values: [{day: 'Monday', donut: 34, variety: "plain"}]}
		]},
	{
		key:"Tuesday",
		values: [
			{ key: "glazed", values: [{day: 'Tuesday', donut: 41, variety: "glazed"}]}
		]
	}
]
						

d3.format


d3.time.format("%Y-%m-%d"); //2015-08-26
d3.format("+,%"); //+2,400%
							
JSFiddle

d3.time.scale - constructs a linear time scale.


var xScale = d3.time.scale()
 .domain([2009-07-13T00:02, 2009-07-13T23:48])
 .rangeRound([0, width]);
 //rangeRound does the same thing as range but rounds the values to integers or begining of dates.
						
JSFiddle

d3.time.intervals - a time interval in local time.

  • d3.time.hour
  • d3.time.week
  • d3.time.monday
  • d3.time.year

Good News!

THE END

BY Aysegul Yonet / aysegul@anniecannons.com

Slides : bit.ly/sfhtml5-d3