Template:Graph:World Historical Highlights

From MediaWiki.org
Jump to navigation Jump to search
Template documentation


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[edit]

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[edit]

{{Graph:World Historical Highlights

| title=Global Rates of Obesity and Overweight
| table=Obesity Males.tab
| column=percent_overweight
| columnName=Rate of BMI>25
| year=2014
| note=[1]
}}

See or edit source data. [2]

Dataset format[edit]

The dataset should be stored at Commons, in the Data namespace, as a tabular data (.tab) file. 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.

Steps:

  • Download a .csv file, for example from ourworldindata.org
  • Trim to three columns in a spreadsheet program
  • Upload it at 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[edit]

{{Graph:World Historical Highlights

| title=Global Rates of Obesity and Overweight
| table=Obesity Males.tab
| column=percent_overweight
| columnName=Rate of BMI>25
| year=2014
| note=[1]
}}

See or edit source data. [2]

<graph>
{ 
  //
  // 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": {{{year}}} },
    { "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:///{{{table}}}",
    "format": {"type": "json", "property": "data"},
    "transform": [
      { "type": "formula", "field": "value", "expr": "datum.{{{column}}}" }
    ]
  },{
    "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": null
    },{
      "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": ["#f1f1f0", "#08306b"],
    "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"}
    ]} } }]
  },{
    "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"}
    ],
    "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": "\u007b{datum.data|number:'.0%'}\u007d"},
                {"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": "\u007b{parent.name}\u007d"},
              "fill": {"value": "black"},
              "fontWeight": {"value": "bold"}
        } } },
        {
          "type": "text",
          "properties": {
            "update": {
              "x": {"value": 6}, "y": {"value": 29},
              "text": [
                {"test": "isRange", "template": "Growth:\t\u007b{tooltip.datum.calc|number:'.1%'}\u007d"},
                {"template": "{{{columnName}}}:\t\u007b{tooltip.datum.calc|number:',.1f'}\u007d%"}
              ],
              "fill": {"value": "black"}
        } } },
        {
          "type": "text",
          "properties": {
            "update": {
              "x": {"value": 6}, "y": {"value": 44},
              "text": [
                {"test": "isRange", "template": ""},
                {"template": "Global position:\t#\u007b{parent.rank|number:'.0f'}\u007d"}
              ],
              "fill": {"value": "black"}
        } } },
    ]}

  ]
}
</graph>