Node.js is dead, long live Node.js

Vega.js - Building charts in minutes

Jaime Andrés García
Analytic Board
Medellín, 16 de Septiembre de 2015

Why Vega.js?

Support fast and customizable design

Make visualizations more reusable and shareable

Enable programmatic generation of visualizations

Improve performance and platform flexibility

SVG - Canvas - WebGL

Testing SVG - Canvas - WebGL

Step 1 - Acquiring the data

Node.js ChangelogExtract Semantic

Step 2 - Installing vega.js

bower install d3 vega
or
npm install d3 vega

Step 3 - Calling vega

function parse(spec,id) {
  vg.parse.spec(spec, function(chart) {
    var view = chart({ el:id });
    view.viewport(null)
      .renderer("svg")
      .update();
  });
}
parse("charts/chart.json","#vis");

Step 4 - Visualization

"width": 800,
"height": 300,
"padding": {"top": 10, "left": 30, "bottom": 30, "right": 10},
"data": [
  {
    "name": "table",
    "url": "data/data.csv",
    "format": {
      "type": "csv",
      "parse": {
        "date": "date"
      }
    }
  }
]

Step 5 - Scales

"scales": [
  {
    "name": "x",
    "type": "time",
    "range": "width",
    "domain": {"data": "table", "field": "date"}
  },
  {
    "name": "y",
    "type": "log",
    "range": "height",
    "domain": {"data": "table", "field": "version"}
  }
]

Step 6 - Axes

"axes": [
  {"type": "x", "scale": "x"},
  {"type": "y", "scale": "y"}
]

Step 7 - Marks

"marks": [
  {
    "type": "symbol",
    "from": {"data": "table"},
    "properties": {
      "enter": {
        "x": {"scale": "x", "field": "date"},
        "y": {"scale": "y", "field": "version"},
        "stroke": {"value": "#80bd01"},
        "fill": {"value": "#80bd01"}
      },
      "update": {
        "size": {"value": 10},
        "fillOpacity": {"value": 1}
      },
      "hover": {
        "size": {"value": 40},
        "fillOpacity": {"value": 0.5}
      }
    }
  }
]

Result - Node versions

There is a missing part in the story

IO.js

Step 9 - Marks Groups

{
  "type": "group",
  "from": {
    "data": "nodeversions",
    "transform": [{"type": "facet", "groupby": ["engine"]}]
  },
  "marks": [
    {
      "type": "symbol",
      "properties": {
        "enter": {
          "x": {"scale": "x", "field": "date"},
          "y": {"scale": "y", "field": "version"},
          "fill": {"scale": "color", "field": "engine"},
          "stroke": {"scale": "color", "field": "engine"}
        },
        "update": {
          "size": {"value": 15},
          "fillOpacity": {"value": 1}
        },
        "hover": {
          "size": {"value": 40},
          "fillOpacity": {"value": 0.5}
        }
      }
    }

Step 10 - Text Marks in specific dates

{
  "type": "text",
  "from": {
    "transform": [{"type": "filter", "test": "datum.date == time('2015-01-14')"}]
  },
  "properties": {
    "enter": {
      "x": {"scale": "x", "field": "date", "offset": -20},
      "y": {"scale": "y", "field": "version"},
      "fill": {"scale": "color", "field": "engine"},
      "text": {"field": "engine"},
      "baseline": {"value": "middle"}
    }
  }
}

Step 11 - Tooltip - Signals

"signals": [
  {
    "name": "tooltip",
    "init": {"expr": "{date:time('2009-06-11'),version:0.3}"},
    "streams": [
      {"type": "symbol:mouseover", "expr": "datum"},
      {"type": "symbol:mouseout", "expr": "{}"}
    ],
    "transform": [
      {"type": "sort", "by": "orginalversion"}
    ]
  }
]

Step 12 - Tooltip - Predicates

"predicates": [
  {
    "name": "tooltip", "type": "==",
    "operands": [{"signal": "tooltip._id"}, {"arg": "id"}]
  }
]

Step 13 - Tooltip - Rules

{
  "type": "text",
  "properties": {
    "enter": {
      "fill": {"value": "#000"}
    },
    "update": {
      "x": {"value": 6},
      "y": {"value": 14},
      
      "text":{
        "rule": [
          {
            "predicate": {
              "name": "tooltip",
              "id": {"value": null}
            },
            "template": ""
          },
          {"template":
          "{{tooltip.date|time:'%Y-%m-%d'}}
          ({{tooltip.version|left:1}}.{{tooltip.version|slice:1}})"}
        ]
      },
      
      "fillOpacity": {
        "rule": [
          {
            "predicate": {
              "name": "tooltip",
              "id": {"value": null}
            },
            "value": 0
          },
          {"value": 1}
        ]
      }
    }
  }
}

Result - The complete story

Now

Some gifs that always work

horror

killing myself

clarity

terrified

@analyticboard

Jaime Andrés García