Last active
August 29, 2015 14:03
-
-
Save nitaku/f0f98e2499a312f93b0f to your computer and use it in GitHub Desktop.
OpeNER - Places with categories (pie chart 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 | |
radius = 2 | |
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()})") | |
# semantic zooming | |
zoom_group.selectAll('.place') | |
.attr('r', radius/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(160000) | |
.rotate([-10.277475, -42.789034, 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) | |
data_url = 'http://wafi.iit.cnr.it/webvis/tmp/elba_places.json' | |
geo_url = 'http://wafi.iit.cnr.it/webvis/italiastat/data/istat/2011/reg2011.topo.json' | |
d3.json geo_url, (geo) -> | |
regions = topojson.feature(geo, geo.objects.reg2011) | |
zoom_group.selectAll('.region') | |
.data(regions.features) | |
.enter().append('path') | |
.attr('class', 'region') | |
.attr('d', path_generator) | |
d3.json data_url, (points) -> | |
# hexagonal binning | |
radius = 16 | |
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})" | |
pie_layout = d3.layout.pie() | |
.sort(null) | |
.value((count) -> count.count) | |
radius_scale = d3.scale.sqrt() | |
.domain([0, max_tot]) | |
.range([0, apothem]) | |
arc_generator = d3.svg.arc() | |
.outerRadius((count) -> radius_scale( d3.select(this.parentNode).datum().length )) | |
.innerRadius(0) | |
pies = subplots.selectAll('.pie') | |
.data((bin) -> pie_layout(bin.classes_count)) | |
pies.enter().append('path') | |
.attr | |
class: 'pie' | |
d: arc_generator | |
fill: (count) -> colorify(count.data.class) | |
#zoom_group.selectAll('.place') | |
# .data(points) | |
# .enter().append('circle') | |
# .attr('class', 'place') | |
# .attr('r', radius) | |
# .attr('fill', (d) -> colorify(d.category) ) | |
# .attr('transform', (d) -> | |
# p = projection([d.lng, d.lat]) | |
# return "translate(#{p[0]},#{p[1]})" | |
# ) | |
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 { | |
background: #272822; | |
margin: 0; | |
padding: 0; | |
} | |
svg { | |
background: #ADD2EF; | |
} | |
.region { | |
fill: white; | |
stroke: #ADD2EF; | |
stroke-width: 1px; | |
vector-effect: non-scaling-stroke; | |
} | |
.graticule { | |
fill: none; | |
stroke-width: 1px; | |
stroke: gray; | |
vector-effect: non-scaling-stroke; | |
} |
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 (pie chart binning)" /> | |
<title>OpeNER - Places with categories (pie chart 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, radius, svg, width, zoom, zoom_group; | |
width = 960; | |
height = 500; | |
radius = 2; | |
svg = d3.select('svg'); | |
zoom_group = svg.append('g'); | |
zoom = d3.behavior.zoom().scaleExtent([1, 4]).on('zoom', function() { | |
zoom_group.attr('transform', "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")"); | |
return zoom_group.selectAll('.place').attr('r', radius / zoom.scale()); | |
}); | |
svg.call(zoom); | |
projection = d3.geo.azimuthalEqualArea().clipAngle(180 - 1e-3).scale(160000).rotate([-10.277475, -42.789034, 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); | |
data_url = 'http://wafi.iit.cnr.it/webvis/tmp/elba_places.json'; | |
geo_url = 'http://wafi.iit.cnr.it/webvis/italiastat/data/istat/2011/reg2011.topo.json'; | |
d3.json(geo_url, function(geo) { | |
var regions; | |
regions = topojson.feature(geo, geo.objects.reg2011); | |
zoom_group.selectAll('.region').data(regions.features).enter().append('path').attr('class', 'region').attr('d', path_generator); | |
return d3.json(data_url, function(points) { | |
var angle, apothem, arc_generator, bins, hexbin, max, max_tot, pie_layout, pies, radius_scale, subplots; | |
radius = 16; | |
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 + ")"; | |
} | |
}); | |
pie_layout = d3.layout.pie().sort(null).value(function(count) { | |
return count.count; | |
}); | |
radius_scale = d3.scale.sqrt().domain([0, max_tot]).range([0, apothem]); | |
arc_generator = d3.svg.arc().outerRadius(function(count) { | |
return radius_scale(d3.select(this.parentNode).datum().length); | |
}).innerRadius(0); | |
pies = subplots.selectAll('.pie').data(function(bin) { | |
return pie_layout(bin.classes_count); | |
}); | |
return pies.enter().append('path').attr({ | |
"class": 'pie', | |
d: arc_generator, | |
fill: function(count) { | |
return colorify(count.data["class"]); | |
} | |
}); | |
}); | |
}); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment