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} }     }    }  ] }