Interactive Data Visualizations

examples and creating your own

Mike Stubna, PhD
12 March 2014

Notes from the Data Philly meetup
Go back to the main page

Data Visualizations

From: National Geographic

From: National Geographic


Jonathan Corum, who designs visualizations for the NY Times, says to know your audience and design for them

potential design ranges:

From the NY Times: Where poor and uninsured Americans live

From the NY Times: 512 paths to the White House

From the NY Times: Keplers tally of planets


Jonathan Corum says about his development thought process:

When he reran his script, he discovered new things about the data set, because of the visualization

Common themes from these interactive data visualizations

Where they could be used


how much is …

too much?

Is interactivity always helpful?

Charles Minard's map of Napoleon's Russian campaign of 1812

Are animations necessary?


As data scientists, we are very comfortable using Python, MATLAB, R, etc., for

It would be ideal to have a similarly flexible framework for rapidly iterating on developing data visualizations

Why build visualizations for the web?

Basic components of a web document

What is D3?

Advantages of D3


Basic graphical elements: SVG

    <svg width="300" height="200">
      <rect x="50" y="50" width="200" height="100" fill="orange" stroke="navy" stroke-width="10"/>
    <svg width="300" height="200">
      <g transform="translate(100,50) rotate(30) scale(0.5)">
        <rect x="50" y="50" width="100" height="100" fill="none" stroke="navy" stroke-width="10"/>
        <rect x="200" y="50" width="100" height="100" fill="none" stroke="navy" stroke-width="10"/>
    <svg width="300" height="200">
      <ellipse cx="150" cy="100" rx="60" ry="30" fill="none" stroke="navy" stroke-width="5"  />

How to build visualizations for the web

Higher level languages


compiles to javascript but has


compiles to css but permits


From Google: Google public data explorer

Ex 1: interactivity as another dimension

Ex 1: code


        <link href="/stylesheets/all.css" media="screen" rel="stylesheet" type="text/css">
        <script src="/javascripts/jquery-2.1.0.js" type="text/javascript"></script>
        <script src="/javascripts/d3.js" type="text/javascript"></script>
        <script src="/javascripts/d3.tip.js" type="text/javascript"></script>
        <script src="/javascripts/life_expectancy_fertility_rate_data.js" type="text/javascript"></script>
        <script src="/javascripts/example_1.js" type="text/javascript"></script>
      <body class="example_1">
        <div id="example" class="data_viz_example"></div>


    constructor: ->
      @margin = {top: 20, right: 20, bottom: 30, left: 50}
      @width = 960 - @margin.left - @margin.right
      @height = 500 - - @margin.bottom
      # the data
      @countries =
      @years =

      # initialize graph
      slider = $('#slider')

    add_graph: ->
      # create the view
      @view ='#example').append('svg')
        .attr('width', @width + @margin.left + @margin.right)
        .attr('height', @height + + @margin.bottom)
        .attr('transform', "translate(#{@margin.left},#{})")
      # add the circles
      @circles = @view
        .attr('class', 'circle')
    define_scales: ->
      @x_scale = d3.scale.linear().domain([10, 90]).range([0, @width])
      @y_scale = d3.scale.linear().domain([0.5, 10]).range([@height, 0])
      # scale r so that area is proportional to population
      @r_scale = d3.scale.linear().domain(@get_population_min_max().map (x) -> Math.sqrt(x)).range([1, 50])    

    # calculates the min/max population for the data set
    get_population_min_max: ->
      all_data = @countries.reduce (prev, curr) ->
        prev.concat curr.population
      , []

    # html5 range inputs are supported by most browsers:
    add_year_slider: ->
      slider = $("<input id='slider' type='range' min='1960' max='2011'/>")
      curr_val = $("<span id='currentValue'></span>")
      $('#example').append [slider, $("<p id='note'>Year: </p>").append(curr_val)]

      slider.on 'change', =>
        val = slider.val()
        curr_val.html val
        @view_year @years.indexOf(Number(val))

    # transition the circles to the data at the given year
    view_year: (i) ->
        .attr('cx', (d) => @x_scale(d.life_expectancy[i]))
        .attr('cy', (d) => @y_scale(d.fertility_rate[i]))
        .attr('r', (d) => @r_scale(Math.sqrt(d.population[i])))

    add_axes: ->
      @x_axis_view = @view.append('g')
        .attr('class', 'axis')
        .attr('transform', "translate(0,#{@height})")

      @y_axis_view = @view.append('g')
        .attr('class', 'axis')
      @x_axis = d3.svg.axis().scale(@x_scale).orient('bottom')

      @y_axis = d3.svg.axis().scale(@y_scale).orient('left')

      # axes labels
      $('#example').append [
        $("<div class='x_label label'>Life Expectancy (years)</div>")
        $("<div class='y_label label'>Fertility Rate</div>") ]

    # appends tooltips to the bars. Uses d3-tip.js
    # see
    add_tooltips: ->
      tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html((d) -> "<span>#{d.country_name}</span>")

        .on('mouseout', tip.hide)


    .data_viz_example {
      position: absolute;
      margin-top: 40px;
      margin-left: 20px;
      // ticks and labels
      .axis path, .axis line { 
        fill: none;
        stroke: #3F3F3F;
        shape-rendering: crispEdges;

      .label {
        position: absolute;

        top: 500px;
        left: 470px;

      .y_label {
        -webkit-transform-origin: 0;
        transform-origin: 0;
        -webkit-transform: translateX(0px) rotate(-90deg);
        transform: translateX(0px) rotate(-90deg);
        top: 340px;
        left: 0px;

    .d3-tip {
      margin: auto;
      font-size: 0.8em;
      font-weight: bold;
      padding: 5px;
      background: rgba(0, 0, 0, 0.8);
      color: #fff;

    // Example 1
    &.example_1 {
      position: relative;
      width: 100%;
      circle {
        fill-opacity: 0;  
        stroke: #202555;
        stroke-width: 2px;
      #slider {
        position: relative;
        top: 50px;
        width: 400px;
      #note {
        position: relative;
        top: 30px;
      .x_label { left: 400px; }
      .y_label { top: 300px;}

Ex 2: animations can highlight comparisons

From NY Times: American time use survey

Provide comparisons between between groupings in the data

Ex 2: code

coffeescript (excerpt)

    constructor: ->
      @data =
      @activity_names = @data[0].map (x) ->

      @margin = {top: 20, right: 20, bottom: 30, left: 50}
      @width = 960 - @margin.left - @margin.right
      @height = 500 - - @margin.bottom

    # area
    @area = d3.svg.area()
      .x( (d) => @x_scale(d.x) )
      .y0( (d) => @y_scale(d.y0) )
      .y1( (d) => @y_scale(d.y0 + d.y) )

    # use stack function to map the data into form needed for stacked graph
    @stack = d3.layout.stack().values( (d) -> d.values)
    data = @stack(@data[0].map (x) ->
      values: (d,i) -> {x: i, y: d} )

    # draw the areas
      .attr('d', (d) => @area(d.values))
      .style('fill', (d) => @color_scale(

    transition: ->
      data = @data[@year_select.prop('selectedIndex')]
      index = @activity_select.prop('selectedIndex')

      data = @stack( (x,i) ->
        values: (d,j) ->
          x: j
          y: if index is 0 or index-1 is i then d else 0 )

        .attr('d', (d) => @area(d.values))

Each graph binds the data to visual properties in slightly different ways. D3 takes care of animating the graphs between states.

coffeescript (excerpt)

    # displays the data in a scatterplot
    show_scatterplot: ->
      bar_width = 20
      x_domain = [44, 85]
      x_label = 'Life Expectancy'
      y_domain = [0, 200]
      y_label = 'Countries'

      @update_scales x_domain, y_domain

        .delay((d,i) -> 10*i)
        .attr('width', bar_width)
        .attr('x', (d) => @x_scale(d.life_expectancy)-bar_width/2)
        .attr('y', (d,i) => @y_scale(i) - 20)
        .attr('height', @height - @y_scale(9))
        .attr('stroke-width', 1)
        .attr('rx', 10)
        .attr('ry', 10)

      @update_axes x_label, false, y_label, true

From interactive visualizations of decision trees

Ex 4: visual model exploration

Challenges with touch devices

Resources for learning d3.js

Other Web-based Tools

Other data visualization resources