Although the Mercator projection is perhaps the most familiar, many different map projections exist to map the Earth's spherical surface to a two-dimensional image. Each projection introduces some type of distortion; for different purposes, some distortions may be more desirable. This example is another choropleth map, showing population density map of the world's countries. Use the drop-down menu to compare several projections supported by Protovis.
Next: Heatmaps
<html>
<head>
<title>Choropleth Map</title>
<link type="text/css" rel="stylesheet" href="ex.css?3.2"/>
<script type="text/javascript" src="../protovis-r3.2.js"></script>
<script type="text/javascript" src="countries.js"></script>
<style type="text/css">
#fig {
width: 860px;
height: 550px;
}
</style>
</head>
<body><div id="center"><div id="fig">
<div align="right">
<b>Projection:</b>
<select id="menu" onchange="geo.projection(this.value); vis.render();">
<option value="none">Identity projection</option>
<option value="mercator">Mercator projection</option>
<option value="gall-peters">Gall-Peters projection</option>
<option value="sinusoidal">Sinusoidal projection</option>
<option value="hammer" selected>Hammer projection</option>
</select>
</div>
<script type="text/javascript+protovis">
/*
* A diverging color scale, using previously-computed quantiles of population
* densities; in the future, we might use a quantile scale here to do this
* automatically. Map colors based on www.ColorBrewer.org, by Cynthia A. Brewer,
* Penn State.
*/
var fill = pv.Scale.linear()
.domain(140, 650, 1900)
.range("#91bfdb", "#ffffbf", "#fc8d59");
/* Precompute the country's population density and color. */
countries.forEach(function(c) {
c.color = stats[c.code].area
? fill(stats[c.code].pop / stats[c.code].area)
: "#ccc"; // unknown
});
var w = 860,
h = 3 / 5 * w,
geo = pv.Geo.scale("hammer").range(w, h);
var vis = new pv.Panel()
.width(w)
.height(h);
/* Countries. */
vis.add(pv.Panel)
.data(countries)
.add(pv.Panel)
.data(function(c) c.borders)
.add(pv.Line)
.data(function(b) b)
.left(geo.x)
.top(geo.y)
.title(function(d, b, c) c.name)
.fillStyle(function(d, b, c) c.color)
.strokeStyle(function() this.fillStyle().darker())
.lineWidth(1)
.antialias(false);
/* Latitude ticks. */
vis.add(pv.Panel)
.data(geo.ticks.lat())
.add(pv.Line)
.data(function(b) b)
.left(geo.x)
.top(geo.y)
.strokeStyle("rgba(128,128,128,.3)")
.lineWidth(1)
.interpolate("cardinal")
.antialias(false);
/* Longitude ticks. */
vis.add(pv.Panel)
.data(geo.ticks.lng())
.add(pv.Line)
.data(function(b) b)
.left(geo.x)
.top(geo.y)
.strokeStyle("rgba(128,128,128,.3)")
.lineWidth(1)
.interpolate("cardinal")
.antialias(false);
vis.render();
</script>
</div></div></body>
</html>