OpeNER - Places with categories (Paris, bubble binning)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Setup | |
width = 960 | |
height = 500 | |
svg = d3.select('svg') | |
# append a group for zoomable content | |
zoom_group = svg.append('g') | |
# define a zoom behavior | |
zoom = d3.behavior.zoom() | |
.scaleExtent([1,4]) # min-max zoom | |
.on('zoom', () -> | |
# whenever the user zooms, | |
# modify translation and scale of the zoom group accordingly | |
zoom_group.attr('transform', "translate(#{zoom.translate()})scale(#{zoom.scale()})") | |
) | |
# bind the zoom behavior to the main SVG | |
svg.call(zoom) | |
# Lambert equal-area projection - EU standard for statistical maps | |
projection = d3.geo.azimuthalEqualArea() | |
.clipAngle(180 - 1e-3) | |
.scale(280000) | |
.rotate([-2.340087890624995, -48.858643406835796, 0]) | |
.translate([width / 2, height / 2]) | |
.precision(0.1) | |
path_generator = d3.geo.path() | |
.projection(projection) | |
categories = ['restaurant', 'attraction', 'poi', 'accommodation'] | |
classes = categories.length | |
colorify = d3.scale.category10() | |
.domain(categories) | |
geo_url = 'http://wafi.iit.cnr.it/webvis/tmp/paris.topojson' | |
data_url = 'http://wafi.iit.cnr.it/webvis/tmp/paris.json' | |
d3.json geo_url, (geo) -> | |
regions = topojson.feature(geo, geo.objects['conseils-quartiers']) | |
zoom_group.selectAll('.region') | |
.data(regions.features) | |
.enter().append('path') | |
.attr('class', 'region') | |
.attr('d', path_generator) | |
zoom_group.append('path') | |
.attr | |
class: 'water' | |
transform: 'translate(45,-206) scale(1.1)' | |
d: "m 341.4375,154.84375 -27.78125,13.125 -27.78125,10.625 -8.09375,5.53125 -21.71875,16.6875 -10.09375,8.0625 -16.15625,10.625 -14.65625,6.0625 -19.6875,10.09375 -16.65625,8.59375 -8.59375,8.0625 -12.625,19.71875 -10.625,10.09375 -14.125,21.21875 -13.65625,18.1875 L 99,343.75 83.84375,361.9375 c 0,0 -13.146098,16.66211 -14.15625,19.1875 -1.010153,2.52538 -5.03125,17.65625 -5.03125,17.65625 l -9.09375,35.875 1.5,7.0625 2.53125,13.65625 -1,15.125 L 56.0625,485.15625 51,495.25 53.03125,515.96875 56.0625,520 l 5.0625,11.625 -1.53125,11.125 5.0625,11.09375 12.625,16.15625 11.625,8.59375 8.0625,1.53125 19.71875,-7.09375 13.625,-6.0625 7.5625,-4.03125 14.65625,-15.15625 12.625,-11.09375 13.65625,-21.21875 9.0625,-13.625 19.21875,-29.3125 L 217.1875,461.4375 235.375,443.75 246.46875,428.59375 249,419 l 9.09375,-10.09375 9.59375,-7.59375 12.125,-5.03125 29.28125,-2.03125 24.75,-0.5 32.84375,15.65625 13.625,6.5625 6.0625,0.5 7.59375,3.53125 11.09375,12.125 13.15625,8.09375 14.625,7.5625 21.71875,12.625 15.65625,15.15625 2.03125,6.5625 15.65625,17.1875 7.5625,10.09375 5.5625,7.5625 c 0,0 21.70859,24.76094 22.71875,26.78125 1.01015,2.0203 17.1875,20.71875 17.1875,20.71875 l 17.15625,17.15625 19.71875,10.625 13.625,6.0625 6.5625,6.5625 -1,12.625 -3.53125,22.71875 2.53125,13.125 9.09375,12.125 7.0625,10.625 4.03125,3.03125 6.5625,9.0625 8.59375,8.59375 4.03125,15.65625 -4.03125,17.1875 -22.71875,55.03125 24.75,-45.4375 5.03125,-22.71875 -0.5,-17.1875 -7.0625,-13.125 -8.59375,-11.625 -10.09375,-10.09375 -7.59375,-8.59375 -6.0625,-8.59375 -0.5,-8.5625 2.53125,-15.15625 2.53125,-17.1875 -2.53125,-4.03125 10.09375,1 15.15625,-2.53125 9.59375,1.53125 10.625,-1.53125 17.15625,3.5625 11.125,-2.03125 10.09375,-1.53125 18.6875,0.53125 -4.53125,-0.53125 -16.6875,-3.53125 -7.0625,1.53125 -8.59375,2.53125 -13.625,-2.53125 -12.625,2.53125 -10.09375,-3.03125 c 0,0 -11.63087,2 -14.15625,2 -2.52538,0 -12.625,-0.5 -12.625,-0.5 L 596.5,594.25 583.875,589.71875 566.6875,580.625 554.0625,569 540.4375,555.875 528.8125,540.71875 513.15625,520.53125 496,498.8125 485.875,487.1875 472.75,473.03125 457.09375,456.375 l -1.5,-5.5625 -1.03125,-6.5625 -14.65625,-7.5625 -13.625,-10.625 -19.6875,-7.0625 -13.125,-5.5625 -11.125,-1.5 L 367.1875,405.375 349,396.78125 l -16.15625,-9.09375 -13.125,0 -10.625,0 -25.25,1.5 -21.21875,7.59375 -9.59375,12.125 -12.625,16.65625 -23.71875,25.75 -24.25,36.375 -20.21875,30.3125 -13.625,19.6875 -9.09375,7.0625 -10.09375,11.625 -10.09375,7.0625 -11.125,6.0625 -12.125,1.03125 L 95.96875,567.5 82.3125,558.40625 75.25,554.34375 67.6875,543.75 l 0,-2.53125 0,-7.5625 -1.53125,-5.5625 -4.53125,-6.5625 -4.03125,-6.5625 -1.03125,-13.65625 3.03125,-10.09375 7.59375,-25.75 -2.53125,-12.625 -3.03125,-16.15625 3.53125,-25.28125 7.5625,-26.75 6.21875,-11.125 3.53125,-5.4375 18.53125,-6.6875 14.15625,-13.625 11.125,-18.1875 15.125,-23.21875 2.9375,-6.3125 -10.5,15.40625 L 123.25,327.5625 116.15625,344.25 99,358.375 l -14.96875,5.8125 1.8125,-2.375 8.84375,-10 18.96875,-20.6875 36.84375,-44.46875 0.625,-1.03125 -6.78125,14.4375 2.625,-3.8125 4.71875,-11.53125 11.96875,-19.78125 12.625,-13.625 27.78125,-15.65625 17.65625,-4.5625 L 241.4375,220 l 28.28125,-22.21875 20.1875,-14.15625 41.4375,-17.65625 10.09375,-11.125 z m 51.78125,262.6875 c 0,0 11.96875,4.11161 13.21875,4.46875 1.25,0.35714 16.25,6.78125 16.25,6.78125 l 6.96875,4.125 c 0.17857,0.71428 1.40625,10.875 1.40625,10.875 0,0 -12.48214,-3.75 -13.375,-5 -0.89285,-1.25 -12.5,-8.03125 -12.5,-8.03125 l -11.96875,-13.21875 z m 39.625,18.21875 9.125,3.9375 11.0625,6.25 0,8.375 -18.21875,-9.28125 c 0,0 -1.96875,-8.38839 -1.96875,-9.28125 z m -363.375,116.625 1.0625,0.6875 21.78125,17.875 10,4.625 c 0,0 -2.125,0.7366 -3.375,1.09375 C 97.6875,577.01339 91.96875,577 91.96875,577 l -7.6875,-4.09375 -8.5625,-8.75 -6.96875,-10.375 0.71875,-1.40625 z" | |
d3.json data_url, (points) -> | |
# hexagonal binning | |
radius = 26 | |
apothem = Math.sqrt(3)/2 * radius | |
hexbin = d3.hexbin() | |
.size([width, height]) | |
.radius(radius) | |
.x((d) -> projection([d.lng, d.lat])[0] ) | |
.y((d) -> projection([d.lng, d.lat])[1] ) | |
bins = _.chain(hexbin(points)) | |
.forEach( (bin) -> | |
bin.classes_count = _.chain(categories) | |
.map( (klass) -> | |
count = bin.filter( (point) -> point.category is klass ).length | |
return { | |
count: count, | |
class: klass | |
} | |
) | |
.value() | |
) | |
.value() | |
max_tot = d3.max(bins, (bin) -> bin.length) | |
max = d3.max(bins, (bin) -> d3.max(bin.classes_count, (count) -> count.count) ) | |
angle = 2*Math.PI / classes | |
# pie chart subplotting | |
subplots = zoom_group.selectAll('.subplot') | |
.data(bins) | |
subplots.enter().append('g') | |
.attr | |
class: 'subplot' | |
transform: (bin) -> "translate(#{bin.x},#{bin.y})" | |
max_dist = apothem / (1+Math.sin(angle/2)) | |
dist_scale = d3.scale.sqrt() | |
.domain([0, max]) | |
.range([0, max_dist]) | |
petals = subplots.selectAll('.petal') | |
.data((bin) -> bin.classes_count) | |
petals.enter().append('circle') | |
.attr | |
class: 'petal' | |
cx: (d, i) -> dist_scale(d.count)*Math.cos(i*angle-Math.PI/2) | |
cy: (d, i) -> dist_scale(d.count)*Math.sin(i*angle-Math.PI/2) | |
r: (d) -> dist_scale(d.count)*Math.sin(angle/2) | |
fill: (count) -> colorify(count.class) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 0; | |
padding: 0; | |
} | |
svg { | |
background: white; | |
} | |
.petal { | |
stroke: white; | |
stroke-width: 1; | |
vector-effect: non-scaling-stroke; | |
} | |
.region { | |
stroke: white; | |
stroke-width: 3px; | |
fill: #DFDFDF; | |
} | |
.graticule { | |
fill: none; | |
stroke-width: 1px; | |
stroke: gray; | |
vector-effect: non-scaling-stroke; | |
} | |
.water { | |
fill: #BEDDF5; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="description" content="OpeNER - Places with categories (Paris, bubble binning)" /> | |
<title>OpeNER - Places with categories (Paris, bubble binning)</title> | |
<link rel="stylesheet" href="index.css"> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/d3.hexbin.v0.min.js?5c6e4f0"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script> | |
</head> | |
<body> | |
<svg height="500" width="960"></svg> | |
<script src="index.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var categories, classes, colorify, data_url, geo_url, height, path_generator, projection, svg, width, zoom, zoom_group; | |
width = 960; | |
height = 500; | |
svg = d3.select('svg'); | |
zoom_group = svg.append('g'); | |
zoom = d3.behavior.zoom().scaleExtent([1, 4]).on('zoom', function() { | |
return zoom_group.attr('transform', "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")"); | |
}); | |
svg.call(zoom); | |
projection = d3.geo.azimuthalEqualArea().clipAngle(180 - 1e-3).scale(280000).rotate([-2.340087890624995, -48.858643406835796, 0]).translate([width / 2, height / 2]).precision(0.1); | |
path_generator = d3.geo.path().projection(projection); | |
categories = ['restaurant', 'attraction', 'poi', 'accommodation']; | |
classes = categories.length; | |
colorify = d3.scale.category10().domain(categories); | |
geo_url = 'http://wafi.iit.cnr.it/webvis/tmp/paris.topojson'; | |
data_url = 'http://wafi.iit.cnr.it/webvis/tmp/paris.json'; | |
d3.json(geo_url, function(geo) { | |
var regions; | |
regions = topojson.feature(geo, geo.objects['conseils-quartiers']); | |
zoom_group.selectAll('.region').data(regions.features).enter().append('path').attr('class', 'region').attr('d', path_generator); | |
zoom_group.append('path').attr({ | |
"class": 'water', | |
transform: 'translate(45,-206) scale(1.1)', | |
d: "m 341.4375,154.84375 -27.78125,13.125 -27.78125,10.625 -8.09375,5.53125 -21.71875,16.6875 -10.09375,8.0625 -16.15625,10.625 -14.65625,6.0625 -19.6875,10.09375 -16.65625,8.59375 -8.59375,8.0625 -12.625,19.71875 -10.625,10.09375 -14.125,21.21875 -13.65625,18.1875 L 99,343.75 83.84375,361.9375 c 0,0 -13.146098,16.66211 -14.15625,19.1875 -1.010153,2.52538 -5.03125,17.65625 -5.03125,17.65625 l -9.09375,35.875 1.5,7.0625 2.53125,13.65625 -1,15.125 L 56.0625,485.15625 51,495.25 53.03125,515.96875 56.0625,520 l 5.0625,11.625 -1.53125,11.125 5.0625,11.09375 12.625,16.15625 11.625,8.59375 8.0625,1.53125 19.71875,-7.09375 13.625,-6.0625 7.5625,-4.03125 14.65625,-15.15625 12.625,-11.09375 13.65625,-21.21875 9.0625,-13.625 19.21875,-29.3125 L 217.1875,461.4375 235.375,443.75 246.46875,428.59375 249,419 l 9.09375,-10.09375 9.59375,-7.59375 12.125,-5.03125 29.28125,-2.03125 24.75,-0.5 32.84375,15.65625 13.625,6.5625 6.0625,0.5 7.59375,3.53125 11.09375,12.125 13.15625,8.09375 14.625,7.5625 21.71875,12.625 15.65625,15.15625 2.03125,6.5625 15.65625,17.1875 7.5625,10.09375 5.5625,7.5625 c 0,0 21.70859,24.76094 22.71875,26.78125 1.01015,2.0203 17.1875,20.71875 17.1875,20.71875 l 17.15625,17.15625 19.71875,10.625 13.625,6.0625 6.5625,6.5625 -1,12.625 -3.53125,22.71875 2.53125,13.125 9.09375,12.125 7.0625,10.625 4.03125,3.03125 6.5625,9.0625 8.59375,8.59375 4.03125,15.65625 -4.03125,17.1875 -22.71875,55.03125 24.75,-45.4375 5.03125,-22.71875 -0.5,-17.1875 -7.0625,-13.125 -8.59375,-11.625 -10.09375,-10.09375 -7.59375,-8.59375 -6.0625,-8.59375 -0.5,-8.5625 2.53125,-15.15625 2.53125,-17.1875 -2.53125,-4.03125 10.09375,1 15.15625,-2.53125 9.59375,1.53125 10.625,-1.53125 17.15625,3.5625 11.125,-2.03125 10.09375,-1.53125 18.6875,0.53125 -4.53125,-0.53125 -16.6875,-3.53125 -7.0625,1.53125 -8.59375,2.53125 -13.625,-2.53125 -12.625,2.53125 -10.09375,-3.03125 c 0,0 -11.63087,2 -14.15625,2 -2.52538,0 -12.625,-0.5 -12.625,-0.5 L 596.5,594.25 583.875,589.71875 566.6875,580.625 554.0625,569 540.4375,555.875 528.8125,540.71875 513.15625,520.53125 496,498.8125 485.875,487.1875 472.75,473.03125 457.09375,456.375 l -1.5,-5.5625 -1.03125,-6.5625 -14.65625,-7.5625 -13.625,-10.625 -19.6875,-7.0625 -13.125,-5.5625 -11.125,-1.5 L 367.1875,405.375 349,396.78125 l -16.15625,-9.09375 -13.125,0 -10.625,0 -25.25,1.5 -21.21875,7.59375 -9.59375,12.125 -12.625,16.65625 -23.71875,25.75 -24.25,36.375 -20.21875,30.3125 -13.625,19.6875 -9.09375,7.0625 -10.09375,11.625 -10.09375,7.0625 -11.125,6.0625 -12.125,1.03125 L 95.96875,567.5 82.3125,558.40625 75.25,554.34375 67.6875,543.75 l 0,-2.53125 0,-7.5625 -1.53125,-5.5625 -4.53125,-6.5625 -4.03125,-6.5625 -1.03125,-13.65625 3.03125,-10.09375 7.59375,-25.75 -2.53125,-12.625 -3.03125,-16.15625 3.53125,-25.28125 7.5625,-26.75 6.21875,-11.125 3.53125,-5.4375 18.53125,-6.6875 14.15625,-13.625 11.125,-18.1875 15.125,-23.21875 2.9375,-6.3125 -10.5,15.40625 L 123.25,327.5625 116.15625,344.25 99,358.375 l -14.96875,5.8125 1.8125,-2.375 8.84375,-10 18.96875,-20.6875 36.84375,-44.46875 0.625,-1.03125 -6.78125,14.4375 2.625,-3.8125 4.71875,-11.53125 11.96875,-19.78125 12.625,-13.625 27.78125,-15.65625 17.65625,-4.5625 L 241.4375,220 l 28.28125,-22.21875 20.1875,-14.15625 41.4375,-17.65625 10.09375,-11.125 z m 51.78125,262.6875 c 0,0 11.96875,4.11161 13.21875,4.46875 1.25,0.35714 16.25,6.78125 16.25,6.78125 l 6.96875,4.125 c 0.17857,0.71428 1.40625,10.875 1.40625,10.875 0,0 -12.48214,-3.75 -13.375,-5 -0.89285,-1.25 -12.5,-8.03125 -12.5,-8.03125 l -11.96875,-13.21875 z m 39.625,18.21875 9.125,3.9375 11.0625,6.25 0,8.375 -18.21875,-9.28125 c 0,0 -1.96875,-8.38839 -1.96875,-9.28125 z m -363.375,116.625 1.0625,0.6875 21.78125,17.875 10,4.625 c 0,0 -2.125,0.7366 -3.375,1.09375 C 97.6875,577.01339 91.96875,577 91.96875,577 l -7.6875,-4.09375 -8.5625,-8.75 -6.96875,-10.375 0.71875,-1.40625 z" | |
}); | |
return d3.json(data_url, function(points) { | |
var angle, apothem, bins, dist_scale, hexbin, max, max_dist, max_tot, petals, radius, subplots; | |
radius = 26; | |
apothem = Math.sqrt(3) / 2 * radius; | |
hexbin = d3.hexbin().size([width, height]).radius(radius).x(function(d) { | |
return projection([d.lng, d.lat])[0]; | |
}).y(function(d) { | |
return projection([d.lng, d.lat])[1]; | |
}); | |
bins = _.chain(hexbin(points)).forEach(function(bin) { | |
return bin.classes_count = _.chain(categories).map(function(klass) { | |
var count; | |
count = bin.filter(function(point) { | |
return point.category === klass; | |
}).length; | |
return { | |
count: count, | |
"class": klass | |
}; | |
}).value(); | |
}).value(); | |
max_tot = d3.max(bins, function(bin) { | |
return bin.length; | |
}); | |
max = d3.max(bins, function(bin) { | |
return d3.max(bin.classes_count, function(count) { | |
return count.count; | |
}); | |
}); | |
angle = 2 * Math.PI / classes; | |
subplots = zoom_group.selectAll('.subplot').data(bins); | |
subplots.enter().append('g').attr({ | |
"class": 'subplot', | |
transform: function(bin) { | |
return "translate(" + bin.x + "," + bin.y + ")"; | |
} | |
}); | |
max_dist = apothem / (1 + Math.sin(angle / 2)); | |
dist_scale = d3.scale.sqrt().domain([0, max]).range([0, max_dist]); | |
petals = subplots.selectAll('.petal').data(function(bin) { | |
return bin.classes_count; | |
}); | |
return petals.enter().append('circle').attr({ | |
"class": 'petal', | |
cx: function(d, i) { | |
return dist_scale(d.count) * Math.cos(i * angle - Math.PI / 2); | |
}, | |
cy: function(d, i) { | |
return dist_scale(d.count) * Math.sin(i * angle - Math.PI / 2); | |
}, | |
r: function(d) { | |
return dist_scale(d.count) * Math.sin(angle / 2); | |
}, | |
fill: function(count) { | |
return colorify(count["class"]); | |
} | |
}); | |
}); | |
}); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment