block by rveciana 7161183

Touristic establishments by EUROSTAT NUTS regions

Full Screen

This example belongs to the GeoExamples blog http://geoexamples.blogspot.com/2013/10/using-eurostats-data-with-d3js.html

The NUTS classification (Nomenclature of territorial units for statistics) is a hierarchical system for dividing up the economic territory of the EU. Many of the EUROSTAT data is relative to these regions, and this data is a good candidate to be mapped.

The problem is that EUROSTAT provides some shapefiles in one hand, but without the actual names for the regions, nor other information, and some tables with the name and population for every region. This data has to be joined to be able to map properly.

In this example, the number of establishments, bedrooms and bed-places data has been represented. Since the data gives absolute values for regions that have different sizes and populations, the map represents the number of establishments for every 10000 inhabitants. The values from the scale go from 0 (dark blue) to 30 (bright red).

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>Number of establishments, bedrooms and bed-places - NUTS 3 regions</title>
<style>

.background {
  fill: #fff;
  stroke: #ccc;
}

.tooltip{ background-color:rgba(200,200,200,0.5);;
          margin: 10px;
          height: 90px;
          width: 150px;
          padding-left: 10px; 
          padding-top: 10px;
    -webkit-border-radius:10px;
    -moz-border-radius:10px;
    border-radius:10px;
        }
</style>
<body>
<h2>Number of establishments, bedrooms and bed-places - NUTS 3 regions</h2>
<div id="map"></div>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script type="text/javascript" src="./tooltip.js"></script>
<script type="text/javascript" src="./legend.js"></script>
<script>
var width = 600,  
    height = 600;  
  
var projection = d3.geo.stereographic()  
    .center([3.9,43.0])  
    .scale(1000)  
    .translate([width / 4 , height / 2]); 

var path = d3.geo.path()  
    .projection(projection);

var svg = d3.select("#map").append("svg")
    .attr("width", 960)
    .attr("height", 500);

var domain = [0,30]
var color = d3.scale.linear().domain(domain).range(['blue', 'red']);

d3.csv("tour_cap_nuts3_1_Data.csv", function(stats) {
  data = {};
  stats.forEach(function(d) {
    if (d.TIME == 2010){
      data[d.GEO] = d.Value.replace(",",""); //Thousands is a comma!
    }
  });

d3.json("/rveciana/raw/5919944/regions.json", function(error, europe) {
	svg.selectAll(".region")
	.data(topojson.feature(europe, europe.objects.regions).features)
  .enter()
    .append("path")
    .filter(function(d) { return !isNaN(parseFloat(data[d.properties.NUTS_ID])); }) 
      .attr("class", "region")
      .attr("d", path)
      .style("stroke", "#999")
      .style("stroke-width", 0.2)
      .style("fill", function(d) {
        if (!isNaN(parseFloat(data[d.properties.NUTS_ID])))

          return color(10000*data[d.properties.NUTS_ID]/d.properties.POPULATION);
        else
          return "#999";
      })
      .style("opacity", function(d){
        if (!isNaN(parseFloat(data[d.properties.NUTS_ID])))
          return 1;
        else
          return 0;
      })
      
      .call(d3.helper.tooltip(function(d, i){return tooltipText(d);}));


    function tooltipText(d){
           if (isNaN(parseFloat(data[d.properties.NUTS_ID]))) {
            var beds = "No Data";
           } else {
            var beds = data[d.properties.NUTS_ID];
           }
           return "<b>" + d.properties.NAME + "</b>"
                  + "<br/> pop: " + d.properties.POPULATION 
                  + "<br/> beds: " + beds;
      }
    svg.call(legend({width:300, posx: 100, posy:400, elements: 16, domain: domain, title:"Number of establishments / 10000 inhabitants"}));
});
});
</script>


<footer>Source: <a href="//epp.eurostat.ec.europa.eu/portal/page/portal/crime/data/database">eurostat</a></footer>

legend.js

var legend = function(accessor){
    return function(selection){
      
      //Draw the legend for the map
      var legend = selection.append("g");
      var legendText = accessor.title;
      var numSquares = accessor.elements;
      var xLegend = 0;
      var yLegend = 0;
      var widthLegend = 400;
      
      var title_g = legend.append("g");
      var values_g = legend.append("g");
      
      var legendTitle = title_g.append("text")
        .text("Legend")
        .attr("font-family", "sans-serif")
        .attr("font-size", "18px")
        .attr("fill", "black");
        var bbox = legendTitle.node().getBBox();
        legendTitle.attr("x", xLegend + widthLegend/2 - bbox.width/2);
        legendTitle.attr("y", yLegend + 20);
        
      var legendTextEl = title_g.append("text")
        .text(legendText)
        .attr("y", yLegend + 75)
        .attr("font-family", "sans-serif")
        .attr("font-size", "14px")
        .attr("fill", "black");
      var bbox = legendTextEl.node().getBBox();
      legendTextEl.attr("x", xLegend + widthLegend/2 - bbox.width/2);

      for (i=0; i<numSquares; i++){
        values_g.append("rect")
          .attr("x", xLegend + (i+0.1*i/numSquares)*(widthLegend/numSquares))
          .attr("y", yLegend + 25)
          .attr("width", (widthLegend/numSquares)*0.9)
          .attr("height", 20)
          .attr("fill", color(accessor.domain[0] + i * accessor.domain[1]/(numSquares-1)));
        var value_text = values_g.append("text")
          .text(accessor.domain[0] + i * accessor.domain[1]/(numSquares-1))
          .attr("y", yLegend + 55)
          .attr("font-family", "sans-serif")
          .attr("font-size", "12px")
          .attr("fill", "black");
        var bbox = value_text.node().getBBox();
        value_text
          .attr("x", xLegend + (i+0.1*i/numSquares)*(widthLegend/numSquares) + (widthLegend/numSquares)*(0.9/2)- bbox.width/2);

      }
      var scale = accessor.width / 400;
      legend.attr("transform","translate("+accessor.posx+","+accessor.posy+") scale("+scale+") ");

};
};

tooltip.js

d3.helper = {};

d3.helper.tooltip = function(accessor){
    return function(selection){
        var tooltipDiv;
        var bodyNode = d3.select('body').node();
        selection.on("mouseover", function(d, i){
            // Clean up lost tooltips
            d3.select('body').selectAll('div.tooltip').remove();
            // Append tooltip
            tooltipDiv = d3.select('body').append('div').attr('class', 'tooltip');
            var absoluteMousePos = d3.mouse(bodyNode);
            tooltipDiv.style('left', (absoluteMousePos[0] + 10)+'px')
                .style('top', (absoluteMousePos[1] - 15)+'px')
                .style('position', 'absolute') 
                .style('z-index', 1001);
            // Add text using the accessor function
            var tooltipText = accessor(d, i) || '';
            // Crop text arbitrarily
            //tooltipDiv.style('width', function(d, i){return (tooltipText.length > 80) ? '300px' : null;})
            //    .html(tooltipText);
        })
        .on('mousemove', function(d, i) {
            // Move tooltip
            var absoluteMousePos = d3.mouse(bodyNode);
            tooltipDiv.style('left', (absoluteMousePos[0] + 10)+'px')
                .style('top', (absoluteMousePos[1] - 15)+'px');
            var tooltipText = accessor(d, i) || '';
            tooltipDiv.html(tooltipText);
        })
        .on("mouseout", function(d, i){
            // Remove tooltip
            tooltipDiv.remove();
        });

    };
};