Skip to content

Instantly share code, notes, and snippets.

@radbrt
Last active September 26, 2015 20:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save radbrt/c728f5bd29f3d3e11d81 to your computer and use it in GitHub Desktop.
Save radbrt/c728f5bd29f3d3e11d81 to your computer and use it in GitHub Desktop.
European earnings

#European earnings Click on a country to see earnings for the tree Structure of Earnings surveys collected by Eurostat (2002, 2006, 2010). The chloropleth map displays earnings from latest year. Unfortunately, many countries do not have data for 2002 (other datasets are being explored).

Choose between nominal Euros and purchasing power adjusted figures. Unfortunately the barchart doesn't update automatically upon changing between the two.

Data from Eurostat, map blatantly borrowed from https://gist.github.com/Hedva/8226636.

Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Diverse</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="json-stat.js" ></script>
<style type="text/css">
body {
background-color: #fff;
font-family: "Helvetica Neue", "sans-serif";
font-size: 11px;
}
svg.mainFrame {
background-color: #6baed6;
}
svg path {
stroke: #4499aa;
stroke-width: 0.5px;
}
svg path:hover {
fill: orange;
cursor: pointer;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: "Helvetica Neue", "sans-serif";
font-size: 11px;
}
#tooltip {
position: absolute;
top: 15px;
left: 530px;
z-index: 10;
padding: 5px;
width: 420px;
height: 250px;
color: #CC5D0E;
font-family: sans-serif;
font-size: 12px;
font-weight: bold;
text-align: center;
background-color: rgba(100, 110, 110, 0.75);
opacity: 0;
pointer-events: none;
}
.xlabel {
text-align: center;
}
.bar {
text-align: center;
}
#tooltip.visible {
opacity: 1;
}
/* #radio {
position: absolute;
right: 15px;
bottom: 15px;
z-index: 10;
}*/
</style>
</head>
<body>
<div id="tooltip"></div>
<form id="radio">
<input type="radio" name="group-stack" value="eur" checked>EUR<br>
<input type="radio" name="group-stack" value="pps">PPS
</form>
<script>
var bh = 250;
var bw = 420;
var bp = {t: 10, r: 50, b: 15, l: 10 };
var map;
var nFormat = d3.format(",");
var w = 960;
var h = 500;
d3.select("#radio")
.style("position", "absolute")
.style("left", "900px")
.style("top", "460px");
var projection = d3.geo.equirectangular()
.center([29, 52])
.translate([ w/2, h/2 ])
.scale([ 650 ])
;
var path = d3.geo.path()
.projection(projection);
d3.json("europe3.json", function(json) {
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h)
.attr("class", "mainFrame")
;
JSONstat("http://ec.europa.eu/eurostat/wdds/rest/data/v1.1/json/en/earn_ses_monthly?nace_r2=B-S_X_O&indic_se=ERN_MN_EUR&indic_se=ERN_MN_PPS&sex=T&precision=0&isco08=TOTAL&age=TOTAL&worktime=FT", function() {
dt=this.Dataset(0).toTable({ type : "arrobj", content : "id" })
dt2=d3.nest()
.key(function(d) { return d.geo; })
.entries(dt);
//console.log(dt2);
for (i=0; i<dt2.length; i++) {
for (j=0; j<json.features.length; j++) {
if(json.features[j].id==dt2[i].key) {
json.features[j].ERN_MN_EUR=dt2[i].values[dt2[i].values.length-1].value;
json.features[j].pps=dt2[i].values.filter(function(d) { return d.indic_se=="ERN_MN_PPS"; });
json.features[j].eur=dt2[i].values.filter(function(d) { return d.indic_se=="ERN_MN_EUR"; });
}
}
}
var color=d3.scale.quantize()
.domain([
// d.values[d.values.length-1] pattern to get latest year (if correctly sorted...)
d3.min(dt2, function(d) { return d.values[d.values.length-1].value; }),
d3.max(dt2, function(d) { return d.values[d.values.length-1].value; })
])
.range(["#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#005a32"]);
var groups = svg.selectAll("g")
.data(json.features)
.enter()
.append("g")
.attr("class", "gr");
//console.log(json.features);
var map = groups.append("path")
.attr("d", path)
.attr("class", "euCountries")
.attr("fill", function(d) {
if(d.eur) {
return color(d.eur[d.eur.length-1].value);
} else {
return "#ccc";
}
});
var yScale = d3.scale.linear()
.domain([
//OK, this gets convoluted... to be improved. Needed to nest through countries and years.
0,
d3.max(dt2, function(d) {
return d3.max(d.values, function(d) { return d.value; }); })
])
.range([(bh-bp.b), bp.b]);
var xScale = d3.scale.ordinal()
.domain(d3.range(dt2[0].values.filter(function(d) { return d.indic_se=="ERN_MN_EUR"; }).length))
.rangeRoundBands([ bp.r, bw - bp.r ], 0.05);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("right")
;
var d0 = d3.select("#tooltip");
var divtip = d0
.append("svg")
.attr("width", bw)
.attr("height", bh)
;
var barGroups = divtip.selectAll("g")
.data(json.features[0].pps)
.enter()
.append("g")
.attr("class", "bar")
.attr("width", xScale.rangeBand());
var bar = barGroups
.append("rect")
.attr("class", "barGroups")
.style("fill", "#cc9900")
.attr("width", xScale.rangeBand() )
.attr("y", function(d) { return bh; })
.attr("height", function(d) { return 0; })
;
var yLine = divtip.append("g")
.attr("class", "y axis")
.call(yAxis)
.attr("transform", "translate(" + (bw-bp.r) + ", 0)");
yLine.append("text").text("Mean monthly earnings (€)")
.attr("transform", "rotate(-90), translate(-" + (bh/2) + ",50)")
.attr("text-anchor", "middle")
;
barGroups.append("text")
.attr("class", "xlabel")
.attr("x", function(d, i) { return xScale(i) + (xScale.rangeBand()/2); })
.attr("y", bh)
.attr("width", xScale.rangeBand() )
.text(function(d) { return d.time; })
.attr("text-anchor", "middle")
;
var title = d0.append("div")
.attr("class", "xBoxClass")
.style("position", "absolute")
.style("color", "#333")
.style("top", "5px")
.style("left", "5px")
.style("font-size", "20px");
d3.select("#radio").on("change", function() {
if (d3.select('input[name="group-stack"]:checked').node().value=='eur'){
map
.transition()
.duration(500)
.delay(300)
.attr("fill", function(d) {
if(d.eur) {
return color(d.eur[d.eur.length-1].value);
} else {
return "#ccc";
}
})
} else {
map
.transition()
.duration(500)
.delay(300)
.attr("fill", function(d) {
if(d.pps) {
return color(d.pps[d.pps.length-1].value);
} else { return "#ccc"; }
})
}
d3.select("#tooltip")
.transition()
.duration(300)
.style("opacity", 0.5)
;
});
map.on("click", function(d) {
if (d3.select('input[name="group-stack"]:checked').node().value=='eur' && d.eur) {
// ONLY UPDATE IF HAZ DATA
d3.select("#tooltip")
.transition()
.duration(300)
.style("opacity", 1);
title.text(d.properties.name);
bar.data(d.eur)
.transition()
.duration(500)
.delay(function(d, i) { return i*100; })
.attr("y", function(d) { return yScale(d.value); })
.attr("x", function(d, i) { return xScale(i); })
.attr("height", function(d) { return (bh-bp.b)-yScale(d.value); });
} else if (d3.select('input[name="group-stack"]:checked').node().value=='pps' && d.pps) {
d3.select("#tooltip")
.transition()
.duration(300)
.style("opacity", 1);
title.text(d.properties.name);
bar.data(d.pps)
.transition()
.duration(500)
.delay(function(d, i) { return i*100; })
.attr("y", function(d) { return yScale(d.value); })
.attr("x", function(d, i) { return xScale(i); })
.attr("height", function(d) { return (bh-bp.b)-yScale(d.value); });
}
});
});
});
</script>
</body>
</html>
/*
JSON-stat Javascript Toolkit v. 0.8.3
http://json-stat.org
https://github.com/badosa/JSON-stat
Copyright 2015 Xavier Badosa (http://xavierbadosa.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the License for the specific language governing
permissions and limitations under the License.
*/
function JSONstat(t,e){return window===this?new JSONstat.jsonstat(t,e):void 0}var JSONstat=JSONstat||{}
JSONstat.version="0.8.3",function(){"use strict"
function t(t){return"[object Array]"===Object.prototype.toString.call(t)}function e(e,n){var i,s,r,l,a=function(t,e){var n,i,s=e!==!1
if(window.XDomainRequest&&/^(http(s)?:)?\/\//.test(t)){if(!s)return
i=new XDomainRequest,i.onload=function(){n=JSON.parse(i.responseText),e.call(JSONstat(n))},i.open("GET",t),i.send()}else if(i=new XMLHttpRequest,i.onreadystatechange=function(){if(4===i.readyState){var t=i.status
n=t&&i.responseText&&(t>=200&&300>t||304===t)?JSON.parse(i.responseText):null,s&&e.call(JSONstat(n))}},i.open("GET",t,s),i.send(null),!s)return n},o=function(e,n){var i,s=[]
if("string"==typeof e&&(e=[e]),t(e)){if(e.length===n)return e
if(1===e.length){for(i=0;n>i;i++)s.push(e[0])
return s}}for(i=0;n>i;i++){var r=void 0===e[i]?null:e[i]
s.push(r)}return s}
if(this.length=0,this.id=[],null!==e&&void 0!==e)switch(this["class"]=e["class"]||"bundle",this["class"]){case"bundle":var u=[],h=0
if(this.error=null,this.length=0,"string"==typeof e&&e.length>0&&(e=a(e,"function"==typeof n?n:!1)),null===e||"object"!=typeof e)return this["class"]=null,void(void 0===e&&(delete this.id,delete this["class"],delete this.error,delete this.length))
if(e.hasOwnProperty("error"))return void(this.error=e.error)
if("dataset"===e["class"]||"collection"===e["class"])return JSONstat(e)
for(s in e)h++,u.push(s)
this.__tree__=e,this.length=h,this.id=u
break
case"dataset":e.hasOwnProperty("__tree__")||(delete e["class"],e={__tree__:e}),this.__tree__=i=e.__tree__,this.label=i.label||null,this.note=i.note||null,this.link=i.link||null,this.href=i.href||null,this.updated=i.updated||null,this.source=i.source||null,this.extension=i.extension||null
var f,c=0
if(i.hasOwnProperty("value")&&t(i.value))c=i.value.length
else if(i.hasOwnProperty("status")&&t(i.status))c=i.status.length
else if(i.hasOwnProperty("dimension")){var d=i.dimension.size,p=1
for(f=d.length;f--;)p*=d[f]
c=p}if(this.value=o(i.value,c),this.status=i.hasOwnProperty("status")?o(i.status,c):null,i.hasOwnProperty("dimension")){if(!t(i.dimension.id)||!t(i.dimension.size)||i.dimension.id.length!=i.dimension.size.length)return
var v=i.dimension,g=v.role||null,y=v.id,_=v.size.length,b=function(t){g.hasOwnProperty(t)||(g[t]=null)}
if(this.length=_,this.id=y,g&&(b("time"),b("geo"),b("metric"),b("classification")),g&&null===g.classification){var m=[],w=["time","geo","metric"],O=function(t,e){for(var n=e.length;n--;)if(t===e[n])return!0
return!1}
for(f=0;3>f;f++){var x=g[w[f]]
null!==x&&(m=m.concat(x))}for(g.classification=[],f=0;_>f;f++)O(y[f],m)||g.classification.push(y[f])
0===g.classification.length&&(g.classification=null)}this.role=g,this.n=c
for(var S=0,k=this.length;k>S;S++)if(v[v.id[S]].category.hasOwnProperty("index")){if(t(v[v.id[S]].category.index)){var P={},D=v[v.id[S]].category.index
for(r=D.length,l=0;r>l;l++)P[D[l]]=l
v[v.id[S]].category.index=P}}else{var j=0
v[v.id[S]].category.index={}
for(s in v[v.id[S]].category.label)v[v.id[S]].category.index[s]=j++}}else this.length=0
break
case"dimension":i=e.__tree__
var J=[],N=i.category
if(!e.hasOwnProperty("__tree__")||!i.hasOwnProperty("category"))return
if(!N.hasOwnProperty("label")){N.label={}
for(s in N.index)N.label[s]=s}for(s in N.index)J[N.index[s]]=s
this.__tree__=i,this.label=i.label||null,this.note=i.note||null,this.link=i.link||null,this.href=i.href||null,this.id=J,this.length=J.length,this.role=e.role,this.hierarchy=N.hasOwnProperty("child"),this.extension=i.extension||null
break
case"category":var T=e.child
this.id=T,this.length=null===T?0:T.length,this.index=e.index,this.label=e.label,this.note=e.note||null,this.unit=e.unit,this.coordinates=e.coord
break
case"collection":if(this.length=0,this.label=e.label||null,this.note=e.note||null,this.link=e.link||null,this.href=e.href||null,this.updated=e.updated||null,this.source=e.source||null,this.extension=e.extension||null,null!==this.link&&e.link.item){var z=e.link.item
if(this.length=t(z)?z.length:0,this.length)for(l=0;l<this.length;l++)this.id[l]=z[l].href}}}e.prototype.Item=function(t){if(null===this||"collection"!==this["class"]||!this.length)return null
if("number"==typeof t)return t>this.length||0>t?null:this.link.item[t]
var e,n=[]
if("object"==typeof t){if(!t["class"]&&!t.follow)return null
t["class"]?e=function(t,e,i){i["class"]===t.link.item[e]["class"]&&n.push(t.link.item[e])}:t.follow&&(e=function(t,e){n.push(JSONstat(t.id[e]))})}else e=function(t,e){n.push(t.link.item[e])}
for(var i=0;i<this.length;i++)e(this,i,t)
return n},e.prototype.Dataset=function(t){if(null===this)return null
if("dataset"===this["class"])return void 0!==t?this:[this]
if("bundle"!==this["class"])return null
if(void 0===t){for(var n=[],i=0,s=this.id.length;s>i;i++)n.push(this.Dataset(this.id[i]))
return n}if("number"==typeof t){var r=this.id[t]
return void 0!==r?this.Dataset(r):null}var l=this.__tree__[t]
return void 0===l?null:new e({"class":"dataset",__tree__:l})},e.prototype.Dimension=function(t){var n,i=[],s=this.id.length,r=function(t,e){var n=t.role
if(null!==n)for(var i in n)for(var s=null!==n[i]?n[i].length:0;s--;)if(n[i][s]===e)return i
return null}
if(null===this||"dataset"!==this["class"])return null
if(void 0===t){for(n=0;s>n;n++)i.push(this.Dimension(this.id[n]))
return i}if("number"==typeof t){var l=this.id[t]
return void 0!==l?this.Dimension(l):null}var a=this.__tree__.dimension
if(void 0===a)return null
if("object"==typeof t){if(t.hasOwnProperty("role")){for(n=0;s>n;n++){var o=this.id[n]
r(a,o)===t.role&&i.push(this.Dimension(o))}return void 0===i[0]?null:i}return null}var u=a[t]
return void 0===u?null:new e({"class":"dimension",__tree__:u,role:r(a,t)})},e.prototype.Category=function(t){if(null===this||"dimension"!==this["class"])return null
if(void 0===t){for(var n=[],i=0,s=this.id.length;s>i;i++)n.push(this.Category(this.id[i]))
return n}if("number"==typeof t){var r=this.id[t]
return void 0!==r?this.Category(r):null}var l=this.__tree__.category
if(void 0===l)return null
var a=l.index[t]
if(void 0===a)return null
var o=l.unit&&l.unit[t]||null,u=l.coordinates&&l.coordinates[t]||null,h=l.child&&l.child[t]||null,f=l.note&&l.note[t]||null
return new e({"class":"category",index:a,label:l.label[t],note:f,child:h,unit:o,coord:u})},e.prototype.Data=function(e){var n,i,s=[],r=function(t){for(var e in t)if(t.hasOwnProperty(e))return e},l=function(t,e){for(var n=[],i=t.dimension,s=i.id,l=0,a=s.length;a>l;l++){var o=s[l],u=e[o]
n.push("string"==typeof u?u:1===i.size[l]?r(i[o].category.index):null)}return n}
if(null===this||"dataset"!==this["class"])return null
if(void 0===e){for(i=this.value.length,n=0;i>n;n++)s.push(this.Data(n))
return s}if("number"==typeof e){var a=this.value[e]
return void 0!==a?{value:a,status:this.status?this.status[e]:null}:null}var o=this.__tree__,u=o.dimension.size,h=u.length
if(t(e)){if(this.length!==e.length)return null
var f=1,c=0,d=[],p=[]
for(n=0;h>n;n++)if(void 0!==e[n]){if("number"!=typeof e[n]||e[n]>=u[n])return null
f*=n>0?u[h-n]:1,c+=f*e[h-n-1]}else d.push(n),p.push(u[n])
if(d.length>1)return null
if(1===d.length){for(var v=0,g=p[0];g>v;v++){var y=[]
for(n=0;h>n;n++)y.push(n!==d[0]?e[n]:v)
s.push(this.Data(y))}return s}return{value:this.value[c],status:this.status?this.status[c]:null}}var _=l(o,e),b=[],m=o.dimension
for(i=_.length,n=0;i>n;n++)b.push(m[m.id[n]].category.index[_[n]])
return this.Data(b)},e.prototype.toTable=function(t,e){if(null===this||"dataset"!==this["class"])return null
1==arguments.length&&"function"==typeof t&&(e=t,t=null)
var n,i,s,r,l,a=this.__tree__
if(t=t||{field:"label",content:"label",vlabel:"Value",slabel:"Status",type:"array",status:!1},"function"==typeof e){n=this.toTable(t)
var o=[],u="array"!==t.type?0:1,h="object"!==t.type?n.slice(u):n.rows.slice(0)
for(l=h.length,i=0;l>i;i++){var f=e.call(this,h[i],i)
void 0!==f&&o.push(f)}return"object"===t.type?{cols:n.cols,rows:o}:("array"===t.type&&o.unshift(n[0]),o)}if("arrobj"===t.type){n=this.toTable({field:"id",content:t.content,status:t.status})
var c=[],d=n.shift()
for(l=n.length,i=0;l>i;i++){var p={}
for(s=n[i].length;s--;)p[d[s]]=n[i][s]
c.push(p)}return c}var v,g,y,_,b="id"===t.field
if("object"===t.type){var m="number"==typeof this.value[0]||null===this.value[0]?"number":"string"
v=function(t,e){var n=b&&t||e||t
z.push({id:t,label:n,type:"string"})},g=function(t,e,n){var i=b&&"value"||t||"Value",s=b&&"status"||e||"Status"
n&&z.push({id:"status",label:s,type:"string"}),z.push({id:"value",label:i,type:m})},y=function(t){B.push({v:t})},_=function(t){B.push({v:t}),V.push({c:B})}}else v=function(t,e){var n=b&&t||e||t
z.push(n)},g=function(t,e,n){var i=b&&"value"||t||"Value",s=b&&"status"||e||"Status"
n&&z.push(s),z.push(i),T.push(z)},y=function(t){B.push(t)},_=function(t){B.push(t),T.push(B)}
var w=a.dimension,O=w.id,x=O.length,S=w.size
if(x!=S.length)return!1
var k=[],P=1,D=1,j=[],J=[],N=[],T=[],z=[],V=[]
for(i=0;x>i;i++){var q=O[i],C=w[q].label
v(q,C),P*=S[i],D*=S[i]
var R=[]
for(s=0;s<S[i];s++)for(var X in w[O[i]].category.index)if(w[O[i]].category.index[X]===s){var E="id"!==t.content&&w[O[i]].category.label?w[O[i]].category.label[X]:X
R.push(E)}k.push(R),j.push(D)}for(g(t.vlabel,t.slabel,t.status),l=k.length,i=0;l>i;i++){for(var G=[],A=0,H=k[i].length;H>A;A++)for(var I=0;I<P/j[i];I++)G.push(k[i][A])
J.push(G)}for(l=J.length,i=0;l>i;i++){var L=[],M=0
for(r=0;P>r;r++)L.push(J[i][M]),M++,M===J[i].length&&(M=0)
N.push(L)}for(r=0;P>r;r++){var B=[]
l=J.length
for(var F=0;l>F;F++)y(N[F][r])
t.status&&y(this.status?this.status[r]:null),_(this.value[r])}return"object"===t.type?{cols:z,rows:V}:T},e.prototype.node=function(){return this.__tree__},e.prototype.toString=function(){return this["class"]},e.prototype.toValue=function(){return this.length},JSONstat.jsonstat=e}()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment