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

Building JavaScript Visualizations Part 2

Building JavaScript Visualizations Part 2

Stephen Thomas

October 18, 2014
Tweet

More Decks by Stephen Thomas

Other Decks in Technology

Transcript

  1. Building JavaScript Visualizations
    Part 2: You Might Want D3.js
    Stephen Thomas ([email protected])

    View Slide

  2. Network Graph
    Easy with sigmajs but limited

    View Slide

  3. D3.js Gives Us Full Control

    View Slide

  4. D3.js Philosophy
    • D3.js is not really a visualization library; it does
    not draw visualizations
    • D3 = "Data Driven Documents"; it primarily
    associates data with DOM elements and
    manages the results
    • D3.js also provides tools that you can use to
    draw visualizations

    View Slide

  5. Buying a House with sigmajs

    View Slide

  6. Buying a House with D3.js

    View Slide

  7. HTML Skeleton




    Jazz Connections









    View Slide

  8. Data in JSON Format
    [ {
    artist: "Miles Davis",
    title: "Kind of Blue",
    itunes: "https://itunes.apple.com/...",
    cover: "http://a4.mzstatic.com/...",
    color: "#47738C",
    text: "#0A0606",
    musicians: [ "Cannonball Adderley", "Paul Chambers", "Jimmy Cobb",
    "John Coltrane", "Miles Davis", "Bill Evans" ]
    },{
    artist: "John Coltrane",
    title: "A Love Supreme",
    itunes: "https://itunes.apple.com/...",
    cover: "http://a5.mzstatic.com/...",
    color: "#747C7B",
    text: "#343437",
    musicians: [ "John Coltrane", "Jimmy Garrison", "Elvin Jones", "McCoy Tyner" ]
    },
    // Data set continues...

    View Slide

  9. Retrieve via AJAX
    d3.json('data.json', function(error, data) {
    // data contains the JavaScript object
    // (in this case an array)

    View Slide

  10. Create an Array of Nodes
    var nodes = data.map(function(datum, idx, list) {
    var node = {};
    node.title = datum.title;
    node.subtitle = datum.artist;
    node.image = datum.cover;
    node.url = datum.itunes;
    node.color = datum.color;
    node.text = datum.text;
    node.links = datum.musicians.slice(0);
    var radius = 0.4 * Math.min(height,width);
    var theta = 2 * Math.PI * idx / list.length;
    node.x = (width/2) + radius*Math.sin(theta);
    node.y = (height/2) + radius*Math.cos(theta);
    return node;
    });

    View Slide

  11. Find All Links Between Nodes
    var links = [];
    data.forEach(function(srcNode, srcIdx, srcList) {
    srcNode.musicians.forEach(function(srcLink) {
    for (var tgtIdx = srcIdx + 1; tgtIdx < srcList.length; tgtIdx++) {
    var tgtNode = srcList[tgtIdx];
    if (tgtNode.musicians.some(function(tgtLink){
    return tgtLink === srcLink;
    })) {
    links.push({
    source: srcIdx,
    target: tgtIdx,
    link: srcLink
    });
    }
    }
    });
    });

    View Slide

  12. Eliminate Duplicate Links
    var edges = [];
    links.forEach(function(link) {
    var existingEdge = false;
    for (var idx = 0; idx < edges.length; idx++) {
    if ((link.source === edges[idx].source) && (link.target === edges[idx].target)) {
    existingEdge = edges[idx];
    break;
    }
    }
    if (existingEdge) {
    existingEdge.links.push(link.link);
    } else {
    edges.push({
    source: link.source,
    target: link.target,
    links: [link.link]
    });
    }
    });

    View Slide

  13. DOM Selection & Manipulation
    Creating the Stage
    var graph = d3.select('#graph');
    var notes = d3.select('#notes');
    var svg = graph.append('svg')
    .attr('width', width)
    .attr('height', height);

    View Slide

  14. Draw the Nodes - First Attempt
    Although the following code does add 25 circles
    to the page, it's not taking advantage of D3.js
    nodes.forEach(function(node) {
    svg.append("circle");
    });
    There's a better approach...

    View Slide

  15. Draw the Nodes - Associating
    Data with DOM Elements
    var selection = svg.selectAll("circle")
    .data(nodes);
    This looks really weird ... at first ...

    View Slide

  16. What if the Circles Existed?
    svg.selectAll("circle").data(nodes);

    View Slide

  17. Only Some Circles?
    svg.selectAll("circle").data(nodes);

    View Slide

  18. Even No Circles?
    svg.selectAll("circle").data(nodes);

    View Slide

  19. Draw the Missing Circles
    var selection = svg.selectAll("circle")
    .data(nodes);
    selection.enter().append("circle");
    Or, more concisely
    var nodeSelection = svg.selectAll("circle")
    .data(nodes)
    .enter().append("circle");

    View Slide

  20. Draw the Edges
    var edgeSelection = svg.selectAll("line")
    .data(edges)
    .enter().append("line");
    (Actually, we should draw the edges before the
    nodes.)

    View Slide

  21. Position the Elements
    nodeSelection
    .attr('r', 10)
    .attr('cx', function(dataValue) { return dataValue.x; })
    .attr('cy', function(dataValue) { return dataValue.y; });
    edgeSelection
    .attr('x1', function(d) { return nodes[d.source].x; })
    .attr('y1', function(d) { return nodes[d.source].y; })
    .attr('x2', function(d) { return nodes[d.target].x; })
    .attr('y2', function(d) { return nodes[d.target].y; });

    View Slide

  22. Houston,
    We Have a Graph

    View Slide

  23. Force Direction
    Algorithmic approach to positioning graph
    elements
    • Simulates a physical world with forces such as
    gravity and electromagnetism
    • Elements given properties that correspond to
    mass and charge
    • Positions elements in reaction to simulated
    physical forces

    View Slide

  24. D3.js Force Layout
    Initialize the layout
    var force = d3.layout.force()
    .size([width, height])
    .nodes(nodes)
    .links(edges)
    .linkDistance(40)
    .force(-500);

    View Slide

  25. D3.js Force Layout
    Update the positions
    force.on('tick', function() {
    nodeSelection
    .attr('cx', function(d) { return d.x; })
    .attr('cy', function(d) { return d.y; });
    edgeSelection
    .attr('x1', function(d) { return d.source.x; })
    .attr('y1', function(d) { return d.source.y; })
    .attr('x2', function(d) { return d.target.x; })
    .attr('y2', function(d) { return d.target.y; });
    });

    View Slide

  26. D3.js Force Layout
    force.start();

    View Slide

  27. Interactivity
    D3.js event handling
    nodeSelection.on('click', function(d) {
    d3.select(this)
    .classed('selected', true)
    .attr('r', 1.5*nodeRadius);
    });

    View Slide

  28. Animations
    D3.js transitions
    nodeSelection.on('click', function(d) {
    d3.select(this)
    .classed('selected', true)
    .transition()
    .attr('r', 1.5*nodeRadius);
    });

    View Slide

  29. More Information
    Source at http://bl.ocks.org/sathomas/
    a7b0062211af69981ff3
    Web Site: jsDataV.is
    Book: Data Visualization with JavaScript
    (No Starch Press, available early 2015)
    Full content available for free on web site

    View Slide