Many companies are built with Python as primary backend language
ogr2ogr
, ogrinfo
, gdalwarp
, etc.proj
utility to convert data between projections+proj=poly -m 1:25000 +lat_0=35 ...
projection definitionsMVTree
and TPRTree
)Capability | C/C++ Library |
---|---|
Spatial Operations | GEOS |
Vector I/O | GDAL (OGR) |
Raster Operations and I/O | GDAL |
Projections | PROJ.4 |
Spatial Indexing | libspatialindex |
Many geospatial applications use one or more of these
Capability | C/C++ Library | Python Library |
---|---|---|
Spatial Operations | GEOS | shapely |
Vector I/O | GDAL (OGR) | fiona |
Raster Operations and I/O | GDAL | rasterio |
Projections | PROJ.4 | pyproj |
Spatial Indexing | libspatialindex | rtree |
Python "glue" libraries wrap low-level functionality.
Create and manipulate 2D geometry objects
from shapely.geometry import Point, LineString, Polygon
p = Point(x, y)
line = LineString([(x0, y0), (x1, y1), (x2, y2)])
polygon = Polygon([(x0, y0), (x1, y1), (x2, y2)])
intersects
, contains
, within
, crosses
, ...intersection
, difference
, union
, ...fio
command line program for quick access and for use in command pipelinesimport fiona
with fiona.open('Boston_Neighborhoods.shp') as f:
crs = f.crs
features = list(f)
print(crs)
{'init': u'epsg:4326'}
print(features[0])
{'type': 'Feature',
'geometry': { 'type': 'MultiPolygon', 'coordinates': ...},
'id': '0',
'properties': OrderedDict([('Acres', 1605.56181523),
('Name', 'Roslindale'),
('OBJECTID', 1),
('SHAPE_area', 69938272.6723),
('SHAPE_len', 53563.9125971)])
}
rio
command line tool for quick access and use in pipelinesimport math
import pyproj
proj = pyproj.Proj(init='epsg:26986')
x0, y0 = proj(-71.0838, 42.3627) # CIC coordinates
x1, y1 = proj(-71.1057, 42.3670) # Cambridge City Hall coordinates
# Euclidean distance in meters
math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
1866.132
Project Shapely geometry objects
from functools import partial
import pyproj
from shapely.geometry import Polygon
from shapely.ops import transform
project = partial(
pyproj.transform,
pyproj.Proj(init='epsg:4326'),
pyproj.Proj(init='epsg:26986'))
# Outline of CIC building
p = Polygon([[-71.08372, 42.36313], [-71.08296, 42.36293], [-71.08303, 42.36239], [-71.08371, 42.36253], [-71.0840, 42.36266], [-71.08372, 42.36313]])
p2 = transform(project, p)
p2.area # Area in square meters
4591.96
from rtree import index
# Create a list of neighborhood objects that have attributes:
# .name : string
# .polygon : Shapely Polygon object
neighborhoods = read_neighborhoods(filename)
# Create and populate the index
idx = index.Index()
for i, n in enumerate(neightborhoods):
idx.insert(i, n.polygon.bounds)
# Query for polygons whose bounds overlap a point
x, y = -71.097389, 42.346599 # Fenway Park coordinates
list(idx.intersection((x, y, x, y)))
[16]
neighborhoods[16].name
'Fenway'
Conda is newer and generally makes installing native dependencies (like GDAL, GEOS) easier than virtualenv.
Tip: Use a new environment for every project. Do not install libraries into your global python installation (i.e., no sudo pip install ...
)
virtualenv ~/venv
source ~/venv/bin/activate
pip install shapely fiona
conda create -n maptime -c conda-forge shapely fiona
source activate maptime
conda install ipython
$ conda create -n maptime -c conda-forge shapely fiona
$ source activate maptime
$ conda install ipython
$ cd ~/Downloads
$ unzip maptime-python.zip
$ cd maptime-python/code
$ ipython
$ ipython
In [1]: %run shapes.py
from shapely.geometry import Point, LineString, Polygon
# Create a Point with x, y coordinates
point1 = Point(1.5, 0.5)
point2 = Point(2.5, 2.5)
# Create a LineString with a list of (x, y) tuples
line1 = LineString([(0.5, 1.5), (3.5, 1.5)])
poly1 = Polygon([(1.0, 0.0), (3.0, 0.0), (2.0, 2.0)])
poly2 = Polygon([(2.0, 0.5), (3.5, 0.5), (3.5, 1.0), (2.0, 1.0)])
# Polygons can have holes. Specify them as a list of list of (x, y) tuples
poly_w_hole = Polygon([(0.0, 0.0), (5.0, 0.0), (5.0, 5.0), (0.0, 5.0)],
[[(1.0, 1.0), (2.0, 1.0), (2.0, 2.0), (1.0, 2.0)],
[(3.0, 3.0), (4.0, 3.0), (4.0, 4.0), (3.0, 4.0)]])
%run code/ratmap.py
neighborhoods = read_neighborhoods('data/Boston_Neighborhoods.shp')
rodents = read_rodents('data/rodents.geojson')
assign_rodent_counts(neighborhoods, rodents)
# Sort the neighborhoods by number of rodent reports
neighborhoods.sort(key=lambda x: x.n_rodents)
for n in neighborhoods:
print('%s: %s' % (n.name, n.n_rodents))
# Sort by rodent reports normalized by area
neighborhoods.sort(key=lambda x: x.n_rodents / x.area)
for n in neighborhoods:
print('%s: %s' % (n.name, n.n_rodents))
Feel free to follow up at the meetup page.
Thanks to Michelle Fullwood, Sean Gillies, and Shaun Walbridge for early comments and feedback.