Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created September 21, 2012 03:45
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tmcw/3759614 to your computer and use it in GitHub Desktop.
Save tmcw/3759614 to your computer and use it in GitHub Desktop.
OSM Growth

What is this? It's about 7 years of OpenStreetMap growth. Each step in the animation is 72 days, and the colors alternate between red and blue. The data is from Latest Weekly Changesets from planet.openstreetmap.org, processed into an SQLite database with sometimemachine. The points being drawn are the centers of the bounding boxes of changesets. There are 13,098,655 changesets in the database. The script to generate the visualization is below, and the rest of the make steps are

gm mogrify -format gif *.png
gifsicle --loop -d20 *.gif > ../animation.gif

Requiring gifsicle and graphicsmagick.

Fast growth in rectangular areas (like the DRC) is typically because of imports to the OSM data from other open datasources. The dots in the middle of the ocean are because of bounding boxes that either cross the meridian or span the entire globe.

var Canvas = require('canvas'),
moment = require('moment'),
fs = require('fs');
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('changesets_precise.sqlite');
var block = 1;
var w = 360 * 4, h = 180 * 4;
var c = new Canvas(w, h);
var ctx = c.getContext('2d');
ctx.fillStyle = '#e9e9e9';
ctx.fillRect(0, 0, w, h);
function x(lon) {
return (lon + 180) / 360 * w;
}
function y(lat) {
return (90 - lat) / 180 * h;
}
var drawn = {};
var gap = (60 * 60 * 24 * 73);
var n = 0;
var colors = ['#FF00C3', '#0091FF'];
var col = 0;
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = colors[col];
ctx.fillText('OpenStreetMap', w - 100, h - 20);
db.get('SELECT min(closed_at) as m FROM osm_changeset LIMIT 1;', function(err, min) {
db.get('SELECT max(closed_at) as m FROM osm_changeset LIMIT 1;', function(err, max) {
var start = min.m;
var end = min.m + gap;
ctx.fillText(moment(new Date(min.m * 1000)).format('L'), 10, h - 20);
ctx.fillText(moment(new Date(max.m * 1000)).format('L'), 400, h - 20);
function run() {
drawn = {};
ctx.globalAlpha = 0.2;
ctx.fillRect(
70,
h - 26,
~~((((start - min.m) / (max.m - min.m)) * 290)),
5);
ctx.globalAlpha = 1;
db.each("SELECT lon, lat FROM osm_changeset WHERE closed_at BETWEEN " + start + " AND " + end + ";", function(err, row) {
var xp = Math.floor(x(row.lon));
var yp = Math.floor(y(row.lat));
var k = xp + ' ' + yp;
if (drawn[k]) return;
ctx.fillRect(
xp,
yp,
block, block);
drawn[k] = true;
}, function() {
var k = '' + n;
if (k.length == 1) k = '0' + k;
fs.writeFileSync('changesets_' + k + '.png', c.toBuffer());
if (start > max.m) return;
start += gap;
end += gap;
n++;
col++;
if (col > 1) col = 0;
ctx.fillStyle = colors[col];
run();
});
}
run();
});
});
Copy link

ghost commented Jul 15, 2014

Hi,

I'm working at replicating this and I am able to ingest the latest changeset downloaded here, http://planet.openstreetmap.org/planet/, into a sqlite database following https://github.com/tmcw/sometimemachine instructions. I can then run this script and it creates the multiple .png images but the only thing that changes between is the timestamp at the bottom, there is no population on the map. I've used a sqlite manager to go into the database and confirm that the data does exist with id's, user ids, lat, long, etc but the data doesn't seem to be populated in the images.

The database is 1.3GB in size, did you ever have this issue running through this?

Thanks

Copy link

ghost commented Jul 16, 2014

Solved.

I noticed the script above calls lat, long for column name and the sqlite database ingested uses min_long, min_lat, max_long, max_lat

Copy link

ghost commented Jul 16, 2014

Create a lon and lat column in osm_changeset table type REAL.

Then,

UPDATE osm_changeset SET lat=(max_lon - ((max_lon - min_lon) / 2));
UPDATE osm_changeset SET lat=(max_lat - ((max_lat - min_lat) / 2));

Above creates arbitrary center points between the maximum and minimum values for lon and lat for the script to use.

Copy link

ghost commented Jul 16, 2014

**** UPDATE osm_changeset SET lon=(max_lon - ((max_lon - min_lon) / 2));

typo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment