Quality analysis for OpenStreetMap
By Matt Greene
OSM QA Tiles are now being updated daily for the entire world on osmlab.github.io as mbtiles. OSM QA Tiles contain the full spectrum of OpenStreetMap data at full fidelity. Use them with Tile Reduce to conflate OpenStreetMap with other datasets, detect bugs like connectivity issues, or monitor for vandalism — you can do nearly any tile-based analysis of OpenStreetMap data.

OSM QA Tiles contain the full spectrum of OpenStreetMap data for analysis.
To analyze the data in OSM QA Tiles, you can write simple Turf.js based processors in Tile Reduce. Tile Reduce is a geospatial MapReduce library for running custom processors across all tiles in a given area. Tile Reduce handles scaling these processors across all available cores on a machine, and it exposes data as GeoJSON, making processors easy to write and understand.
Here are two examples of how to build simple data analysis with OSM QA Tiles and Tile Reduce.
Count buildings in an area
index.js
var TileReduce = require('tile-reduce');
var turf = require('turf');
var argv = require('minimist')(process.argv.slice(2));
// Pass area from command line
var area = JSON.parse(argv.area);
// Options: zoom level, tile source(s), processor to run)
var opts = {
zoom: 15,
tileLayers: [
{
name: 'osmdata',
mbtiles: __dirname+'/latest.planet.mbtiles',
layers: ['osm']
}
],
map: __dirname+'/buildings.js'
};
// Initialize Tile Reduce
var tilereduce = TileReduce(area, opts);
var buildings = 0;
// Accumulate results
tilereduce.on('reduce', function(result){
buildings += result;
});
// Output results
tilereduce.on('end', function(error){
console.log(buildings);
});
tilereduce.run();
buildings.js
var turf = require('turf');
var normalize = require('geojson-normalize');
module.exports = function(tileLayers, opts, done){
// Create GeoJSON FeatureCollection from source data
var osmdata = normalize(tileLayers.osmdata.osm);
var buildingCount = 0;
// Count features containing the "building" key
osmdata.features.forEach(function(feature) {
if (feature.properties.building) {
buildingCount++;
}
});
// Return results
done(null, buildingCount);
};
Run for given bounding box
node index.js --area [min x, min y, max x, max y]
Create a difference map to TIGER roads
index.js
var TileReduce = require('tile-reduce');
var turf = require('turf');
// Declare area in [x,y,z] format
var area = [327,791,11];
// Setup options for two mbtiles sources
var opts = {
zoom: 15,
tileLayers: [
{
name: 'osmdata',
url: __dirname + '/latest.planet.mbtiles',
layers: ['osm']
},
{
name: 'tiger',
url: __dirname + '/tiger.mbtiles',
layers: ['tiger20062014']
}
],
map: __dirname + '/difference.js'
};
// Initialize TileReduce
var tilereduce = TileReduce(area, opts);
...
difference.js
var turf = require('turf'),
flatten = require('geojson-flatten'),
normalize = require('geojson-normalize'),
tilebelt = require('tilebelt');
module.exports = function(tileLayers, tile, done) {
// Concatenate feature classes and normalize data
var tigerRoads = normalize(tileLayers.tiger.tiger20062014);
var osmData = normalize(tileLayers.osmdata.osm);
// Buffer OpenStreetMap features with 'highway' tags
var streetBuffers = turf.featurecollection([]);
streetBuffers.features = osmData.features.map(function(f){
if (f.properties.highway) {
return turf.buffer(road, 20, 'meters').features[0];
}
});
streetBuffers = normalize(turf.merge(streetBuffers));
// Erase OpenStreetMap highway buffers from tiger lines to reveal difference
var tigerDeltas = turf.featurecollection([]);
if (tigerRoads && streetBuffers) {
tigerRoads.features.forEach(function(tigerRoad){
streetBuffers.features.forEach(function(streetsRoad){
var roadDiff = turf.erase(tigerRoad, streetsRoad);
if(roadDiff && !filter(roadDiff)) tigerDeltas.features.push(roadDiff);
});
});
}
// Return results
done(null, tigerDeltas);
};
...
View the complete code for difference.js here
Run and render map with Tippecanoe
node index.js | tippecanoe -o difference.mbtiles
We’re looking forward to seeing more data analysis from the community using OSM QA Tiles and Tile Reduce. Email us at help@mapbox.com or hit me up on Twitter @mateo_verde if you have any questions.