├── 1.html ├── 10.html ├── 11.html ├── 15.html ├── 2-2.html ├── 2-3.html ├── 2.html ├── 3.html ├── 4.html ├── 5-2.html ├── 5.html ├── 6.html ├── 7-2.html ├── 7-3.html ├── 7-4.html ├── 7.html ├── 8-2.html ├── 8-3.html ├── 8.html ├── 9.html ├── README.md ├── d3.v3.min.js ├── dot.gif ├── index.html ├── main.css ├── mydata.csv ├── mydata.json ├── nations.json ├── r2d3.min.js ├── styles.css └── tell-a-story.html /1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |No Code Provided during the first part.
12 | 13 | -------------------------------------------------------------------------------- /10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |16 | var width = 500, height = 250, padding = 1; 17 | var canvas = d3.select("body") 18 | .append("svg") 19 | .attr("width", width) 20 | .attr("height", height) 21 | // Creates a request for the JSON file at the specified url, callback function gets data parameter containing json object. 22 | d3.json("mydata.json", function(data) { 23 | // workaround to get maximum value since our data is multidimensional. 24 | var max_age = d3.max(data, function(d) { return +d.age;} ); 25 | var median_age = max_age/2; 26 | /* 27 | Make use of scales, which takes an input range (data) and transform that 28 | to a range that will fit in the container. ie.. those rectangle width's should 29 | be no more than the canvas width. 30 | SEE Scales Tutorial. 31 | */ 32 | var widthScale = d3.scale.linear() 33 | .domain([0, max_age]) 34 | .range([0, width]); 35 | /* 36 | Make use of scales to transform the input array range to its color heat. 37 | The bigger value the closer to the maximum range. 38 | This example is perfect for data visualization techniques of light colors (signifying 39 | low levels) to warmer colors (signifying higher levels). 40 | */ 41 | var color = d3.scale.linear() 42 | .domain([0, max_age]) 43 | .range(["green", "grey"]); 44 | var barHeight = height / data.length; 45 | // each corresponding bar and text should be considered in one group. 46 | var bars = canvas.selectAll("g") 47 | .data(data) 48 | .enter().append("g"); 49 | bars.append("rect") 50 | // bar's color is based on the age calculated on color scale. 51 | .attr("fill", function(d){ return color(d.age); } ) 52 | // bar's width is based on the age calculated on width scale. 53 | .attr("width", function(d){ return widthScale(d.age); } ) 54 | // make use of simple scaling using number of elements in data. 55 | .attr("height", (barHeight - padding) ) 56 | // starting position of bar's y axis is based on its index in data array and barheight. 57 | .attr("y", function(d, i){ return i * barHeight; } ); 58 | bars.append("text") 59 | .attr("dy",".35em") 60 | .attr("y", function(d, i){ return ((i+1) * barHeight) - (data.length * padding + 1); } ) 61 | .attr("x", 0) 62 | .attr("fill", "white") 63 | .text(function(d) { return d.name + " " + d.age; }); 64 | }); 65 |66 | 98 | 99 | -------------------------------------------------------------------------------- /11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var width = 500; 17 | var height = 500; 18 | var canvas = d3.select("body") 19 | .append("svg") 20 | .attr("width", width) 21 | .attr("height", height); 22 | var data = [ 23 | {x: 10, y: 20}, 24 | {x: 40, y: 60}, 25 | {x: 50, y: 70} 26 | ]; 27 | var group = canvas.append("g").attr("transform", "translate(100, 100)"); 28 | var line = d3.svg.line() 29 | .x( function(d) {return d.x;} ) 30 | .y( function(d) {return d.y;} ); 31 | group.selectAll("path") 32 | .data([data]) 33 | .enter() 34 | .append("path") 35 | .attr("d", line) 36 | .attr("fill", "none") 37 | .attr("stroke", "black") 38 | .attr("stroke-width", 10); 39 |40 | 65 | 66 | -------------------------------------------------------------------------------- /15.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | // adds non-existent p element to dom body and then add text to p element. 17 | // example of method chaining. 18 | d3.select("body").append("p").text("Hi, What's up?"); 19 |20 | 24 | 25 | -------------------------------------------------------------------------------- /2-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | // debug variable in console through console.log 17 | // see link: http://stackoverflow.com/questions/4743730/what-is-console-log-and-how-do-i-use-it 18 | console.log(d3); 19 |20 | 24 | 25 | -------------------------------------------------------------------------------- /2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | // replaces text 17 | d3.select("p").text("Hello World"); 18 |19 |
This is a paragraph.
20 | 24 | 25 | -------------------------------------------------------------------------------- /3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |16 | // append svg object to the dom body and assign to variable canvas 17 | var canvas = d3.select("body") 18 | .append("svg") 19 | // specify width and height 20 | .attr("width", 500) 21 | .attr("height", 500); 22 | // create a circle and assign attributes. 23 | var circle = canvas.append("circle") 24 | .attr("cx", 250) 25 | .attr("cy", 250) 26 | .attr("r", 50) 27 | .attr("fill", "red"); 28 | // create a rectangle and assign attributes. 29 | var rect = canvas.append("rect") 30 | .attr("width", 250) 31 | .attr("height", 250); 32 | // create a line and assign attributes. 33 | var line = canvas.append("line") 34 | // x1 first horizontal position of the line 35 | .attr("x1", 0) 36 | // y1 first vertical position of the line 37 | .attr("y1", 100) 38 | // second point where the line goes to 39 | .attr("x2", 400) 40 | .attr("y2", 400) 41 | .attr("stroke", "green") 42 | .attr("stroke-width", 10); 43 |44 | 65 | 66 | -------------------------------------------------------------------------------- /4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var dataArray = [20, 40, 50]; 17 | var canvas = d3.select("body") 18 | .append("svg") 19 | .attr("width", 500) 20 | .attr("height", 500); 21 | /* 22 | Select all elements that match criteria "rectangle". In this case we don't 23 | have any rectangle yet, so it returns an empty selection with svg properties 24 | that can be bind/connected to data through data method. 25 | */ 26 | var bars = canvas.selectAll("rect") 27 | // specify where the input is coming from.. 28 | .data(dataArray) 29 | // if necessary creates the data bound elements. 30 | .enter() 31 | // for each created data-bound element append a rectangle 32 | .append("rect") 33 | // attribute width will be based on the function of the data 34 | // @link : http://stackoverflow.com/questions/18655275/javascript-closures-function-parameters 35 | // input parameter d is the data element coming from dataArray. 36 | .attr("width", function(d){ return d * 10; } ) 37 | .attr("height", 50) 38 | // attribute y wil be based on the function of the data 39 | // note that the data is dataArray = [20, 40, 50] 40 | // input parameter i corresponds to the index of element. 41 | // ie.. i = 1 for value 20, 2nd value is 40 (i=2), 3rd value is 50 (i=3) 42 | .attr("y", function(d, i){ return i * 100; } ); 43 |44 | 60 | 61 | -------------------------------------------------------------------------------- /5-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var dataArray = [5, 20, 40, 50, 60]; 17 | var width = 500; 18 | var height = 500; 19 | var max_input = d3.max(dataArray); 20 | /* 21 | Make use of scales, which takes an input range (dataArray) and transform that 22 | to a range that will fit in the container. ie.. those rectangle width's should 23 | be no more than the canvas width. 24 | */ 25 | var widthScale = d3.scale.linear() 26 | // A scale's input domain is the range of possible input data values 27 | // declaring to the scale function that the lowest possible input is 0 28 | // while the maximum possible input is max_input aka 60. 29 | .domain([0, max_input]) 30 | // A scale's output range is the range of possible output values 31 | // output would be from the lowest range : 0 to the highest range: width aka 500 32 | .range([0, width]); 33 | /* 34 | Make use of scales to transform the input array range to its color heat. 35 | The bigger value the closer to the maximum range. 36 | This example is perfect for data visualization techniques of light colors (signifying 37 | low levels) to warmer colors (signifying higher levels). 38 | */ 39 | var color = d3.scale.linear() 40 | // A scale's input domain is the range of possible input data values 41 | .domain([0, max_input]) 42 | // A scale's output range is the range of possible output values 43 | // output would be from the lowest range : yellow to the highest range: red 44 | .range(["yellow", "red"]); 45 | var canvas = d3.select("body") 46 | .append("svg") 47 | .attr("width", width) 48 | .attr("height", height); 49 | /* 50 | Notice that the width of each bar is the value of each element of the dataArray applied to widthScale 51 | so: 52 | 1st bar is widthScale(5) which is 41.6 53 | 2nd bar is widthScale(20) which is 166.6 54 | 3rd bar is widthScale(40) which is 333.3 55 | 4th bar is widthScale(50) which is 416.6 56 | last bar is widthScale(60) which is 500 57 | */ 58 | var bars = canvas.selectAll("rect") 59 | .data(dataArray) 60 | .enter() 61 | .append("rect") 62 | .attr("width", function(d){ return widthScale(d); } ) 63 | .attr("height", 50) 64 | .attr("fill", function(d){ return color(d); } ) 65 | .attr("y", function(d, i){ return i * 100; } ); 66 |67 | 91 | 92 | -------------------------------------------------------------------------------- /5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var dataArray = [20, 40, 50, 600]; 17 | var canvas = d3.select("body") 18 | .append("svg") 19 | .attr("width", 500) 20 | .attr("height", 500); 21 | /* 22 | Notice that the width of each bar is the value of each element of the dataArray multiplied by 10. 23 | so: 24 | 1st bar is 200 25 | 2nd bar is 400 26 | 3rd bar is 500 27 | 4th bar is 6000 28 | But the canvas has a maximum width of only 500! Now it looks like 3rd bar and 4th bar is the same value. 29 | For the solution to this trouble go to part 2! 30 | */ 31 | var bars = canvas.selectAll("rect") 32 | .data(dataArray) 33 | .enter() 34 | .append("rect") 35 | .attr("width", function(d){ return d * 10; } ) 36 | .attr("height", 50) 37 | .attr("y", function(d, i){ return i * 100; } ); 38 |39 | 53 | 54 | -------------------------------------------------------------------------------- /6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var dataArray = [5, 20, 40, 50, 60]; 17 | var width = 500; 18 | var height = 500; 19 | var max_input = d3.max(dataArray); 20 | // initiate tool to relate dataArray with canvas specifications. 21 | var widthScale = d3.scale.linear() 22 | // A scale's input domain is the range of possible input data values 23 | .domain([0, max_input]) 24 | // A scale's output range is the range of possible output values 25 | .range([0, width]); 26 | var color = d3.scale.linear() 27 | .domain([0, max_input]) 28 | .range(["yellow", "red"]); 29 | /* 30 | generate axis for labeling based on the values of widthScale 31 | */ 32 | var axis = d3.svg.axis() 33 | // override the default number of ticks from 10 to 5 34 | // https://github.com/mbostock/d3/wiki/SVG-Axes 35 | .ticks("5") 36 | .scale(widthScale); 37 | var canvas = d3.select("body") 38 | .append("svg") 39 | .attr("width", width) 40 | .attr("height", height) 41 | // add ability to group svg elements together. 42 | .append("g") 43 | // shift canvas to a little to the right x increase to 20 44 | .attr("transform", "translate(20, 0)") 45 | canvas.append("g") 46 | // shift this new element to a little to the bottom y increase to (500-20) 47 | // translate(x,y) 48 | .attr("transform", "translate(0, " + (height - 20) + ")") 49 | // new element is based on the axis 50 | .call(axis); 51 | var bars = canvas.selectAll("rect") 52 | .data(dataArray) 53 | .enter() 54 | .append("rect") 55 | // bar's width attribute is based on the value of the widthScale applied dataArray 56 | .attr("width", function(d){ return widthScale(d); } ) 57 | .attr("height", 50) 58 | // bar's color attribute is based on the value of the dataArray and the color scale. 59 | .attr("fill", function(d){ return color(d); } ) 60 | .attr("y", function(d, i){ return i * 100; } ); 61 |62 | 105 | 106 | -------------------------------------------------------------------------------- /7-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var data = [10, 20]; 17 | var width = 500; 18 | var height = 500; 19 | var canvas = d3.select("body") 20 | .append("svg") 21 | .attr("width", width) 22 | .attr("height", height); 23 | var circle = canvas.append("circle") 24 | .attr("cx", 50) 25 | .attr("cy", 100) 26 | .attr("r", 25); 27 | // Enter example. (more data elements than existing circle elements) 28 | // DOM elements < data elements (enter) 29 | // at this point there's one circle created already 30 | var circle = canvas.selectAll("circle") 31 | .data(data) 32 | // update any existing circles selected and color those green. 33 | .attr("fill", "green") 34 | .enter() 35 | .append("circle") 36 | .attr("cx", 50) 37 | .attr("cy", 50) 38 | .attr("r", 25) 39 | // any data-bound created circles color those to red. 40 | .attr("fill", "red"); 41 |42 | 64 | 65 | -------------------------------------------------------------------------------- /7-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var data = [10, 20]; 17 | var width = 500; 18 | var height = 500; 19 | var canvas = d3.select("body") 20 | .append("svg") 21 | .attr("width", width) 22 | .attr("height", height); 23 | var circle1 = canvas.append("circle") 24 | .attr("cx", 50) 25 | .attr("cy", 100) 26 | .attr("r", 25); 27 | var circle2 = canvas.append("circle") 28 | .attr("cx", 100) 29 | .attr("cy", 200) 30 | .attr("r", 50); 31 | // Enter example. (dom elements have the same number of data elements) 32 | // DOM elements = data elements (enter) 33 | // at this point 2 circles are already created and does not go through the enter routine 34 | var circle = canvas.selectAll("circle") 35 | .data(data) 36 | // update any existing circles selected and color those green. 37 | .attr("fill", "green") 38 | .enter() 39 | .append("circle") 40 | .attr("cx", 50) 41 | .attr("cy", 50) 42 | .attr("r", 25) 43 | // any data-bound created circles color those to red. 44 | // notice that these were not actually triggered. 45 | .attr("fill", "red"); 46 |47 | 73 | 74 | -------------------------------------------------------------------------------- /7-4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var data = [10]; 17 | var width = 500; 18 | var height = 500; 19 | var canvas = d3.select("body") 20 | .append("svg") 21 | .attr("width", width) 22 | .attr("height", height); 23 | var circle1 = canvas.append("circle") 24 | .attr("cx", 50) 25 | .attr("cy", 100) 26 | .attr("r", 25); 27 | var circle2 = canvas.append("circle") 28 | .attr("cx", 100) 29 | .attr("cy", 200) 30 | .attr("r", 50); 31 | // Exit example. (There are more dom elements than data elements) 32 | // DOM elements > data elements (exit) 33 | // two circles were selected but only one was bounded because only element in data 34 | // notice the routine still passes through exit and colored circle blue. 35 | var circle = canvas.selectAll("circle") 36 | .data(data) 37 | // update any existing circles selected and color those green. 38 | .attr("fill", "green") 39 | .exit() 40 | .attr("fill", "blue"); 41 |42 | 64 | 65 | -------------------------------------------------------------------------------- /7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
16 | var data = [10]; 17 | var width = 500; 18 | var height = 500; 19 | var canvas = d3.select("body") 20 | .append("svg") 21 | .attr("width", width) 22 | .attr("height", height); 23 | 24 | // Enter example. (more data elements than existing circle elements) 25 | // DOM elements < data elements (enter) 26 | // at this point there's no dom elements for circle yet. 27 | var circle = canvas.selectAll("circle") 28 | // bind empty selections to data 29 | .data(data) 30 | // 31 | .enter() 32 | // append a circle to each data element 33 | .append("circle") 34 | .attr("cx", 50) 35 | .attr("cy", 50) 36 | .attr("r", 25); 37 |38 | 54 | 55 | -------------------------------------------------------------------------------- /8-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
17 | /** 18 | * Script draws circle, 2 seconds after drawing the circle, move the circle to the right. 19 | * set the time moving to the right for about 1.5 secs. 20 | * Also showcases the ability to have basic animated sequences: 21 | * move right, move down, move left. 22 | */ 23 | var width = 500; 24 | var height = 500; 25 | var canvas = d3.select("body") 26 | .append("svg") 27 | .attr("width", width) 28 | .attr("height", height); 29 | var circle = canvas.append("circle") 30 | .attr("cx", 50) 31 | .attr("cy", 50) 32 | .attr("r", 25); 33 | // on circle object render 34 | circle.transition() 35 | // move circle to the right 36 | .attr("cx", 150) 37 | // set the length of time moving to 1.5 secs (1500 milliseconds) 38 | .duration(1500) 39 | // but start the transition 2 seconds after object render 40 | .delay(2000) 41 | // new sequence move a little to the bottom 42 | .transition() 43 | .attr("cy", 200) 44 | // new sequence move a little to the left. 45 | .transition() 46 | .attr("cx", 50); 47 |48 | 68 | 69 | -------------------------------------------------------------------------------- /8-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
17 | /** 18 | * Script draws circle, 2 seconds after drawing the circle, move the circle to the right. 19 | * set the time moving to the right for about 1.5 secs. 20 | * Additional this script showcases event listener "each" function 21 | * At the start of the moving animation color the circle green. 22 | * At the end of the moving animation color the circle red. 23 | */ 24 | var width = 500; 25 | var height = 500; 26 | var canvas = d3.select("body") 27 | .append("svg") 28 | .attr("width", width) 29 | .attr("height", height); 30 | var circle = canvas.append("circle") 31 | .attr("cx", 50) 32 | .attr("cy", 50) 33 | .attr("r", 25); 34 | // on circle object render 35 | circle.transition() 36 | // move circle to the right 37 | .attr("cx", 150) 38 | // set the length of time moving to 1.5 secs (1500 milliseconds) 39 | .duration(1500) 40 | // but start the transition 2 seconds after object render 41 | .delay(2000) 42 | // At the start of the moving animation color the circle green. 43 | .each("start", function() { d3.select(this).attr("fill", "green") } ) 44 | // At the end of the moving animation color the circle red. 45 | .each("end", function() { d3.select(this).attr("fill", "red") } ); 46 |47 | 66 | 67 | -------------------------------------------------------------------------------- /8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
17 | /** 18 | * Script draws circle, 2 seconds after drawing the circle, move the circle to the right. 19 | * set the time moving to the right for about 1.5 secs. 20 | */ 21 | var width = 500; 22 | var height = 500; 23 | var canvas = d3.select("body") 24 | .append("svg") 25 | .attr("width", width) 26 | .attr("height", height); 27 | var circle = canvas.append("circle") 28 | .attr("cx", 50) 29 | .attr("cy", 50) 30 | .attr("r", 25); 31 | // on circle object render 32 | circle.transition() 33 | // move circle to the right 34 | .attr("cx", 150) 35 | // set the length of time moving to 1.5 secs (1500 milliseconds) 36 | .duration(1500) 37 | // but start the transition 2 seconds after object render 38 | .delay(2000); 39 |40 | 56 | 57 | -------------------------------------------------------------------------------- /9.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
Api Reference @link https://github.com/mbostock/d3/wiki/Arrays
15 | Back to table of contents 16 | 17 |18 | // To See Output Requires google chrome or firefox (with firebug plugin) 19 | // debug variable in console through console.log 20 | // see link: http://stackoverflow.com/questions/4743730/what-is-console-log-and-how-do-i-use-it 21 | var data = [10, 20, 30, 40, 50]; 22 | // gets first element returns value : 10, additionally alters data array and removes first element 10. 23 | data.shift(); 24 | // let's reintialize the data array back to its original state. 25 | var data = [10, 20, 30, 40, 50]; 26 | // returns an array that is sorted descending (output): [50, 40, 30, 20, 10] 27 | data.sort(d3.descending); 28 | // Returns the minimum value in the given array (output): 10 29 | d3.min(data); 30 | // Returns the maximum value in the given array (output): 50 31 | d3.max(data); 32 | // Returns the minimum and maximum value in the given array (output) : [10, 50] 33 | d3.extent(data); 34 | // Returns the sum of the given array. (output) : 150 35 | d3.sum(data); 36 | // Returns the mean of the given array. (output) : 30 37 | d3.mean(data); 38 | // Returns the median of the given array. (output) : 30 39 | d3.median(data); 40 | // Randomizes the order of the specified array 41 | d3.shuffle(data); 42 |43 | 57 | 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A tutorial series covering the Javascript library D3. 2 | 3 | - Github codebase provided by chriscalip. 4 | - Based on youtube series provided by d3Vienno. 5 | - Codebase located at : https://github.com/chriscalip/d3.js.tutorials 6 | - Youtube user account link: http://www.youtube.com/user/d3Vienno 7 | - Youtube playlist located at : http://www.youtube.com/playlist?list=PL6il2r9i3BqH9PmbOf5wA5E1wOG3FT22p 8 | - See it in action at: http://chriscalip.github.io/d3.js.tutorials/index.html 9 | 10 | ## Javascript library D3 Tutorial Series: 11 | 12 | 1. Introduction 13 | Part 1 of a series of tutorials on the Javascript library D3. 14 | 2. Select and Append 15 | Part 2 of a series of tutorials on the Javascript library D3. In this part we take a look at how we can use the console to inspect elements, and also how the Select and Append methods work. 16 | 3. Basic SVG shapes 17 | Part 3 of a series of tutorials on the Javascript library D3. 18 | 4. Visualizing data 19 | Part 4 of a series of tutorials on the Javascript library D3. 20 | 5. Scales 21 | This is part 5 of a series of tutorials on the Javascript library D3. This video is a short introduction to using D3's built-in scale function. 22 | 6. Groups and axes 23 | Part 6 of a series of tutorials on the Javascript library D3. In this video we take a look at the SVG group element, and add an axis to our bar chart. 24 | 7. Enter, Update, Exit 25 | Part 7 of a series of tutorials on the Javascript library D3.js. In this video, we take a step back and revisit the actual data binding in D3. 26 | 8. Transitions 27 | Part 8 of a series of tutorials on the Javascript library D3. This video is a short introduction to transitions in D3. 28 | 9. Working With Arrays 29 | Part 9 of a series of tutorials on the Javascript library D3. In this video we explore some really basic methods concerning arrays in D3. 30 | 10. Loading External Data 31 | Part 10 of a series of tutorials on the Javascript library D3. In this video we load external JSON and CSV data. 32 | 11. Paths 33 | Part 11 of a series of tutorials on the Javascript library D3. In this video, I show you the very basics of how to create SVG paths out of data. 34 | 12. Arcs 35 | Part 12 of a series of tutorials on the Javascript library D3. In this short video I show you how arcs are created in D3. 36 | 13. The Pie Layout 37 | Part 13 of a series of tutorials on the Javascript library D3. In this video we take a look at our first D3 layout, the pie layout. 38 | 14. The Tree Layout (1/2) 39 | Part 14 of a series of tutorials on the Javascript library D3. This section is divided up in two parts. In the first video, we learn how to use the diagonal path generator. 40 | 15. The Tree Layout (2/2) 41 | Part 15 of a series of tutorials on D3. This tutorial covers how to create a tree layout. 42 | 16. Cluster, Pack & Bubble layouts 43 | Part 16 of a series of tutorials on the Javascript library D3. In this video we take a quick look at the cluster layout, devote some time to the pack layout and finish off by glimpsing at how to create a bubble chart. 44 | 17. The Histogram Layout (1/2) 45 | Part 17 of a series of tutorials on the Javascript library D3. 46 | 18. The Histogram Layout (2/2) 47 | Part 18 of a series of tutorials on the Javascript library D3. 48 | 19. The Treemap Layout 49 | Part 19 of a series of tutorials on the Javascript library. 50 | 20. Maps in D3 51 | Part 20 of a series of tutorials on the Javascript library D3. -------------------------------------------------------------------------------- /d3.v3.min.js: -------------------------------------------------------------------------------- 1 | d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function u(){}function i(){}function o(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function a(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=fa.length;r>e;++e){var u=fa[e]+t;if(u in n)return u}}function c(){}function s(){}function l(n){function t(){for(var t,r=e,u=-1,i=r.length;++ue;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function L(n){return ga(n,Ma),n}function T(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t
=o.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(Bo.map,e,0),0)},i.key=function(n){return o.push(n),i},i.sortKeys=function(n){return a[o.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},Bo.set=function(n){var t=new i;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(i,{has:function(n){return sa+n in this},add:function(n){return this[sa+n]=!0,n},remove:function(n){return n=sa+n,n in this&&delete this[n]},values:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===la&&n.call(this,t.substring(1))}}),Bo.behavior={},Bo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Bo.event=null,Bo.requote=function(n){return n.replace(ha,"\\$&")};var ha=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ga={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},pa=function(n,t){return t.querySelector(n)},va=function(n,t){return t.querySelectorAll(n)},da=Ko[a(Ko,"matchesSelector")],ma=function(n,t){return da.call(n,t)};"function"==typeof Sizzle&&(pa=function(n,t){return Sizzle(n,t)[0]||null},va=function(n,t){return Sizzle.uniqueSort(Sizzle(n,t))},ma=Sizzle.matchesSelector),Bo.selection=function(){return _a};var ya=Bo.selection.prototype=[];ya.select=function(n){var t,e,r,u,i=[];n=v(n);for(var o=-1,a=this.length;++o=0&&(e=n.substring(0,t),n=n.substring(t+1)),xa.hasOwnProperty(e)?{space:xa[e],local:n}:n}},ya.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Bo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(m(t,n[t]));return this}return this.each(m(n,t))},ya.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=M(n)).length,u=-1;if(t=e.classList){for(;++u =0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=es.get(e)||ts,r=rs.get(r)||dt,Dr(r(e.apply(null,Wo.call(arguments,1))))},Bo.interpolateHcl=Br,Bo.interpolateHsl=Wr,Bo.interpolateLab=Jr,Bo.interpolateRound=Gr,Bo.transform=function(n){var t=Go.createElementNS(Bo.ns.prefix.svg,"g");return(Bo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Kr(e?e.matrix:us)})(n)},Kr.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var us={a:1,b:0,c:0,d:1,e:0,f:0};Bo.interpolateTransform=eu,Bo.layout={},Bo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e Source: Tom Carden, Gapminder.
63 |
64 | This is a recreation in D3 of Gapminder’s Wealth & Health of Nations, made famous by Hans Rosling’s memorable 2006 TED talk. It shows the dynamic fluctuation in per-capita income (x), life expectancy (y) and population (radius) of 180 nations over the last 209 years. Nations are colored by geographic region; mouseover to read their names.
65 |
66 | As Tom Carden noted, there’s a surprising amount of work that goes into making something look simple. For one, data collected in recent years is consistent, while data prior to 1950 is sparse; although potentially misleading, these visualizations use linear interpolation for missing data points. The lookup for the two interpolation values at each frame is accelerated using bisection of sorted arrays per dimension.
67 |
68 | Interested to see how this chart was implemented? View source! Want a fun project? Try adding a Voronoi overlay (as in this airport diagram) to improve mouseover interaction on small targets. Or try a static version, using trails instead of motion.
69 |
70 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=Ar()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=vt(a),M=vt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.xt;++t)(r=d[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=m[t],"number"==typeof r.source&&(r.source=d[r.source]),"number"==typeof r.target&&(r.target=d[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=d[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,m[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,m[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,d[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Bo.behavior.drag().origin(dt).on("dragstart.force",cu).on("drag.force",t).on("dragend.force",su)),arguments.length?(this.on("mouseover.force",lu).on("mouseout.force",fu).call(e),void 0):e},Bo.rebind(a,c,"on")};var is=20,os=1;Bo.layout.hierarchy=function(){function n(t,o,a){var c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(s=c.length)){for(var s,l,f=-1,h=t.children=new Array(s),g=0,p=o+1;++fg;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=dt,e=_u,r=bu,u=Mu,i=yu,o=xu;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:cs.get(t)||_u,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:ss.get(t)||bu,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var cs=Bo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(wu),i=n.map(Su),o=Bo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Bo.range(n.length).reverse()},"default":_u}),ss=Bo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:bu});Bo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i
10 |
16 | Table of contents:
19 |
20 |
113 |
and also how the Select and Append methods work.
26 | :part3
27 | :part2
28 | Select and Append
29 |
devote some time to the pack layout
and finish off by glimpsing at how to create a bubble chart.
91 | The Wealth & Health of Nations
57 |
58 |
59 |
60 |
61 |
62 |