Skip to content

Instantly share code, notes, and snippets.

@hotzeplotz
Last active August 29, 2015 14:10
Show Gist options
  • Select an option

  • Save hotzeplotz/0199a17276be22465ad5 to your computer and use it in GitHub Desktop.

Select an option

Save hotzeplotz/0199a17276be22465ad5 to your computer and use it in GitHub Desktop.
European MetroMonitor - Workshop
/**
* Turn a CSV file with longitude and latitude columsn into a GeoJSON data structure
*/
function csv_to_geojson(csv_data) {
var full_data = {
type: "FeatureCollection",
features: []
};
full_data.features = _.map(csv_data,
function(city_row, key, list) {
return {
id: city_row.MetroRegion,
properties: city_row,
type: "Feature",
geometry: {
type: "Point",
coordinates: [
city_row.Longitude, city_row.Latitude
]
}
};
});
return full_data;
}
/**
* Prepare and build the map!
*/
function make_map(map_data) {
L.mapbox.accessToken = 'pk.eyJ1IjoibHNlY2l0aWVzIiwiYSI6IjJ6ZjA5UGMifQ.8y1yiWucAic55wg5YoiTGQ';
var map = L.mapbox.map(map_data.map_id, 'lsecities.k37p4f29', {
attributionControl: false,
infoControl: true
})
.setView(map_data.initial_position, map_data.initial_zoom),
$metro_tooltip = $('.metro-tooltip');
/*****
* Uncomment the following line to enable Leaflet-Hash */
// var hash = new L.Hash(map);
/**
* Show tooltip
*/
function enterLayer(){
var metroName = this.feature.properties.MetroRegion,
val_at_timepoint = map_data.time_var_value_function(this.feature.properties[map_data.time_var]),
val_growth = Math.round(this.feature.properties[map_data.growth_var] * 100) / 100;
$metro_tooltip.html(
'<h3>' + metroName + '</h3>' +
'<dl>' +
'<dt>' + map_data.time_var_label + '</dt>' +
'<dd>' + val_at_timepoint + ' ' + map_data.time_var_unit + '</dd>' +
'<dt>' + map_data.growth_var_label + '</dt>' +
'<dd>' + val_growth + ' ' + map_data.growth_var_unit + '</dd>' +
'</dl>'
).show();
this.bringToFront();
this.setStyle({
weight: 2,
opacity: 1
});
}
/**
* Hide tooltip
*/
function leaveLayer(){
$metro_tooltip.hide();
this.bringToBack();
this.setStyle({
weight: 1,
opacity: 0.7
});
}
/**
* Create a new layer with a special pointToLayer function
* which is used to generate scaled points
*/
var citiesLayer = L.geoJson(null, {
pointToLayer: scaledPoint,
onEachFeature: function(feature, layer) {
layer.on({
mouseover: enterLayer,
mouseout: leaveLayer
});
}
})
.addTo(map);
var fill; // attach function later within d3.json();
function citiesSize(feature) {
return { radius: pointRadius(feature)};
}
function pointColor(feature) {
return fill(feature.properties[map_data.growth_var]);
}
function pointRadius(feature) {
var val_value = +feature.properties[map_data.time_var];
return d3.scale.sqrt()
.domain([0, 2e4])
.range([0, 20])(val_value) * 1.5;
}
function scaledPoint(feature, latlng) {
return L.circleMarker(latlng, {
radius: pointRadius(feature),
fillColor: pointColor(feature),
fillOpacity: 0.75,
weight: 0.5,
color: '#fff'
});
}
// Request our data and add it to the citiesLayer.
d3.csv(map_data.data_file, function(err, csv_data) {
var data = csv_to_geojson(csv_data);
var min = d3.min(data.features.map(function(d) { return d.properties[map_data.growth_var]; }));
var max = d3.max(data.features.map(function(d) { return d.properties[map_data.growth_var]; }));
fill = map_data.circles_fill(min, max);
citiesLayer.addData(data);
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>European MetroMonitor</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<!-- include MapBox stylesheet -->
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.1.4/mapbox.css' rel='stylesheet' />
<!-- include our own stylesheet -->
<link href='style.css' rel='stylesheet' />
</head>
<body>
<div id='map' class='dark'></div>
<div class="metro-tooltip"></div>
<!-- include external libraries: MapBox, D3 and jQuery -->
<script src='//api.tiles.mapbox.com/mapbox.js/v2.1.4/mapbox.js'></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/d3/3.4.6/d3.min.js' charset="utf-8"></script>
<script src='//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js'></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- include our own JavaScript code -->
<script src='data-visualization.js'></script>
<script>
make_map({
data_file: 'http://bl.ocks.org/hotzeplotz/raw/1bef0638b3ba0d2e01b5/43259ee8f3bae048cc42a4d94df33a9b77f3d532/dataset.csv',
map_id: 'map',
/*****
* to change the initial centering of the map to a specific european city,
* search for its latitude and longitude and update the initial_position
* setting below; try your dream summer holiday destination! :)
* e.g. google 'palermo lat lon' and use the values given by google,
* rounding them to two decimal digits [ 38.11, 13.36 ]*/
initial_position: [51.51, 12.00],
/*****
* to start with a closer zoom, increase the initial_zoom setting below
* to a value above 4 (e.g. try 6 or 7) */
initial_zoom: 4,
/*****
* to plot a variable other than POPTOTT_2012 (metro region's population in 2012)
* for the radius of circles, choose one of the dataset's variables here:
* https://gist.githubusercontent.com/hotzeplotz/1bef0638b3ba0d2e01b5/raw/variables.txt
* and set it as time_var below; don't forget to update
* time_var_label, time_var_unit and time_var_value_function time accordingly! */
time_var: 'POPTOTT_2012',
time_var_label: 'Population (2012)',
time_var_unit: 'million',
time_var_value_function: function(val) {
return (val / 1000).toFixed(2);
},
time_var_extent: function(data, variable) { /* return [min, max] for variable across data */ },
/*****
* to plot a variable other than EMP_2012_GR (metro region's employment growth rate in 2012)
* for the colour of circles, choose one of the dataset's variables here:
* https://gist.githubusercontent.com/hotzeplotz/1bef0638b3ba0d2e01b5/raw/variables.txt
* and set it as growth_var below; don't forget to update
* growth_var_label and growth_var_unit accordingly! */
growth_var: 'GVA_2012_GR',
growth_var_label: 'GVA growth rate (2012)',
growth_var_unit: '%',
/*****
* default circles_fill, as used in European MetroMonitor app
*/
// circles_fill: function(min, max) {
// return d3.scale.linear()
// .domain([-10, -5, 0, 5, 10])
// .range(["#2B83BA", "#ABDDA4", "#FFFFBF", "#FDAE61", "#D7191C"]);
//}
/*****
* use the circle_fill setting below to only highlight which cities have
* negative growth and which have positive growth for the given year
*/
circles_fill: function(min, max) {
return d3.scale.threshold()
.domain([ 0 ])
.range([ 'red', 'green']);
}
/*****
* or - just for fun - colour circles according to latitude with the
* circle_fill setting below; hint: you also need to set the
* growth_var above to "Latitude" (mind the capital L)
*/
//circles_fill: function(min, max) {
// return d3.scale.linear()
// .domain([ 0, 90 ])
// .range([ 'red', 'blue']);
//}
/*****
* use the circle_fill setting below to only highlight which cities have
* negative growth and which have positive growth for the given year
*/
// circles_fill: function(min, max) {
// return d3.scale.threshold()
// .domain([ 0 ])
// .range([ 'red', 'green']);
// }
/*****
* or use the circles_fill setting below for a different fill style;
* try using http://colorbrewer2.org/ to generate a colour palette
*/
// circles_fill: function(min, max) {
// return d3.scale.threshold()
// .domain([ -10 , -5, 0, 5, 10 ])
// .range(['rgb(242,240,247)','rgb(203,201,226)','rgb(158,154,200)','rgb(117,107,177)','rgb(84,39,143)']);
// }
});
</script>
</body>
</html>
body {
margin:0;
padding:0;
font-family: sans-serif;
}
#map {
position:absolute;
top:0;
bottom:0;
width:100%;
}
.metro-tooltip{
position: absolute;
top: 2em;
right: 1em;
z-index: 6;
background: rgba(0,0,0,.75);
color: white;
padding: .5em .75em;
font-size: .85em;
display: none;
}
.leaflet-tile-pane {
opacity: 0.6;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment