Extension:Graph/Interactive Graph Tutorial 2

In this tutorial we will create an interactive graph that will display historical fertility rates per country, with a slider to pick the year, and a map to show rate distribution around the world. The source code for this graph is here. You might also be interested in the complete Vega documentation.

In this tutorial, we continue from the first part of the tutorial.

Drawing a map with some useful data
Now that we built the slider in part 1 of this tutorial, we can add a map and mix it with the highlighting data. We need two sources of data - the map in TopoJSON format is stored in wiki markup here, and the fertility data that is stored as a CSV text in wiki markup, copied from WorldBank (license)

Each country is tagged with a ISO-3 country code. The CSV data contains "country", "id" columns, as well as years 1960..2013, each as a separate column.

 { "version": 2, "width": 500, "height": 260, "padding": 12, "background": "#edf1f7", "signals": [ {     "name": "isDragging", "init": false, "streams": [ {"type": "@handle:mousedown","expr": "true"}, {"type": "mouseup","expr": "false"} ]   },    {      "name": "scaledHandlePosition", "streams": [ {         "type": "mousemove[isDragging]", "expr": "eventX", "scale": {"name": "yearsScale","invert": true} }     ]    },    {      "name": "currentYear", "init": 2000, "expr": "clamp(parseInt(scaledHandlePosition),1960,2013)" } ],  "data": [ {     "name": "highlights", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:FertilityByCountryHistoric-csv&action=raw", "format": {"type": "csv"}, "transform": [ {         "type": "formula", "field": "v", "expr": "parseFloat(datum[''+currentYear])" }     ]    },    {      "name": "countries", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:WorldMap-iso3-json&action=raw", "format": {"type": "topojson","feature": "countries"}, "transform": [ {         "type": "geopath", "value": "data", "scale": 80, "center": [-180,125], "translate": [0,0], "projection": "equirectangular" },       {          "type": "lookup", "keys": ["id"], "on": "highlights", "onKey": "id", "as": ["zipped"], "default": {"v": null, "country":"No data"} }     ]    }  ],  "scales": [ {     "name": "yearsScale", "type": "linear", "zero": false, "domain": [1960,2013], "range": "width" },   {      "name": "color", "type": "linear", "domain": {"data": "countries","field": "zipped.v"}, "domainMin": 1, "zero": false, "range": ["#FFEDBC", "#f83600"] } ],  "marks": [ {     "name": "yearLabel", "type": "text", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 25}, "fontSize": {"value": 32}, "fontWeight": {"value": "bold"}, "fill": {"value": "steelblue"} },       "update": {"text": {"signal": "currentYear"}} }   },    {      "name": "scrollLine", "type": "rule", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 40}, "x2": {"value": 500}, "stroke": {"value": "#000"}, "strokeWidth": {"value": 2} }     }    },    {      "name": "handle", "type": "path", "properties": { "enter": { "y": {"value": 40}, "path": {"value": "m-5.5,-10l0,20l11.5,-10l-11.5,-10z"}, "stroke": {"value": "#880"}, "strokeWidth": {"value": 2.5} },       "update": { "x": {"scale": "yearsScale","signal": "currentYear"}, "fill": {"value": "#fff"} },       "hover": {"fill": {"value": "#f00"}} }   },    {      "name": "map", "type": "path", "from": {"data": "countries"}, "properties": { "enter": {"path": {"field": "layout_path"}}, "update": { "fill":{ "rule": [ {               "predicate": { "name": "isNotNull", "id": {"field": "zipped.v"} },               "scale": "color", "field": "zipped.v"             }, {"value": "grey"} ]         }        },        "hover": {"fill": {"value": "#989898"}} }   }  ],  "predicates": [ {     "name": "isNotNull", "type": "!=", "operands": [{"value": null}, {"arg": "id"}] } ] }

Adding Legend
Graph will be more informative if the user sees how colors correspond to numbers. Unfortunately the legend placement is a bit broken at the moment and will need to be fixed in Vega, but it tends to work in non-map based graphs.

 { "version": 2, "width": 500, "height": 260, "padding": 12, "background": "#edf1f7", "signals": [ {     "name": "isDragging", "init": false, "streams": [ {"type": "@handle:mousedown","expr": "true"}, {"type": "mouseup","expr": "false"} ]   },    {      "name": "scaledHandlePosition", "streams": [ {         "type": "mousemove[isDragging]", "expr": "eventX", "scale": {"name": "yearsScale","invert": true} }     ]    },    {      "name": "currentYear", "init": 2000, "expr": "clamp(parseInt(scaledHandlePosition),1960,2013)" } ],  "data": [ {     "name": "highlights", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:FertilityByCountryHistoric-csv&action=raw", "format": {"type": "csv"}, "transform": [ {         "type": "formula", "field": "v", "expr": "parseFloat(datum[''+currentYear])" }     ]    },    {      "name": "countries", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:WorldMap-iso3-json&action=raw", "format": {"type": "topojson","feature": "countries"}, "transform": [ {         "type": "geopath", "value": "data", "scale": 80, "center": [-180,125], "translate": [0,0], "projection": "equirectangular" },       {          "type": "lookup", "keys": ["id"], "on": "highlights", "onKey": "id", "as": ["zipped"], "default": {"v": null, "country":"No data"} }     ]    }  ],  "scales": [ {     "name": "yearsScale", "type": "linear", "zero": false, "domain": [1960,2013], "range": "width" },   {      "name": "color", "type": "linear", "domain": {"data": "countries","field": "zipped.v"}, "domainMin": 1, "zero": false, "range": ["#FFEDBC", "#f83600"] } ],  "marks": [ {     "name": "yearLabel", "type": "text", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 25}, "fontSize": {"value": 32}, "fontWeight": {"value": "bold"}, "fill": {"value": "steelblue"} },       "update": {"text": {"signal": "currentYear"}} }   },    {      "name": "scrollLine", "type": "rule", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 40}, "x2": {"value": 500}, "stroke": {"value": "#000"}, "strokeWidth": {"value": 2} }     }    },    {      "name": "handle", "type": "path", "properties": { "enter": { "y": {"value": 40}, "path": {"value": "m-5.5,-10l0,20l11.5,-10l-11.5,-10z"}, "stroke": {"value": "#880"}, "strokeWidth": {"value": 2.5} },       "update": { "x": {"scale": "yearsScale","signal": "currentYear"}, "fill": {"value": "#fff"} },       "hover": {"fill": {"value": "#f00"}} }   },    {      "name": "map", "type": "path", "from": {"data": "countries"}, "properties": { "enter": {"path": {"field": "layout_path"}}, "update": { "fill":{ "rule": [ {               "predicate": { "name": "isNotNull", "id": {"field": "zipped.v"} },               "scale": "color", "field": "zipped.v"             }, {"value": "grey"} ]         }        },        "hover": {"fill": {"value": "#989898"}} }   }  ],  "predicates": [ {     "name": "isNotNull", "type": "!=", "operands": [{"value": null}, {"arg": "id"}] } ],  "legends": [ {     "fill": "color", "title": "Fertility", "offset":-300, "properties": { "gradient": { "stroke": {"value": "transparent"} },       "title": { "fontSize": {"value": 14} }     }    }  ] }

Adding Some Statistics
The map mouseover event will cause the country and the associated rate show up in the right corner.

 { "version": 2, "width": 500, "height": 260, "padding": 12, "background": "#edf1f7", "signals": [ {     "name": "isDragging", "init": false, "streams": [ {"type": "@handle:mousedown","expr": "true"}, {"type": "mouseup","expr": "false"} ]   },    {      "name": "scaledHandlePosition", "streams": [ {         "type": "mousemove[isDragging]", "expr": "eventX", "scale": {"name": "yearsScale","invert": true} }     ]    },    {      "name": "currentYear", "init": 2000, "expr": "clamp(parseInt(scaledHandlePosition),1960,2013)" },   {      "name": "tooltipSignal", "init": {"expr": "{x: 0, y: 0, datum: {} }"}, "streams": [ {           "type": "@map:mouseover", "expr": "{x: eventX, y: eventY, datum: eventItem.datum.zipped}" },       {            "type": "@map:mouseout", "expr": "{x: 0, y: 0, datum: {} }" }     ]     }  ],  "data": [ {     "name": "highlights", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:FertilityByCountryHistoric-csv&action=raw", "format": {"type": "csv"}, "transform": [ {         "type": "formula", "field": "v", "expr": "parseFloat(datum[''+currentYear])" }     ]    },    {      "name": "countries", "url": "https://www.mediawiki.org/w/index.php?title=Extension:Graph/Demo/RawData:WorldMap-iso3-json&action=raw", "format": {"type": "topojson","feature": "countries"}, "transform": [ {         "type": "geopath", "value": "data", "scale": 80, "center": [-180,125], "translate": [0,0], "projection": "equirectangular" },       {          "type": "lookup", "keys": ["id"], "on": "highlights", "onKey": "id", "as": ["zipped"], "default": {"v": null, "country":"No data"} }     ]    }  ],  "scales": [ {     "name": "yearsScale", "type": "linear", "zero": false, "domain": [1960,2013], "range": "width" },   {      "name": "color", "type": "linear", "domain": {"data": "countries","field": "zipped.v"}, "domainMin": 1, "zero": false, "range": ["#FFEDBC", "#f83600"] } ],  "marks": [ {     "name": "yearLabel", "type": "text", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 25}, "fontSize": {"value": 32}, "fontWeight": {"value": "bold"}, "fill": {"value": "steelblue"} },       "update": {"text": {"signal": "currentYear"}} }   },    {      "name": "scrollLine", "type": "rule", "properties": { "enter": { "x": {"value": 0}, "y": {"value": 40}, "x2": {"value": 500}, "stroke": {"value": "#000"}, "strokeWidth": {"value": 2} }     }    },    {      "name": "handle", "type": "path", "properties": { "enter": { "y": {"value": 40}, "path": {"value": "m-5.5,-10l0,20l11.5,-10l-11.5,-10z"}, "stroke": {"value": "#880"}, "strokeWidth": {"value": 2.5} },       "update": { "x": {"scale": "yearsScale","signal": "currentYear"}, "fill": {"value": "#fff"} },       "hover": {"fill": {"value": "#f00"}} }   },    {      "name": "map", "type": "path", "from": {"data": "countries"}, "properties": { "enter": {"path": {"field": "layout_path"}}, "update": { "fill":{ "rule": [ {               "predicate": { "name": "isNotNull", "id": {"field": "zipped.v"} },               "scale": "color", "field": "zipped.v"             }, {"value": "grey"} ]         }        },        "hover": {"fill": {"value": "#989898"}} }   },    {      "type": "text", "properties": { "enter": { "x": {"value": 500}, "y": {"value": 10}, "align": {"value": "right"}, "fontSize": {"value": 17}, "fill": {"value": "black"} },       "update": { "text": {"template": "\u007b{tooltipSignal.datum.country}} \u007b{tooltipSignal.datum.v}}"} }     }    }  ],  "predicates": [ {     "name": "isNotNull", "type": "!=", "operands": [{"value": null}, {"arg": "id"}] } ],  "legends": [ {     "fill": "color", "title": "Fertility", "offset":-300, "properties": { "gradient": { "stroke": {"value": "transparent"} },       "title": { "fontSize": {"value": 14} }     }    }  ] }