Notes from reading Interactive Data Visualization for the Web, 2nd Edition via O'Reilly's Safari subscription. I did the 10-day trial and I'll buy the book when it comes out.

Geomapping Libraries A JavaScript-and-Python combo for gorgeous, entirely vector-based mapping by Gregor Aisch with must-see demos. Please go look at them now. I promise you’ve never seen online maps this beautiful.

Leaflet - a JavaScript library for interactive maps A library for tiled maps, designed for smooth interaction on both desktop and mobile devices. It includes some support for displaying data layers of SVG on top of the map tiles. (See Mike’s demo “Using D3 with Leaflet”.)

Chapter 4: Setup

  • Setup
  • Using Google Web Starter Kit for a server

Chapter 5: Data

Within the scope of D3 and browser-based visualization, however, we will limit ourselves to text-based data.

  • You get columns from a CSV for free, added as an object with an array of the column values
  • Everything is a string, so roll your own converter ``` var rowConverter = function(d) { return { Food: d.Food, //No conversion Deliciousness: parseFloat(d.Deliciousness) }; }

d3.csv("food.csv", rowConverter, function(data) { console.log(data); }); ```

  • Use a global variable and/or error to check for data ``` var dataset; //Declare global variable, initially empty (undefined)

d3.csv("food.csv", function(data) { dataset = data; //Once loaded, copy to dataset. generateVis(); //Then call other functions that hideLoadingMsg(); //depend on data being present. });

var useTheDataLater = function() { //Assuming useTheDataLater() is called sometime after //d3.csv() has successfully loaded in the data, //then the global dataset would be accessible here. }; ```

  var dataset;

d3.csv("food.csv", function(error, data) {

    if (error) {  //If error is not null, something went wrong.
        console.log(error);  //Log the error.
    } else {      //If no error, the file loaded correctly. Yay!
        console.log(data);   //Log the data.

        //Include other code to execute after successful file load here
        dataset = data;


  • enter() is how you bind to elements that don’t yet exist

    To create new, data-bound elements, you must use enter(). This method looks at the current DOM selection, and then at the data being handed to it. If there are more data values than corresponding DOM elements, then enter() creates a new placeholder element on which you can work your magic. It then hands off a reference to this new placeholder to the next step in the chain.

  • Styling by value .style("color", function(d) { if (d > 15) { //Threshold of 15 return "red"; } else { return "black"; } });

Chapter 6: Drawing with Data

  • Basics are the same from v3

Chapter 7: Scales

“Scales are functions that map from an input domain to an output range.”

A scale’s input domain is the range of possible input data values. Given the preceding apples data, appropriate input domains would be either 100 and 500 (the minimum and maximum values of the dataset) or 0 and 500.

A scale’s output range is the range of possible output values, commonly used as display values in pixel units. The output range is completely up to you, as the information designer. If you decide the shortest apple bar will be 10 pixels tall, and the tallest will be 350 pixels tall, then you could set an output range of 10 and 350.

In all seriousness, to avoid ambiguity with dates, I strongly recommend using four-digit years and %Y. Use your spreadsheet to reformat date values before exporting to CSV for D3.

Chapter 8: Axes * Seems pretty much the same from v3 * I love the grid lines in the prettier example 09_time_axis_prettier [image:3F8EFE7B-7EB2-46F7-8E2C-02BDF5076E7F-6335-000021D1CE9388D0/Screenshot 2017-07-12 19.18.34.png]

Chapter 9: Updates, Transitions, and Motion

Ordinal scales are typically used for ordinal data, typically categories with some inherent order to them, such as: * grade B, grade A, grade AA * freshman, sophomore, junior, senior * strongly dislike, dislike, neutral, like, strongly like

  • round: true helps avoid fuzzy svgs

.transition() Specifically, add this link in the chain below where your selection is made, and above where any attribute changes are applied:

Chapter 10: Interactivity

Chapter 11: Using Paths

  • Generating multiple paths from the same data is rad

Chapter 12: Selections

  • Deeeeep dive into console.log
  • Filtering by data values seems very useful"body").selectAll("p") .data(dataset) .enter() .append("p") .text(function(d) { return "I can count up to " + d; }) .filter(function(d) { //Filter current selection of all paragraphs return d > 15; //Returns true only if d > 15 }) //New selection of filtered elements is handed off here .style("color", "red"); //Applies only to elements in the filtered selection


  var allParas ="body").selectAll("p")
    .text(function(d) {
        return "I can count up to " + d;

var redParas = allParas.filter(function(d) {
        return d > 15;
    .style("color", "red");

  • Slider functionality! 03_slider.html ``` //On change, update styling"input") .on("change", function() {

    var threshold =;
        .attr("fill", function(d) {
            return "rgb(0, 0, " + (d.value * 10) + ")";
        .filter(function(d) {
            return d.value <= threshold;
        .attr("fill", "red");

    }); ```

  • Selection via radios 04_radios.html

  • Based on area! 05_combinations.html

Fortunately, we can use each() to run an arbitrary function once for each element in a selection. each() takes whatever selection it’s given and calls the specified function once for each item in the selection. selection.each(function(d, i) { //The 'this' context is now set to //the element on which you’re acting. // //Do something with 'this', d, and/or i here. });

or like selection.each(zoomAndEnhance);

Chapter 13: Layouts

Contrary to what the name implies, D3 layouts do not, in fact, lay anything out for you on the screen.

  • Pie and donuts come from built-in functions
  • Same with stacked charts stack()
  • Force Layouts > Force-directed layouts are so-called because they use simulations of physical forces to arrange elements on the screen.
  • d3-force/ at master · d3/d3-force · GitHub > Physics simulations use the word “tick” to refer to the passage of some amount of time, like the ticking second hand of a clock.

Chapter 14: Geomapping

It’s important to note that longitude is always listed first. Despite the cultural bias toward lat/lon, GeoJSON is a lon/lat world.

Get Lat+Lon is a great resource by Michal Migurski for double-checking coordinate values. Keep it open in a browser tab whenever you’re working on geomaps. You will reference it often. *

d3.geoPath() is a total lifesaver of a function. It does all the dirty work of translating that mess of GeoJSON coordinates into even messier messes of SVG path codes. All hail d3.geoPath()!

A projection is an algorithm of compromise; it is the method by which 3D space is “projected” onto a 2D plane.

If you prefer more concise code, you can specify the projection within the constructor function, like so: var path = d3.geoPath(projection);

Geocoding Resources

Shapefile Resources

Chapter 15: Exporting

  • Good info, I’ll remember Sketch as an option for exporting

Chapter 16: Project Walk-through

  • Multiple charts
  • Touches on scoping the various but I think that this can be handled with wrapping functions

Appendix A. Case Studies

  • I want to replicate the controls in
  • Shirley Wu’s work is amazing Shirley Xueyang Wu

Extra Credit

// add viewBox and preserveAspectRatio properties, // and call resize so that svg resizes on inital page load svg.attr("viewBox", "0 0 " + width + " " + height) .attr("preserveAspectRatio", "xMinYMid") .call(resize);

// to register multiple listeners for same event type, // you need to add namespace, i.e., '' // necessary if you call invoke this function for multiple svgs // api docs:"resize." + container.attr("id"), resize);

// get width of container and resize svg to fit it function resize() { var targetWidth = parseInt("width")); svg.attr("width", targetWidth); svg.attr("height", Math.round(targetWidth / aspect)); } } ```


2,188 0 10