Perceptual scaling of prop symbols
This example shows a solution to achieve perceptual (or apparent) scaling of graduated symbols, using the Leaflet library. Data are raw totals of Kenyan girls enrolled in the 8th grade by county.
Apparently we've never been calculating the area of our circles for graduated symbols?
var data = {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "WOMEN": 276480, "G8": 7265 }, "geometry": { "type": "Point", "coordinates": [ 35.946, 0.669 ] } },
{ "type": "Feature", "properties": { "WOMEN": 364459, "G8": 10983 }, "geometry": { "type": "Point", "coordinates": [ 35.299, -0.726 ] } },
{ "type": "Feature", "properties": { "WOMEN": 703515, "G8": 19593 }, "geometry": { "type": "Point", "coordinates": [ 34.64, 0.749 ] } },
{ "type": "Feature", "properties": { "WOMEN": 387824, "G8": 8889 }, "geometry": { "type": "Point", "coordinates": [ 34.194, 0.387 ] } },
{ "type": "Feature", "properties": { "WOMEN": 186260, "G8": 5950 }, "geometry": { "type": "Point", "coordinates": [ 35.537, 0.802 ] } },
{ "type": "Feature", "properties": { "WOMEN": 261909, "G8": 6561 }, "geometry": { "type": "Point", "coordinates": [ 37.627, -0.604 ] } },
{ "type": "Feature", "properties": { "WOMEN": 288121, "G8": 2493 }, "geometry": { "type": "Point", "coordinates": [ 40.199, -0.489 ] } },
{ "type": "Feature", "properties": { "WOMEN": 501340, "G8": 11827 }, "geometry": { "type": "Point", "coordinates": [ 34.359, -0.543 ] } },
{ "type": "Feature", "properties": { "WOMEN": 69600, "G8": 1442 }, "geometry": { "type": "Point", "coordinates": [ 38.542, 1.01 ] } },
{ "type": "Feature", "properties": { "WOMEN": 342166, "G8": 7076 }, "geometry": { "type": "Point", "coordinates": [ 36.909, -2.121 ] } },
{ "type": "Feature", "properties": { "WOMEN": 859662, "G8": 22085 }, "geometry": { "type": "Point", "coordinates": [ 34.745, 0.404 ] } },
{ "type": "Feature", "properties": { "WOMEN": 376359, "G8": 12004 }, "geometry": { "type": "Point", "coordinates": [ 35.314, -0.296 ] } },
{ "type": "Feature", "properties": { "WOMEN": 820673, "G8": 20077 }, "geometry": { "type": "Point", "coordinates": [ 36.824, -1.069 ] } },
{ "type": "Feature", "properties": { "WOMEN": 574209, "G8": 14485 }, "geometry": { "type": "Point", "coordinates": [ 39.687, -3.176 ] } },
{ "type": "Feature", "properties": { "WOMEN": 267424, "G8": 6514 }, "geometry": { "type": "Point", "coordinates": [ 37.32, -0.525 ] } },
{ "type": "Feature", "properties": { "WOMEN": 601818, "G8": 13499 }, "geometry": { "type": "Point", "coordinates": [ 34.775, -0.775 ] } },
{ "type": "Feature", "properties": { "WOMEN": 494149, "G8": 11499 }, "geometry": { "type": "Point", "coordinates": [ 34.835, -0.169 ] } },
{ "type": "Feature", "properties": { "WOMEN": 531427, "G8": 17780 }, "geometry": { "type": "Point", "coordinates": [ 38.407, -1.491 ] } },
{ "type": "Feature", "properties": { "WOMEN": 333934, "G8": 7510 }, "geometry": { "type": "Point", "coordinates": [ 39.19, -4.183 ] } },
{ "type": "Feature", "properties": { "WOMEN": 200602, "G8": 5323 }, "geometry": { "type": "Point", "coordinates": [ 36.772, 0.324 ] } },
{ "type": "Feature", "properties": { "WOMEN": 48494, "G8": 1233 }, "geometry": { "type": "Point", "coordinates": [ 40.883, -2.079 ] } },
{ "type": "Feature", "properties": { "WOMEN": 555445, "G8": 15311 }, "geometry": { "type": "Point", "coordinates": [ 37.413, -1.28 ] } },
{ "type": "Feature", "properties": { "WOMEN": 453817, "G8": 15150 }, "geometry": { "type": "Point", "coordinates": [ 37.788, -2.158 ] } },
{ "type": "Feature", "properties": { "WOMEN": 465813, "G8": 1584 }, "geometry": { "type": "Point", "coordinates": [ 40.739, 3.436 ] } },
{ "type": "Feature", "properties": { "WOMEN": 140054, "G8": 1650 }, "geometry": { "type": "Point", "coordinates": [ 37.57, 2.979 ] } },
{ "type": "Feature", "properties": { "WOMEN": 685645, "G8": 15012 }, "geometry": { "type": "Point", "coordinates": [ 37.764, 0.167 ] } },
{ "type": "Feature", "properties": { "WOMEN": 472814, "G8": 11098 }, "geometry": { "type": "Point", "coordinates": [ 34.363, -0.99 ] } },
{ "type": "Feature", "properties": { "WOMEN": 452446, "G8": 8499 }, "geometry": { "type": "Point", "coordinates": [ 39.651, -4.021 ] } },
{ "type": "Feature", "properties": { "WOMEN": 484717, "G8": 11810 }, "geometry": { "type": "Point", "coordinates": [ 37.033, -0.81 ] } },
{ "type": "Feature", "properties": { "WOMEN": 1533139, "G8": 24960 }, "geometry": { "type": "Point", "coordinates": [ 36.868, -1.293 ] } },
{ "type": "Feature", "properties": { "WOMEN": 798743, "G8": 22675 }, "geometry": { "type": "Point", "coordinates": [ 36.078, -0.464 ] } },
{ "type": "Feature", "properties": { "WOMEN": 376477, "G8": 10633 }, "geometry": { "type": "Point", "coordinates": [ 35.11, 0.187 ] } },
{ "type": "Feature", "properties": { "WOMEN": 421894, "G8": 7312 }, "geometry": { "type": "Point", "coordinates": [ 35.576, -1.255 ] } },
{ "type": "Feature", "properties": { "WOMEN": 311204, "G8": 7262 }, "geometry": { "type": "Point", "coordinates": [ 34.965, -0.643 ] } },
{ "type": "Feature", "properties": { "WOMEN": 304113, "G8": 9486 }, "geometry": { "type": "Point", "coordinates": [ 36.483, -0.322 ] } },
{ "type": "Feature", "properties": { "WOMEN": 353833, "G8": 9550 }, "geometry": { "type": "Point", "coordinates": [ 36.956, -0.343 ] } },
{ "type": "Feature", "properties": { "WOMEN": 111940, "G8": 1385 }, "geometry": { "type": "Point", "coordinates": [ 37.118, 1.317 ] } },
{ "type": "Feature", "properties": { "WOMEN": 443652, "G8": 10828 }, "geometry": { "type": "Point", "coordinates": [ 34.248, -0.062 ] } },
{ "type": "Feature", "properties": { "WOMEN": 139323, "G8": 4205 }, "geometry": { "type": "Point", "coordinates": [ 38.419, -3.435 ] } },
{ "type": "Feature", "properties": { "WOMEN": 120222, "G8": 1838 }, "geometry": { "type": "Point", "coordinates": [ 39.418, -1.526 ] } },
{ "type": "Feature", "properties": { "WOMEN": 186879, "G8": 4681 }, "geometry": { "type": "Point", "coordinates": [ 37.87, -0.207 ] } },
{ "type": "Feature", "properties": { "WOMEN": 411585, "G8": 9909 }, "geometry": { "type": "Point", "coordinates": [ 34.957, 1.051 ] } },
{ "type": "Feature", "properties": { "WOMEN": 410330, "G8": 3175 }, "geometry": { "type": "Point", "coordinates": [ 35.436, 3.425 ] } },
{ "type": "Feature", "properties": { "WOMEN": 445185, "G8": 9968 }, "geometry": { "type": "Point", "coordinates": [ 35.322, 0.526 ] } },
{ "type": "Feature", "properties": { "WOMEN": 291906, "G8": 8032 }, "geometry": { "type": "Point", "coordinates": [ 34.722, 0.076 ] } },
{ "type": "Feature", "properties": { "WOMEN": 298175, "G8": 1505 }, "geometry": { "type": "Point", "coordinates": [ 40.035, 1.808 ] } },
{ "type": "Feature", "properties": { "WOMEN": 257863, "G8": 4503 }, "geometry": { "type": "Point", "coordinates": [ 35.244, 1.74 ] } },
{ "type": "Feature", "properties": { "WOMEN": null, "G8": null }, "geometry": null }
]
}
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Perceptual Scaling</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
<style>
body { margin:0; padding:0; font-family: sans-serif; }
#map { position:absolute; top:0; bottom:0; width:960px; height: 540px; }
h1 { position: absolute; left: 50px; top: 10px; padding: 8px 2%; margin: 0; background: rgba(255,121,0,0.8); box-shadow: 0 0 15px rgba(0,0,0,0.2); border-radius: 3px; color: whitesmoke; font-weight: normal; font-size: 1.4em; }
</style>
</head>
<body>
<div id='map'></div>
<h1>Kenyan girls enrolled in 8th grade in 2014 by county</h1>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<script src="data.js"></script>
<script>
var map = L.map('map', {
center: [-.23, 37.8],
zoom: 7
});
L.tileLayer('http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
// you need to know what the min value is,
// calculated at runtime or prior
var minValue = 1233;
// minimum desired radius size of circles
var minRadius = 8;
L.geoJson(data, {
pointToLayer: function(feature, ll){
return L.circleMarker(ll, {
color: '#ff7900',
opacity: 1,
weight: 2,
fillColor: '#ff7900',
fillOpacity: .6,
//radius: 10
radius: calcRadius(feature.properties.G8)
});
}
}).addTo(map);
function calcRadius(val) {
return 1.0083 * Math.pow(val/minValue,.5716) * minRadius;
}
</script>
</body>
</html>