Template:Global Heat Maps by Year
This graph's main version resides at Template:Graph:World Historical Highlights. Please make or suggest all the changes there, and copy it everywhere else (until the copying is automated)
Usage
This template creates an interactive world choropleth map, indicating some statistical value with different colors for different countries and years. The "play" button imports the dataset and starts the interactivity. The curve on the timeline shows the summarized values for all countries over time. The timeline is also a year slider, allowing the user to select year for the map. If the user marks an interval of several years on the timeline, the map colors indicate how the value has changed between the first and last year in the interval. A tooltip with country data is shown when the mouse is over a country.
Example
{{Global Heat Maps by Year | title=Global Rates of Obesity and Overweight |
---|
<graph mode="interactive">
{ // // ATTENTION: This code is maintained at https://www.mediawiki.org/wiki/Template:Graph:World_Historical_Highlights // Please do not modify it anywhere else, as it may get copied and override your changes. // Suggestions can be made at https://www.mediawiki.org/wiki/Template_talk:Graph:World_Historical_Highlights // "version": 2, "width": 300, "height": 265, "signals": [ // TODO: should be auto-calculated last available { "name": "initYear", "init": 2014 }, { "name": "gapHeight", "init": 26 }, { // Hide overview if total height is too small "name": "showOverview", "init": {"expr": "true || height < (gapHeight + 100)" } }, { "name": "overviewHeight", "init": {"expr": "showOverview ? 40 : 0" } }, { "name": "detailHeight", "init": {"expr": "height - (showOverview ? overviewHeight + gapHeight : 0)" } }, { "name": "overviewYPos", "init": {"expr": "height - overviewHeight" } }, { "name": "mapXC", "init": {"expr": "width/2"} }, { "name": "mapYC", "init": {"expr": "overviewYPos/2"} }, { "name": "brush_start", "streams": [{ "type": "@overview:mousedown, @overview:touchstart", "expr": "clamp(eventX(), 0, width)", "scale": {"name": "xOverview", "invert": true} }] }, { "name": "brush_end", "streams": [{ "type": "@overview:mousedown, [@overview:mousedown, window:mouseup] > window:mousemove, @overview:mouseup, @overview:touchstart, [@overview:touchstart, window:touchend] > window:touchmove, @overview:touchend", "expr": "clamp(eventX(), 0, width)", "scale": {"name": "xOverview", "invert": true} }] }, { "name": "fromYear", "init": {"expr": "initYear"}, "expr": "year(min(brush_start, brush_end))" }, { "name": "toYear", "init": {"expr": "initYear"}, "expr": "year(max(brush_start, brush_end))" }, { "name": "isRange", "init": {"expr": "false"}, "expr": "fromYear !== toYear" }, { "name": "tooltip", "init": {"expr": "{x: 0, y: 0, datum: false }"}, "streams": [ {"type": "@map:mouseout, @map:touchstart", "expr": "{x: 0, y: 0, datum: false }" }, {"type": "@map:mouseover, @map:touchstart", "expr": "{x: eventX(), y: eventY(), datum: eventItem().datum.lookup}" } ] } ], "data": [{ "name": "data", "url": "tabular:///Obesity Males.tab", "format": {"type": "json", "property": "data"}, "transform": [ { "type": "formula", "field": "value", "expr": "datum.percent_overweight" } ] },{ "name": "totals", "source": "data", "transform": [ { "type": "aggregate", "groupby": ["year"], "summarize": [{"field": "value", "ops": ["sum"], "as": ["total"]}] }, { "type": "formula", "field": "date", "expr": "datetime(datum.year, 0, 1)" } ] },{ // Select just the source data for the starting year "name": "firstYearData", "source": "data", "transform": [{"type": "filter", "test": "datum.year === fromYear"}] },{ // Select just the source data for the ending year "name": "yearData", "source": "data", "transform": [{ "type": "filter", "test": "datum.year === toYear" },{ "type": "sort", "by": ["-value"] },{ "type": "rank", "field": "country" },{ "type": "lookup", "on": "firstYearData", "onKey": "country", "keys": ["country"], "as": ["firstYear"], "default": 2021 },{ "type": "formula", "field": "calc", "expr": "if(isRange, (datum.value - datum.firstYear.value)/datum.firstYear.value, datum.value)" }] },{ "name": "mapData", "url": "map:///Naturalearthdata.com/admin-0-countries-no-antarctica.map", "format": {"type": "json", "property": "data.features"}, "transform": [{ "type": "geopath", "projection": "equirectangular", "scale": 72, "translate": [{"expr": "mapXC"}, {"expr": "mapYC"}] },{ "type": "formula", "field": "my_id", "expr": "datum.properties.iso_a3 || datum.properties.adm0_a3" },{ "type": "lookup", "on": "yearData", "onKey": "country", "keys": ["my_id"], "as": ["lookup"], "default": 100 }] },{ "name": "dummyValue", "values": [{}] }], "scales": [{ "name": "color", "type": "linear", "domain": {"data": "yearData", "field": "calc"}, "range": ["blue", "#a50026"], "zero": false, "clamp": true },{ "name": "diffColor", "type": "linear", "domain": [-1, -0.8, -0.6, -0.3, -0.1, 0, 0.1, 0.3, 0.6, 0.8, 1], "range": ["#313695", "#4575b4", "#74add1", "#abd9e9", "#e0f3f8", "#ffffbf", "#fee090", "#fdae61", "#f46d43", "#d73027", "#a50026"], "zero": false, "clamp": true },{ "name": "xOverview", "type": "time", "range": "width", "domain": {"data": "totals", "field": "date"} },{ "name": "yOverview", "type": "linear", "rangeMin": {"signal": "overviewHeight"}, "nice": true, "zero": false, "domain": {"data": "totals", "field": "total"} }], "marks": [{ "type": "group", "name": "detail", "properties": { "enter": { "height": {"signal": "detailHeight"}, "width": {"signal": "width"} } }, "marks": [{ "name": "map", "type": "path", "from": {"data": "mapData"}, "properties": { "enter": { "stroke": {"value": "#fff"}, "path": {"field": "layout_path"} }, "update": { "fill": [ {"test": "isRange", "field": "lookup.calc", "scale": "diffColor"}, {"field": "lookup.calc", "scale": "color"} ], "stroke": {"value": "#fff"} }, "hover": {"fill": {"value": "#989898"}, "stroke": {"value": "#000"} } } }] },{ "type": "group", "name": "overview", "from": { "data": "dummyValue", // HACK: brush_end is needed to fool optimizer, because otherwise legend doesn't auto-update "transform": [{"type": "filter", "test": "(brush_end && 0) || showOverview"}] }, "properties": { "enter": { "x": {"value": 0}, "y": {"signal": "overviewYPos"}, "height": {"signal": "overviewHeight"}, "width": {"signal": "width"}, "fill": {"value": "transparent"} } }, "axes": [ {"type": "x", "scale": "xOverview", "ticks": 7} ], "marks": [{ // Draw scale for a single year (I wish we could dynamically pick which scale to use for the legend) "type": "group", // HACK: brush_end is needed to fool optimizer, because otherwise legend doesn't auto-update "from": { "data": "dummyValue", "transform": [{"type": "filter", "test": "(brush_end && 0) || !isRange"}] }, "properties": { "enter": { "width": {"signal": "width"} } }, "legends": [{ "fill": "color", "offset": 20, "properties": {"legend": {"y": {"value": 30} } } }]},{ // Draw scale for a range (I wish we could dynamically pick which scale to use for the legend) "type": "group", "from": { "data": "dummyValue", "transform": [{"type": "filter", "test": "isRange"}] }, "properties": { "enter": { "width": {"signal": "width"} } }, "legends": [{ "fill": "diffColor", "offset": 20, "properties": { "legend": {"y": {"value": 30} }, "labels": { "text": [ {"test": "datum.data===0", "value": "0"}, {"test": "(datum.data%1)===0", "template": "{{datum.data|number:'.0%'}}"}, {"value": ""} ]} } }]},{ "name": "yearLabel", "type": "text", "from": { "data": "dummyValue", "transform": [ {"type": "formula", "field": "text", "expr": "if(isRange,fromYear + '-' + toYear, fromYear)"}, {"type": "formula", "field": "fontSize", "expr": "if(isRange,22,32)"} ]}, "properties": { "enter": { "x": {"signal": "width", "offset": 72}, "y": {"value": 20}, "fontWeight": {"value": "bold"}, "align": {"value": "center"}, "baseline": {"value": "middle"}, "fill": {"value": "#08306b"} }, "update": { "fontSize": {"field": "fontSize"}, "text": {"field": "text"} } } },{ "type": "line", "from": { "data": "totals" }, "properties": { "update": { "x": {"scale": "xOverview", "field": "date"}, "y": {"scale": "yOverview", "field": "total"}, "stroke": {"value": "#08306b"}, "strokeWidth": {"value": 2} } } },{ "type": "rect", "from": { "data": "dummyValue", "transform": [ {"type": "formula", "field": "fromDate", "expr": "datetime(fromYear, -6, 1)"}, {"type": "formula", "field": "toDate", "expr": "datetime(toYear, 6, 1)"} ]}, "properties": { "enter": { "y": {"value": 0}, "height": {"signal": "overviewHeight"}, "fill": {"value": "#333"}, "fillOpacity": {"value": 0.2}, "stroke": {"value": "#f00"}, "strokeDash": {"value": [4]} }, "update": { "x": {"scale": "xOverview", "field": "fromDate"}, "x2": {"scale": "xOverview", "field": "toDate"} } } }]}, { "name": "tooltip", "type": "group", "from": { "data": "dummyValue", "transform": [ {"type": "filter", "test": "tooltip.datum && tooltip.datum.calc"}, {"type": "formula", "field": "offsetX", "expr": "5"}, {"type": "formula", "field": "offsetY", "expr": "30"}, {"type": "formula", "field": "tipWidth", "expr": "200"}, {"type": "formula", "field": "tipHeight", "expr": "51"}, {"type": "formula", "field": "alignLeft", "expr": "tooltip.x > width - datum.offsetX - datum.tipWidth"}, {"type": "formula", "field": "alignTop", "expr": "tooltip.y > height - datum.offsetY - datum.tipHeight"}, {"type": "formula", "field": "x", "expr": "max(0, tooltip.x + (datum.alignLeft ? -datum.offsetX-datum.tipWidth : datum.offsetX ))"}, {"type": "formula", "field": "y", "expr": "tooltip.y + (datum.alignTop ? -1 : 1) * datum.offsetY"}, {"type": "formula", "field": "lookupCountry", "expr": "tooltip.datum.country"}, { "type": "lookup", "on": "mapData", "onKey": "my_id", "keys": ["lookupCountry"], "as": ["mapDataVal"], "default": null }, {"type": "formula", "field": "name", "expr": "datum.mapDataVal ? datum.mapDataVal.properties.name : '?xyz?'"}, { "type": "lookup", "on": "yearData", "onKey": "country", "keys": ["lookupCountry"], "as": ["yearDataVal"], "default": null }, {"type": "formula", "field": "rank", "expr": "datum.yearDataVal ? datum.yearDataVal.rank : 1000"} ]}, "properties": { "update": { "x": {"field": "x" }, "y": {"field": "y" }, "width": {"field": "tipWidth" }, "height": {"field": "tipHeight" }, "fill": {"value": "#fff"}, "fillOpacity": {"value": 0.85}, "stroke": {"value": "#aaa"}, "strokeWidth": {"value": 0.5} } }, "marks": [ { "type": "text", "properties": { "update": { "x": {"value": 6}, "y": {"value": 14}, "text": {"template": "{{parent.name}}"}, "fill": {"value": "black"}, "fontWeight": {"value": "bold"} } } }, { "type": "text", "properties": { "update": { "x": {"value": 6}, "y": {"value": 29}, "text": [ {"test": "isRange", "template": "Growth:\t{{tooltip.datum.calc|number:'.1%'}}"}, {"template": "Rate of BMI>25:\t{{tooltip.datum.calc|number:',.1f'}}%"} ], "fill": {"value": "black"} } } }, { "type": "text", "properties": { "update": { "x": {"value": 6}, "y": {"value": 44}, "text": [ {"test": "isRange", "template": ""}, {"template": "Global position:\t#{{parent.rank|number:'.0f'}}"} ], "fill": {"value": "black"} } } }, ]} // Draw title at the top of the graph , { "type": "text", "properties": { "enter": { "x": {"signal": "width", "mult": 0.5, "offset": 30}, "y": {"value": -15}, "text": {"value": "Global Rates of Obesity and Overweight"}, "fontWeight": {"value": "bold"}, "align": {"value": "center"}, "baseline": {"value": "bottom"}, "fill": {"value": "#000"} } } } ] } </graph> See or edit source data. [2] |
Dataset format
The dataset should be stored at Wikimedia commons, in the Data namespace, as a tabular data (.tab) file. Currently, the file format should be JSON, representing a three column table, where the first column is the three-letter ISO country code, the second is the year and the third is the value. In the future, CSV-files may be possible.
Steps:
- Download a .csv file, for example from https://ourworldindata.org
- Trim to three columns in a spreadsheet program
- Upload it at https://www.csvjson.com/csv2json . Select "parse numbers".
- Copy the json output and paste it into Notepad. Find and replace { with [, and "Country:" with nothing
- Paste this data below the heading data, at for example [:commons:Data:Child Mortality.tab]
Be aware of some minor bugs.
See also
- {{Graph:Map}}
- {{Choropleth world map}}