Large Magellanic Cloud/Sandbox

 { "width": 600, "height": 400,

"data": [ {     "name": "gapminder", "url": "wikiraw:///Extension:Graph/data/gapminder-json" },   {      "name": "clusters", "values": [ {"id": 0, "name": "South Asia"}, {"id": 1, "name": "Europe & Central Asia"}, {"id": 2, "name": "Sub-Saharan Africa"}, {"id": 3, "name": "America"}, {"id": 4, "name": "East Asia & Pacific"}, {"id": 5, "name": "Middle East & North Africa"} ]   },    {      "name": "country_timeline", "source": "gapminder", "transform": [ {"type": "filter", "test": "timeline && datum.country == timeline.country"}, {"type": "sort", "by": "year"} ]   },    {      "name": "thisYear", "source": "gapminder", "transform": [ {"type": "filter", "test": "datum.year == currentYear"} ]   },    {      "name": "prevYear", "source": "gapminder", "transform": [ {"type": "filter", "test": "datum.year == currentYear-stepYear"} ]   },    {      "name": "nextYear", "source": "gapminder", "transform": [ {"type": "filter", "test": "datum.year == currentYear+stepYear"} ]   },    {      "name": "countries", "source": "gapminder", "transform": [ {"type": "aggregate", "groupby": ["country"], "summarize": {"*": ["count"]}} ]   },    {      "name": "interpolate", "source": "countries", "transform": [ {         "type": "lookup", "on": "thisYear", "onKey": "country", "keys": ["country"], "as": ["this"], "default": {} },       {          "type": "lookup", "on": "prevYear", "onKey": "country", "keys": ["country"], "as": ["prev"], "default": {} },       {          "type": "lookup", "on": "nextYear", "onKey": "country", "keys": ["country"], "as": ["next"], "default": {} },       {          "type": "formula", "field": "target_fertility", "expr": "interYear > currentYear ? datum.next.fertility : (datum.prev.fertility||datum.this.fertility)" },       {          "type": "formula", "field": "target_life_expect", "expr": "interYear > currentYear ? datum.next.life_expect : (datum.prev.life_expect||datum.this.life_expect)" },       {          "type": "formula", "field": "inter_fertility", "expr": "interYear==2000 ? datum.this.fertility : datum.this.fertility + (datum.target_fertility-datum.this.fertility) * abs(interYear-datum.this.year)/5" },       {          "type": "formula", "field": "inter_life_expect", "expr": "interYear==2000 ? datum.this.life_expect : datum.this.life_expect + (datum.target_life_expect-datum.this.life_expect) * abs(interYear-datum.this.year)/5" }     ]    },    {      "name": "trackCountries", "modify": [ {"type": "toggle", "signal": "active", "field": "country"} ]   }  ],

"signals": [ {"name": "minYear", "init": 1955}, {"name": "maxYear", "init": 2005}, {"name": "stepYear", "init": 5}, {     "name": "active", "init": {}, "streams": [ {"type": "@point:mousedown, @point:touchstart", "expr": "datum"}, {"type": "window:mouseup, window:touchend", "expr": "{}"} ]   },    {"name": "isActive", "expr": "active.country"}, {     "name": "cursor", "streams": [ {"type": "isActive", "expr": "isActive ? 'pointer' : 'default'"} ]   },    {      "name": "timeline", "init": {}, "streams": [ {"type": "@point:mouseover", "expr": "isActive ? active : datum"}, {"type": "@point:mouseout, active", "expr": "active"} ]   },    {      "name": "tX", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.this.fertility", "scale": "x" }]   },    {      "name": "tY", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.this.life_expect", "scale": "y" }]   },    {      "name": "pX", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.prev.fertility", "scale": "x" }]   },    {      "name": "pY", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.prev.life_expect", "scale": "y" }]   },    {      "name": "nX", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.next.fertility", "scale": "x" }]   },    {      "name": "nY", "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "active.next.life_expect", "scale": "y" }]   },    {      "name": "thisDist", "init": 0, "streams":[{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "sqrt(pow(eventX-tX, 2) + pow(eventY-tY, 2))" }]   },    {      "name": "prevDist", "init": 0, "streams":[{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "sqrt(pow(eventX-pX, 2) + pow(eventY-pY, 2))" }]   },    {      "name": "nextDist", "init": 0, "streams":[{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "sqrt(pow(eventX-nX, 2) + pow(eventY-nY, 2))" }]   },    {      "name": "prevScore", "init": 0, "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "((pX-tX) * (eventX-tX) + (pY-tY) * (eventY-tY))/prevDist || -999999" }]   },    {      "name": "nextScore", "init": 0, "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "((nX-tX) * (eventX-tX) + (nY-tY) * (eventY-tY))/nextDist || -999999" }]   },    {      "name": "interYear", "init": 1980, "streams": [{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "min(maxYear, currentYear+5, max(minYear, currentYear-5, prevScore > nextScore ? (currentYear - 2.5*prevScore/sqrt(pow(pX-tX, 2) + pow(pY-tY, 2))) : (currentYear + 2.5*nextScore/sqrt(pow(nX-tX, 2) + pow(nY-tY, 2)))))" }]   },    {      "name": "currentYear", "init": 1980, "streams":[{ "type": "mousemove[isActive], touchmove[isActive]", "expr": "min(maxYear, max(minYear, prevScore > nextScore ? (thisDist < prevDist ? currentYear : currentYear-5) : (thisDist < nextDist ? currentYear : currentYear+5)))" }]   }  ],

"scales": [ {     "name": "x", "type": "linear", "domain": {"data": "gapminder", "field": "fertility"}, "range": "width" },   {      "name": "y", "type": "linear", "domain": {"data": "gapminder", "field": "life_expect"}, "range": "height", "nice": true, "zero": false },   {      "name": "c", "type": "ordinal", "domain": {"data": "gapminder", "field": "cluster"}, "range": "category10" },   {      "name": "label", "type": "ordinal", "domain": {"data": "clusters", "field": "id"}, "range": {"data": "clusters", "field": "name"} } ],

"axes": [ {     "title": "Fertility", "type": "x", "scale": "x", "grid": true, "layer": "back", "ticks": 5 },   {      "title": "Life Expectancy", "type": "y", "scale": "y", "grid": true, "layer": "back", "ticks": 5 } ],

"legends": [{ "fill": "c", "orient": "right", "properties": { "labels": { "text": {"scale": "label", "field": "data"} }   }  }],

"marks": [ {     "type": "text", "properties": { "update": { "text": {"signal": "currentYear"}, "x": {"value": 300}, "y": {"value": 300}, "fill": {"value": "grey"}, "fillOpacity": {"value": 0.25}, "fontSize": {"value": 100} }     }    },    {      "type": "text", "from": {"data": "country_timeline"}, "properties": { "enter": { "x": {"scale": "x", "field": "fertility", "offset": 5}, "y": {"scale": "y", "field": "life_expect"}, "fill": {"value": "#555"}, "fillOpacity": {"value": 0.6}, "text": {"field": "year"} }     }    },    {      "type": "line", "from": {"data": "country_timeline"}, "properties": { "update": { "x": {"scale": "x", "field": "fertility"}, "y": {"scale": "y", "field": "life_expect"}, "stroke": {"value": "#bbb"}, "strokeWidth": {"value": 5}, "strokeOpacity": {"value": 0.5} }     }    },    {      "type": "text", "from": {"data": "interpolate"}, "properties": { "enter": { "fill": {"scale": "c", "field": "this.cluster"}, "fontSize": {"value": 14}, "fontWeight": {"value": "bold"}, "text": {"field": "country"}, "align": {"value": "center"}, "baseline": {"value": "bottom"} },       "update": { "x": {"scale": "x", "field": "inter_fertility"}, "y": {"scale": "y", "field": "inter_life_expect", "offset": -7}, "fillOpacity": [ {             "test": "datum.country==timeline.country || indata('trackCountries', datum.country, 'country')", "value": 0.75 },           {"value": 0} ]       }      }    },    {      "name": "point", "type": "symbol", "from": {"data": "interpolate"}, "properties": { "enter": { "fill": {"scale": "c", "field": "this.cluster"}, "size": {"value": 150} },       "update": { "x": {"scale": "x", "field": "inter_fertility"}, "y": {"scale": "y", "field": "inter_life_expect"}, "fillOpacity": [ {             "test": "datum.country==timeline.country || indata('trackCountries', datum.country, 'country')", "value": 1 },           {"value": 0.5} ]       },        "hover": { "cursor": {"value": "pointer"} }     }    }  ] }