-
Notifications
You must be signed in to change notification settings - Fork 204
TileStache Setup
iNat uses TileStache to serve tiled GeoJSON to power some of its maps.
TileStache supports a tiered caching system. We use Memcache backed by a disk-based cache. We use some simplified geometry tables that are derived from tables in the official schema but need to be generated manually. These are mostly for geometries like country boundaries that don't change much, fi at all. The scripts used to create these tables have been checked in:
This is what our TileStache config file looks like
{
"cache": {
"name": "Multi",
"tiers": [
{
"name": "Memcache",
"servers": ["localhost:11211"],
"version": 5
},
{
"name": "Disk",
"path": "/path/to/TileStache/public",
"dirs": "portable"
}
]
},
"layers": {
"country_points_5": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude/5)*5 AS lat_round, ROUND(longitude/5)*5 AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type = 12 AND bbox_area > 5"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"place_points_5": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude/5)*5 AS lat_round, ROUND(longitude/5)*5 AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,12) AND bbox_area > 10"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"place_points_r0": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude) AS lat_round, ROUND(longitude) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,12,100) AND bbox_area > 0.25"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"place_points_r1": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude,1) AS lat_round, ROUND(longitude,1) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,12,100) AND bbox_area > 0.1"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"place_points_r2": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT DISTINCT ON (lat_round, lon_round) id, name, display_name, place_type, ROUND(latitude,2) AS lat_round, ROUND(longitude,2) AS lon_round, ST_POINT(longitude, latitude) FROM places WHERE place_type IN (8,9,100) AND bbox_area > 0.001"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"observations":
{
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": false,
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT id as observation_id, * FROM observations"
},
"properties": {"observation_id": "id", "taxon_id": "taxon_id", "quality_grade": "quality_grade"}
},
"cache lifespan": 86400,
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"counties": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": "padded",
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT place_geometries.id, place_geometries.place_id, place_geometries.geom FROM places JOIN place_geometries ON places.id = place_geometries.place_id WHERE places.place_type = 9"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"counties_simplified": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": "padded",
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT * FROM counties_simplified"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"states_simplified": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": "padded",
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"table": "states_simplified"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"countries_simplified": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"clipped": "padded",
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT * FROM countries_simplified"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
},
"openspace": {
"provider": {
"name": "vector",
"driver": "PostgreSQL",
"parameters": {
"dbname": "inaturalist_production",
"user": "theuser",
"password": "*****",
"query": "SELECT places.*, place_geometries.geom FROM places JOIN place_geometries ON places.id = place_geometries.place_id WHERE places.place_type = 100"
}
},
"preview": {"ext": "geojson"},
"allowed origin": "*"
}
}
}
TileStache comes with a nice little server script you can use in development
./scripts/tilestache-server.py -c inaturalist.cfg
There are a number of ways to run TileStache in a production environment. For iNaturalist.org we use nginx and Passenger's WSGI functionality:
server {
listen 8081;
server_name yourdomain.com;
root /path/to/TileStache/public;
error_log /path/to/nginx/logs/tilestache-error.log;
access_log /path/to/nginx/logs/tilestache-access.log;
types {
text/json json geojson;
}
location / {
try_files $uri @passenger;
add_header Access-Control-Allow-Origin *;
}
location @passenger {
passenger_enabled on;
root /path/to/TileStache/public;
}
}
import sys
sys.stdout = sys.stderr
def append_local_dir():
import os,sys
local_dir = os.path.dirname(__file__)
sys.path.append(local_dir)
append_local_dir()
import TileStache
application = TileStache.WSGITileServer(config='inaturalist.production.cfg', autoreload=True)