$30 off During Our Annual Pro Sale. View Details »

Architecting Better Charts, FluentConf 2013 Keynote

Architecting Better Charts, FluentConf 2013 Keynote

Announcing the Miso Project's latest library, d3.chart - a framework for building reusable charts with d3.js.
http://misoproject.com/d3-chart

Video: http://www.youtube.com/watch?feature=player_embedded&v=TYgSc_S0lCw&list=SP055Epbe6d5avZGXwE5u039VQq_oQFgrc

Irene Ros

May 29, 2013
Tweet

More Decks by Irene Ros

Other Decks in Technology

Transcript

  1. The ABC of
    Data Visualization
    Irene Ros
    @ireneros
    Mike Pennisi
    @jugglinmike
    http://bocoup.com
    http://misoproject.com

    View Slide

  2. The ABC of
    Data Visualization
    Irene Ros
    @ireneros
    Mike Pennisi
    @jugglinmike
    http://bocoup.com
    http://misoproject.com
    Architecting
    Better Charts

    View Slide

  3. View Slide

  4. Cleanup

    View Slide

  5. Cleanup Transformation

    View Slide

  6. Cleanup Transformation Analysis

    View Slide

  7. Cleanup Transformation Analysis Visualization

    View Slide

  8. Cleanup Transformation Analysis Visualization

    View Slide

  9. Cleanup Transformation Analysis Visualization
    Is it good enough?
    Is the story right?
    Is the conclusion correct?
    Is it the right message?
    No

    View Slide

  10. Cleanup Transformation Analysis Visualization
    Is it good enough?
    Is the story right?
    Is the conclusion correct?
    Is it the right message?
    No
    Yes!
    Build it!
    On the web!

    View Slide

  11. We
    d3.js

    View Slide

  12. View Slide

  13. The Code Spaghetti Monster!

    View Slide

  14. ?
    What does it mean to
    Architect
    Data Visualization

    View Slide

  15. Making Reusable Charts
    Towards Reusable Charts
    http://bost.ocks.org/mike/chart/

    View Slide

  16. Repeatable
    Easy to create multiple instances of
    What is a reusable chart?
    Difficulty level:

    View Slide

  17. Repeatable
    Easy to create multiple instances of
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  18. Repeatable
    Easy to create multiple instances of
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  19. Configurable
    Easy to appropriate for a specific task
    What is a reusable chart?
    Difficulty level:

    View Slide

  20. Configurable
    Easy to appropriate for a specific task
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  21. Configurable
    Easy to appropriate for a specific task
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  22. Extensible
    Easy to extend with additional functionality
    What is a reusable chart?
    Difficulty level:

    View Slide

  23. Extensible
    Easy to extend with additional functionality
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  24. Extensible
    Easy to extend with additional functionality
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor
    10
    20
    60
    30

    View Slide

  25. Composable
    Easy to combine into other charts
    What is a reusable chart?
    Difficulty level:

    View Slide

  26. Composable
    Easy to combine into other charts
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor

    View Slide

  27. Composable
    Easy to combine into other charts
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor Axis Constructor
    +

    View Slide

  28. Composable
    Easy to combine into other charts
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor Axis Constructor
    + Label Constructor
    10
    40
    30 1
    +

    View Slide

  29. Composable
    Easy to combine into other charts
    What is a reusable chart?
    Difficulty level:
    BarChart Constructor Axis Constructor
    + Label Constructor
    10
    40
    30 1
    +
    10
    20
    60
    30
    =

    View Slide

  30. A Announcement
    Big

    View Slide

  31. A Announcement
    Big

    View Slide

  32. http://misoproject.com/d3-chart
    http://github.com/misoproject/d3.chart
    http://blog.bocoup.com
    Code:
    Announcement:

    View Slide

  33. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  34. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  35. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  36. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  37. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  38. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  39. Unpacking d3: var data = [1,3,4,6,10];
    var chart = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200);
    var circles = chart.append("g")
    .classed("circles", true)
    .selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");

    View Slide

  40. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  41. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  42. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  43. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  44. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  45. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  46. Now in d3.chart d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("circle")
    .data(data);
    },
    insert: function() {
    return this.append("circle");
    },
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", "blue");
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw(data);

    View Slide

  47. Repeatable
    var chart2 = d3.select("#vis2")
    .append("svg")
    .attr("height", 1000)
    .attr("width", 1000)
    .chart("CircleChart");
    chart2.draw([10,20,400]);
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart");
    chart1.draw([1,2,4]);

    View Slide

  48. Configurable
    Configurable
    d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    // other layer instructions...
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", this.chart().fill());
    }
    }
    });
    },
    fill: function(newFill) {
    if (arguments.length === 0) {
    return this._fill;
    }
    this._fill = newFill;
    return this;
    }
    });

    View Slide

  49. Configurable
    Configurable
    d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    // other layer instructions...
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", this.chart().fill());
    }
    }
    });
    },
    fill: function(newFill) {
    if (arguments.length === 0) {
    return this._fill;
    }
    this._fill = newFill;
    return this;
    }
    });

    View Slide

  50. Configurable
    Configurable
    d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    // other layer instructions...
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", this.chart().fill());
    }
    }
    });
    },
    fill: function(newFill) {
    if (arguments.length === 0) {
    return this._fill;
    }
    this._fill = newFill;
    return this;
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CircleChart")
    .fill("blue");
    chart1.draw(data);

    View Slide

  51. Configurable
    Extensible
    d3.chart("CircleChart").extend("CirclesWithNumbersChart", {
    initialize: function() {
    this.layer("labels", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("text")
    .data(data);
    },
    insert: function() {
    return this.append("text");
    },
    events: {
    enter: function() {
    return this.attr("x", function(d) {
    return d * 10;
    })
    .attr("y", 80)
    .style("text-anchor", "middle")
    .text(function(d) { return d; });
    }
    }
    });
    }
    });

    View Slide

  52. Extensible
    d3.chart("CircleChart").extend("CirclesWithNumbersChart", {
    initialize: function() {
    this.layer("labels", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("text")
    .data(data);
    },
    insert: function() {
    return this.append("text");
    },
    events: {
    enter: function() {
    return this.attr("x", function(d) {
    return d * 10;
    })
    .attr("y", 80)
    .style("text-anchor", "middle")
    .text(function(d) { return d; });
    }
    }
    });
    }
    });

    View Slide

  53. Extensible
    d3.chart("CircleChart").extend("CirclesWithNumbersChart", {
    initialize: function() {
    this.layer("labels", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("text")
    .data(data);
    },
    insert: function() {
    return this.append("text");
    },
    events: {
    enter: function() {
    return this.attr("x", function(d) {
    return d * 10;
    })
    .attr("y", 80)
    .style("text-anchor", "middle")
    .text(function(d) { return d; });
    }
    }
    });
    }
    });

    View Slide

  54. Extensible
    d3.chart("CircleChart").extend("CirclesWithNumbersChart", {
    initialize: function() {
    this.layer("labels", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("text")
    .data(data);
    },
    insert: function() {
    return this.append("text");
    },
    events: {
    enter: function() {
    return this.attr("x", function(d) {
    return d * 10;
    })
    .attr("y", 80)
    .style("text-anchor", "middle")
    .text(function(d) { return d; });
    }
    }
    });
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CirclesWithNumbersChart")
    .fill("blue");

    View Slide

  55. Composable

    View Slide

  56. Composable
    d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    // other layer instructions...
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", this.chart().fill());
    }
    }
    });
    },
    fill: function(newFill) {
    if (arguments.length === 0) {
    return this._fill;
    }
    this._fill = newFill;
    return this;
    }
    });

    View Slide

  57. Composable
    d3.chart("LabelsChart", {
    initialize: function() {
    this.layer("labels", this.base.append("g"), {
    dataBind: function(data) {
    return this.selectAll("text")
    .data(data);
    },
    insert: function() {
    return this.append("text");
    },
    events: {
    enter: function() {
    return this.attr("x", function(d) {
    return d * 10;
    })
    .attr("y", 80)
    .style("text-anchor", "middle")
    .text(function(d) { return d; });
    }
    }
    });
    }
    });
    d3.chart("CircleChart", {
    initialize: function() {
    this.layer("circles", this.base.append("g"), {
    // other layer instructions...
    events : {
    enter: function() {
    return this.attr("cy", 100)
    .attr("cx", function(d) {
    return d * 10;
    })
    .attr("r", 5)
    .style("fill", this.chart().fill());
    }
    }
    });
    },
    fill: function(newFill) {
    if (arguments.length === 0) {
    return this._fill;
    }
    this._fill = newFill;
    return this;
    }
    });

    View Slide

  58. Composable
    d3.chart("CLChart", {
    initialize: function() {
    var circles = this.mixin(
    this.base.append("g"),
    "CircleChart"
    );
    var labels = this.mixin(
    this.base.append("g"),
    "LabelsChart"
    );
    }
    });

    View Slide

  59. Composable
    d3.chart("CLChart", {
    initialize: function() {
    var circles = this.mixin(
    this.base.append("g"),
    "CircleChart"
    );
    var labels = this.mixin(
    this.base.append("g"),
    "LabelsChart"
    );
    }
    });

    View Slide

  60. Composable
    d3.chart("CLChart", {
    initialize: function() {
    var circles = this.mixin(
    this.base.append("g"),
    "CircleChart"
    );
    var labels = this.mixin(
    this.base.append("g"),
    "LabelsChart"
    );
    }
    });

    View Slide

  61. Composable
    d3.chart("CLChart", {
    initialize: function() {
    var circles = this.mixin(
    this.base.append("g"),
    "CircleChart"
    );
    var labels = this.mixin(
    this.base.append("g"),
    "LabelsChart"
    );
    }
    });
    var chart1 = d3.select("#vis")
    .append("svg")
    .attr("height", 200)
    .attr("width", 200)
    .chart("CLChart");
    chart1.draw(data);

    View Slide

  62. Let’s All Build Charts!
    http://github.com/misoproject/d3.chart
    http://misoproject.com/d3-chart
    Irene Ros
    @ireneros
    Mike Pennisi
    @jugglinmike
    http://bocoup.com
    http://misoproject.com

    View Slide