Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Strata 2013 D3 Tutorial

Scott Murray
February 26, 2013

Strata 2013 D3 Tutorial

A tutorial with Jérôme Cukier introducing d3.js at the Strata Conference in Santa Clara. Code examples and PDF slides here: https://github.com/alignedleft/strata-d3-tutorial

Scott Murray

February 26, 2013
Tweet

More Decks by Scott Murray

Other Decks in Programming

Transcript

  1. 10 20 45 6 D3.js Tutorial Strata Conference February 26,

    2013 Santa Clara github.com/alignedleft/strata-d3-tutorial Download the code examples!
  2. 10 20 45 6 Jérôme Cukier Independent data visualizer Scott

    Murray Assistant Professor, Design University of San Francisco github.com/alignedleft/strata-d3-tutorial Download the code examples!
  3. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>D3 Page Template</title>

    <script type="text/javascript" src="d3.v3.js"></script> </head> <body> <script type="text/javascript"> // Your beautiful D3 code can go here </script> </body> </html>
  4. HTML CSS JS SVG DOM Hypertext Markup Language Cascading Style

    Sheets JavaScript Scalable Vector Graphics The Document Object Model all of the above == web standards
  5. HTML CSS JS SVG DOM Hypertext Markup Language Cascading Style

    Sheets JavaScript Scalable Vector Graphics The Document Object Model Learning D3 is a process of “learning the web”
  6. What you need • A text editor, • The d3

    library, • Files for your code, • Recommended: a web server, • A browser.
  7. A text editor • There are a few options out

    there: textMate, eclipse / aptana, sublime text 2… • What you really need is an editor with syntax highlighting. Constructs with d3 can become very intricate. • Personally, I like sublime text 2.
  8. Files you need • The d3 library : get it

    at http://d3js.org • Or link to it: http://d3js.org/d3. v3.min.js
  9. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> <title>My project</title> <script type="text/javascript" src="../d3.v3.js"></script> <link href="style.css" rel="stylesheet"> </head> <body> <div id="chart"></div> <script type="text/javascript" src="script.js"></script> </body> </html>
  10. A template for d3 <!DOCTYPE html> Start by specifying the

    doctype, to be in HTML5 mode (less suprises).
  11. A template for d3 <!DOCTYPE html> <html> </html> An HTML

    tag is not required, but makes things more legible for people.
  12. A template for d3 <!DOCTYPE html> <html> <head> </head> <body>

    </body> </html> Likewise, head and body tags are not required, but make things easier to read.
  13. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> </head> <body> </body> </html> It's better to specify a content type, this will allow you to use non-ascii characters with confidence.
  14. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> <title>My project</title> </head> <body> </body> </html> You may name your project here.
  15. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> <title>My project</title> <script type="text/javascript" src="http://d3js.org/d3.v3.js"></script> </head> <body> </body> </html> That's where you link to the d3 library. Here I am assuming it is in a folder one level up from the code. Alternatively, you can use http://d3js.org/d3.v2.min.js.
  16. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> <title>My project</title> <script type="text/javascript" src="../d3.v2.js"></script> <link href="style.css" rel="stylesheet"> </head> <body> </body> </html> Optionally, you can link to a stylesheet like so. Or specify style inside a <style> element here.
  17. <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title>My project</title> <script

    type="text/javascript" src="http://d3js.org/d3.v3.js"></script> <link href="style.css" rel="stylesheet"> </head> <body> <div id="chart"></div> </body> </html> Inside the body, we create a <div> element which will hold the vis.
  18. <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <title>My project</title> <script

    type="text/javascript" src="http://d3js.org/d3.v3.js"></script> <link href="style.css" rel="stylesheet"> </head> <body> <div id="chart"></div> <script type="text/javascript" src="script.js"></script> </body> </html> Finally, we link to a script file containing our actual javascript code. Alternatively, we may write our code here inside a <script> element.
  19. A template for d3 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type"

    content="text/html;charset=utf-8"> <title>My project</title> <script type="text/javascript" src="http://d3js.org/d3.v3.js"></script> <link href="style.css" rel="stylesheet"> </head> <body> <div id="chart"></div> <script type="text/javascript" src="script.js"></script> </body> </html>
  20. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") .append("svg") .attr("width",w).attr("height",h); svg .append("text") .text("hello world!").attr("x",100).attr("y",100);
  21. Now let's look at a sample js file. var w=960,h=500;

    Simple variables to size the vis. Those numbers are chosen because they work well with Mike Bostock's http://bl.ocks.org, a simple viewer for code examples hosted on GitHub Gist.
  22. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") Now we are going to create an SVG container. It will be a child of the div named #chart, which we created earlier.
  23. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") .append("svg") This creates the svg element per se.
  24. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") .append("svg") .attr("width",w).attr("height",h); And this last line gives an explicit width and height to the svg element. This is desired in Firefox (in chrome/safari, the svg just resizes as needed) and generally more proper.
  25. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") .append("svg") .attr("width",w).attr("height",h); svg .append("text") Now that we have an SVG container, we can just add any kind of SVG element to it. So let's start with text.
  26. Now let's look at a sample js file. var w=960,h=500;

    var svg=d3.select("#chart") .append("svg") .attr("width",w).attr("height",h); svg .append("text") .text("hello world!").attr("x",100).attr("y",100); This last line specifies characteristics of the element we've just added.
  27. A web server • You can view most d3 visualizations

    locally, simply by opening an html file in a browser. • But if your visualization is reading data from files or from a database (XMLHttpRequest), then you need to publish it on a web server to test it. • There are many options: EasyPHP (windows), Mac OS X Server, MAMP (Mac OS X)
  28. The console D3-capable browsers come with a "console" that helps

    tremendously in web development. Chrome: Ctrl+j (⌥ ⌘+j Mac) Firefox: Ctrl+Shift+k (⌥ ⌘+k Mac) Safari: Ctrl+Alt+c (⌥ ⌘+c Mac)
  29. The console D3-capable browsers come with a "console" that helps

    tremendously in web development. Chrome: Ctrl+j (⌥ ⌘+j Mac) Firefox: Ctrl+Shift+k (⌥ ⌘+k Mac) Safari: Ctrl+Alt+c (⌥ ⌘+c Mac) Among other things, the console lets you see the value of variables, and let you enter some commands directly, without having to put them in a file.
  30. Exercise: Create this web page by typing D3 code into

    the console. Strata Tutorial D3 can be used to generate new DOM elements. Get it from d3js.org! h1 p a
  31. Where's the data? So far we've been adding elements one

    by one. Let's put the data in data visualization!
  32. Introducting selectAll selectAll allows you to select all elements that

    correspond to a condition, and manipulate them all at once. d3.selectAll("p").style("font-weight","bold");
  33. Values based on data Instead of asking d3 to do

    the same thing unconditionally, we can ask it to update certain characteristics of the items based on data. var fs= ["10px","20px","30px"]; d3.selectAll("p") .data(fs) .style("font-size",function(d) {return d;})
  34. Side note: who is d? Here I wrote: .style("font-size",function(d) {return

    d;}) What is d? Here, I'm assigning to the "font-size" style a value which is not static, but dynamic. To compute that value, we retrieve it from the data using functions. The first argument of these functions is the data item. The name of that argument is arbitrary, d is a convention. Here, we just return the value we've read, but inside the function there can be any kind of transformation.
  35. Side note: can I use existing functions instead of retyping

    them each time? YES!! For instance, String(123) converts a number into a string. Conveniently, it also converts a string into a string. In most cases, String(d) is equivalent to function(d) {return d;} So instead of .style("font-size",function(d) {return d;}) We can write: .style("font-size",String)
  36. Creating new elements from data With selectAll, we've seen we

    can manipulate existing elements. With selectAll then data, we've seen that we can manipulate existing elements dynamically, using data. Now what if there are no existing elements?
  37. Working with new elements … .html(function(d) …).style(…) And after this,

    you can chain methods that will update characteristics of the elements as above. elements Do stuff data
  38. Side note: why select before selectAll? In previous examples (before

    enter) we could write directly: d3.selectAll("p"). This will not work when creating new elements. Why? Because new elements have to be created somewhere! So, for this construct to work, you have to select a container first, ie d3.select("body").selectAll("p").data(…).enter()…
  39. Side note: what happens if the data changes? So you

    created a bunch of elements dynamically, using data. Then, for some reason, the data changes. What happens to your elements?
  40. Side note: what happens if the data changes? So you

    created a bunch of elements dynamically, using data. Then, for some reason, the data changes. What happens to your elements? Nothing, unless you also change their attributes. (BTW – this is different from protovis, the ancestor of d3)
  41. How do I remove elements? The remove() method can be

    attached to any selection. d3.selectAll("p").remove() Effectively deletes all paragraphs found in the document.
  42. How do I remove some elements? OK so let's suppose

    my data changes and I have fewer data points than I have created elements. What happens if I want to manipulate my elements? d3.selectAll("p").data(["hello world"]).html(String);
  43. Working with a smaller dataset Only the first element changes.

    The other two are left untouched. elements data Do stuff
  44. How do I remove some elements? In order to capture

    the elements which are no longer matched by a data point, we can use the method exit(): d3.selectAll("p").data(["hello world"]).exit() // do stuff to those, often .remove() ;
  45. Exercise: Create four span elements with the following text and

    colors. darkmagenta teal rosybrown midnightblue span HINT: var colors = [“darkmagenta ”, “teal “, “rosybrown “, “midnightblue “]
  46. SVG

  47. Calculations from data .attr("y", function(d) { return h - (d

    * 4); }) .attr("height", function(d) { return d * 4;}) What if the size of the chart changes? Will that work if the shape of the data changes?
  48. Introducing scales Scales are a family of d3 methods for

    simple algebraic transformations. Here's one var myScale=d3.scale.linear().domain([0,25]) .range([0,100]); myScale(0) // 0 myScale(25) // 100 myScale(10) // 40
  49. Advantages of a scale • it's very easy to change

    its parameters. • If you are changing the size of the elements… without a scale you'd have to change every possible instance of the hard coded calculations. .attr("y", function(d) { return h - (d * 4); }) .attr("height", function(d) { return d * 5;}) This is very error-prone.
  50. Using scales can lead to nice, compact yet legible code

    var y=d3.scale.linear().range([0,100]).domain([0,25]); …. .attr("y",y)
  51. Using scales can lead to nice, compact yet legible code

    var y=d3.scale.linear().range([0,100]).domain([0,25]); …. .attr("y",y) There are several other types of scales: – log – sqrt – power
  52. There are lots of other niceties that come with scales

    y.domain(d3.extent(dataset)) // computes bounds of the scale automatically y.domain([0,d3.max(dataset)]) // another way of determining the domain automatically y.clamp([true]) // values outside the bounds of the domain get the min or max value of the range. y.invert() // the mapping in the reverse direction.
  53. So… What's the sweet spot between using scales (which means

    having to write scales in full once) and writing out functions quickly that do equivalent things?
  54. Ordinal scales So far we have seen quantitative scales, which

    transform a number into another number. But there are also ordinal scales which turn associate a list of items with a value.
  55. Interesting ordinal scales: color palettes! In d3, color palettes are

    really ordinal scales, since they associate discrete values with values. There are a few built in ones: d3.scale.category10() //d3.scale.category10()("a") //
  56. Two broad types of interaction with d3. • Forms And

    it doesn’t have to be a full-fledged form: controls like drop- down menus, tick boxes, sliders etc. • Interaction on elements of the chart proper SVG or HTML elements: clicking, moving the cursor in or out, etc.
  57. Good news! While they may look different, they both really

    work the same. And it’s not super complicated.
  58. Here's an example var w=960,h=500,flag=0; var svg=d3.select("#chart").append("svg").attr("width",w).attr("height",h); var myRect=svg .append(

    "rect").attr({x:100,y:100,width:100,height:100}) .style("fill","steelblue"); myRect.on("click",function() { flag=1-flag; myRect.style("fill", flag?"darkorange":"steelblue"); })
  59. var w=960,h=500,flag=0; var svg=d3.select("#chart").append("svg").attr("width",w).attr("height",h); var myRect=svg .append( "rect").attr({x:100,y:100,width:100,height:100}) .style("fill","steelblue"); myRect.on("click",function()

    { flag=1-flag; myRect.style("fill", flag?"darkorange":"steelblue"); }) And now for the win: we just toggle the value of flag (0 becomes 1 and vice versa) then we style our rectangle according to that value : orange if flag is 1, else blue.
  60. on + event + function That's the general gist of

    it. There are few events you should know. "click" is the workhorse of events. Click anything (a rectangle, text, a shape) and things happen. "mouseover", "mouseout" are other good ones. Great for highlighting stuff and all. "change" is great for forms (the value of the form changed).
  61. Going further: events on groups By setting an event listener

    on a "g" element, it will be triggered by any interaction on any element of that group.
  62. Going further: events and data Can the function access the

    underlying data of the element? Of course! If the element has data tied to it, you can do myElement.on("click",function(d) { // … operations on data … })
  63. Going further: playing with forms Usually the point of form

    controls is to access the value selected by the user. So you'll often have something like: myControl.on("change",function() { doStuff(this.value); }) this.value will store the value of the control.
  64. Let's see how it looks like in the code <body>

    <select id="projection-menu"></select> <input type="range" id="gores" step="1" min="1" max="12" value="3"> The two controls are created there: - drop-down (select) - slider (input with type "range")
  65. Let's see how it looks like in the code d3.select("#gores").on("change",

    function() { gores(); … }); … function gores() { var n = +d3.select("#gores").property("value"); … } When the slider value changes, the "change" event is triggered and so the gores() function is called. Then, this function does stuff depending on the position of the slider, which is obtained thusly: by looking up the property "value" of the slider.
  66. Let's see how it looks like in the code menu.selectAll("option")

    .data(options) .enter().append("option") .text(function(d) { return d.name; }); var menu = d3.select("#projection-menu") .on("change", change); function change() { … update(options[this.selectedIndex]); } Here, the menu is going to be populated with data. Then, just as before, a change event will trigger a function : change. This function will call another one based on which item is selected in the drop down menu.
  67. Let's see how it looks like in the code var

    projection = svg.selectAll(".axis text,.background path,.foreground path") .on("mouseover", mouseover) .on("mouseout", mouseout); function mouseover(d) { svg.classed("active", true); projection.classed("inactive", function(p) { return p !== d; }); projection.filter(function(p) { return p === d; }).each(moveToFront); } function mouseout(d) { svg.classed("active", false); projection.classed("inactive", false); } function moveToFront() { this.parentNode.appendChild(this); } This is our on - event – function This function is called upon mouseover. It uses the underlying value of the line (d). The formatting is done by assigning a CSS class. And this function is called upon mouseout, it essentially resets the other one.
  68. Scott Murray @alignedleft alignedleft.com An Introduction to Designing With D3

    Scott Murray Interactive Data Visualization for the Web Jérôme Cukier @jcukier jeromecukier.net Book signing today! 5:30 pm O’Reilly Booth Expo Hall