Skip to content

Instantly share code, notes, and snippets.



Last active Aug 29, 2015
What would you like to do?
Placenames Heatmap


There are over 2 million place names defined for the United States at, and they contain interesting patterns if you look at the right ones. For example:

  • Lots of gold names out in the West from the gold rush era. Also check out uranium, coal and oil.
  • Cougar live mostly in the Pacific North West (but there are mountain lions elsewhere and even catamounts).
  • German immigrants heavily settled the Midwest. Check out the Swedish and Danish too.
  • The Cherokee nation was originally established around Tennessee, but they were driven into Oklahoma on the Trail of Tears. The Navaho and Pawnee have clear regions too.
  • Regional place topologies, like canyon, bayou, brook and lac are fun history lessons (think about the languages they are derived from).

How it Works

The full-text search engine in PostgreSQL can rapidly search the place names to produce a subset, which are rendered on the client side by Torque into a lovely heat map.

ALTER TABLE geonames ADD COLUMN ts tsearch;
UPDATE geonames SET ts = to_tsvector('english', name);
CREATE INDEX geonames_ts_idx ON geonames USING GIN (ts);

SELECT * FROM geonames 
  WHERE ts @@ plainto_tsquery('english','new york');
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Placenames Heatmap</title>
<link rel="stylesheet" href="" />
<link rel="stylesheet" href="" />
<link rel="stylesheet" href="">
#map {
width: 100%;
var cdb_map;
var cdb_vis;
var cdb_default = "xxxxxxx";
function getSQL(geoname) {
if ( geoname == "" ) {
geoname = cdb_default;
var geoname_clean = geoname.replace(/[;:\"!@#$%^&\*\(\)\[\]\{\}\?\+\/\\=]/g, "");
var sql = "SELECT * FROM geonames WHERE to_tsvector('english', name) @@ plainto_tsquery('english', '" + geoname_clean.replace(/\'/g, "''") + "') ORDER BY Random() LIMIT 20000";
return sql;
function setSQL(layer, sql) {
/* Torque layers have a setSQL() method at the layer level */
if ( layer.model.get('type') == "torque" ) {
/* Other layers have it at the sublayer level */
else {
var sublayer = layer.getSubLayer(0);
function sendQuery(geoname) {
var layers = cdb_vis.getLayers();
var layer = layers[1];
setSQL(layer, getSQL(geoname));
/* Utility function to read GET parameter values */
function getQueryVariable(variable) {
var query =;
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
return false;
window.onload = function() {
var q = getQueryVariable("q");
shareable: true
function(vis, layers) {
cdb_vis = vis;
cdb_map = vis.getNativeMap();
if ( q ) {
window.setTimeout(function() { setSQL(layers[1], getSQL(q)); }, 500);
<div class="container-full">
<div class="input-group">
<span class="input-group-addon">A word you might find in a placename</span>
<input id="geoname" type="text" class="form-control" aria-label="Place name" placeholder="Enter a word" onchange="javascript:sendQuery(value)"/>
<div id="map" />
</div><!-- /.container -->
<!-- Placed at the end of the document so the pages load faster -->
<script src=""></script>
<script src=""></script>
<script src=""></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment