October 24, 2010 PyCon Ukraine Justin Bronn, Esq. - GeoDjango

geodjango.org

October 24, 2010 PyCon Ukraine Justin Bronn, Esq. - GeoDjango

geodjango

Sunday, October 24, 2010

Open Source GIS, Spatial Web Applications and Beyond

PyCon Ukraine Justin Bronn, Esq.

October 24, 2010

Openmed, LLC


Sunday, October 24, 2010


Sunday, October 24, 2010


Sunday, October 24, 2010

Why?


“ 80% 20%

Sunday, October 24, 2010

of enterprise data has

a spatial component

- Unknown


“ spatial data tends to


Sunday, October 24, 2010

be highly self-

correlated

- Shashi Shekhar & Sanjay Chawla


“ near things are more


Sunday, October 24, 2010

related than distant

things

- W. R. Tobler (1970)


Sunday, October 24, 2010

Commoditization


Sunday, October 24, 2010

Operating Systems


Sunday, October 24, 2010

Databases


Sunday, October 24, 2010

GIS

• Geographic Information Systems

• Standards, data, coordinate systems are

foreign to most developers

• Maps are flat, the world is not


Sunday, October 24, 2010

Coordinate Systems

• Way of representing location

• Analogous to Unicode

• Gives context to spatial data


Coordinate Systems

• Geodetic:

Coordinates are in angles

(latitude/longitude);

depends on the datum, an

ellipsoid model of Earth.

• Projected:

Way to represent the

Sunday, October 24, 2010

curved surface of Earth

on flat surface.

Coordinates may be in

linear units (feet, km).

Compromises on various

aspects of distortion.





Standards

OGC: Open Geospatial Consortium, Inc.


Promulgates standards for geospatial

and location based services

SFS: Simple Feature Access for SQL



OGC standard for spatial databases

Very popular

WKT: Well Known Text

• Geometries

• Coordinate Systems

Sunday, October 24, 2010




WKB: Well Known Binary



Standards

Binary representation of geometries

HEX: Binary

“Extended” Standards



• EWKT

• EWKB & HEXEWKB

Sunday, October 24, 2010

Vendor-specific, PostGIS most popular

Embeds dimension and SRID inside






Standards

KML: Keyhole Markup Language


Google Earth/Maps Format

GML: Geometry Markup Language



XML & Enterprise-y

Great for architecture astronauts

WMS: Web Mapping Service


Serves up imagery

WFS: Web Feature Service


Sunday, October 24, 2010

Serves up vector data







Sunday, October 24, 2010

Acronym Soup

GeoJSON: Geometry JSON


Not OGC standard

SRS: Spatial Reference System

CRS: Coordinate Reference System


Synonym for SRS

EPSG: European Petroleum Survey Group

SRID: Spatial Reference Identifier



Integer representing a coordinate system

Typically corresponds to numbers assigned by

EPSG


Sunday, October 24, 2010

SFS Geometries

Point LineString LinearRing

Polygon

Multiple geometries may

be in a collection:

MultiPoint

MultiLineString

MultiPolygon

GeometryCollection


Sunday, October 24, 2010

KML

PROJ.4

OpenLayers

GML WKT GeoJSON GeoRSS

geodjango

GEOS


Sunday, October 24, 2010

History


Sunday, October 24, 2010

2006


Sunday, October 24, 2010

http://houstoncrimemaps.com/


Sunday, October 24, 2010

2007

“gis” branch created


Sunday, October 24, 2010

2008


Sunday, October 24, 2010

1.0


Sunday, October 24, 2010

A world-class geographic web framework

GeoDjango


Sunday, October 24, 2010

2009

1.1 Released


Sunday, October 24, 2010

2010

1.2 Released


Sunday, October 24, 2010

Real World


Sunday, October 24, 2010

http://everyblock.com/


Sunday, October 24, 2010

http://prototype.nytimes.com/represent//


http://projects.latimes.com/mapping-la/neighborhoods/

Sunday, October 24, 2010


Sunday, October 24, 2010

http://marinemap.org/


Sunday, October 24, 2010

http://about.nsw.gov.au/


Sunday, October 24, 2010

http://earth.burningman.com/


Sunday, October 24, 2010

GEOS

Spatial Libraries

GeoIP


Sunday, October 24, 2010

Python Interfaces

• Why?

• Powerful open source

libraries; temperamental



SWIG interfaces

ctypes enables all-Python

interfaces (no compilation

necessary)

Use of C APIs allows for high

degree of cross-platform

compatibility


Sunday, October 24, 2010

GEOS

Geometry Engine Open Source


from django.contrib.gis.geos import *

Sunday, October 24, 2010


pnt = GEOSGeometry('POINT(5 23)')

>>> pnt = Point(5, 23)

>>> pnt = fromstr('010100000000000000000

Sunday, October 24, 2010

014400000000000003740')


coords = ((0, 0), (0, 50), (50, 50),

(50, 0), (0, 0))

>>> poly = Polygon(coords)

>>> mpoly = MultiPolygon(poly)

Sunday, October 24, 2010


print poly.contains(pnt)

True

>>> poly.wkt

POLYGON ((0.0 0.0, 0.0 50.0, 50.0 50.0,

50.0 0.0, 0.0 0.0))

>>> poly.wkb


>>> poly.kml

'...

Sunday, October 24, 2010


Sunday, October 24, 2010

GDAL

Geospatial Data Abstraction Library


from django.contrib.gis.gdal import *

Sunday, October 24, 2010


ds = DataSource('ukraine_location.shp')

>>> layer = ds[0]

>>> len(layer)

35503

>>> layer.fields

['NAME', 'PLACE', ... ]

>>> kiev_features =

Sunday, October 24, 2010

[feat for feat in layer

if feat.get('NAME') == 'Київ']


s1 = SpatialReference(4326)

>>> s2 = SpatialReference('NAD83')

>>> geom = OGRGeometry('POINT(5 23)', s1)

>>> geom.transform(900913)

>>> print geom

POINT (556597.453 2632018.637)

Sunday, October 24, 2010


Sunday, October 24, 2010

GeoIP

IP-based Geolocation


from django.contrib.gis.utils import GeoIP

>>> g = GeoIP()

>>> print g.country('refractions.net')

{'country_name': 'Canada', 'country_code': 'CA'}

>>> print g.city('refractions.net')

{'city': 'Vancouver', 'region': 'BC',

'area_code': 0, 'longitude': -123.13330078125,

'country_code3': 'CAN', 'latitude': 49.25,

'postal_code': 'v6c2b5', 'dma_code': 0,

'country_code': 'CA', 'country_name': 'Canada'}

>>> print g.geos('refractions.net')

POINT (-123.1333007812500000 49.2500000000000000)

Sunday, October 24, 2010


Sunday, October 24, 2010

Geometry Fields


Sunday, October 24, 2010

models.py

from django.contrib.gis.db import models

class Zipcode(models.Model):

code = models.CharField(max_length=5)

mpoly = models.MultiPolygonField()

objects = models.GeoManager()

def __unicode__(self): return self.code


PostgreSQL/PostGIS:

MySQL:

Sunday, October 24, 2010

Show me the SQL


Sunday, October 24, 2010

Geometry Fields

• PointField

• LineStringField

• PolygonField

• MultiPointField

• MultiLineStringField

• MultiPolygonField

• GeometryCollectionField

• GeometryField


Geometry Field Options

• srid




Use this to specify the coordinate system used by the

field.

The SRID is an integer corresponding to an entry in

the spatial_ref_sys (OGC standard) spatial

database table.

Default is 4326 also known as WGS84; coordinates

in units of latitude/longitude.

• spatial_index


Sunday, October 24, 2010

Spatial indices are created by default; set to False to

disable.


Geometry Field Options*

• dim




Use this to specify the coordinate dimension of the

geometry column

May be set with 2 or 3

3 implies 2.5D support (PostGIS only)

• geography




Sunday, October 24, 2010

On PostGIS 1.5+ and SRID=4326 only

Set to True to use a geography column (instead of

geometry)

Enables arbitrary distance comparisons




Sunday, October 24, 2010

GeoManager

Your models must utilize this manager, or else

geographic queries will not work

Caveat: GeoManager required to query across

foreign key relations:

qs = Address.objects.filter(zipcode__poly__contains=pnt)

class Address(models.Model):

num = models.IntegerField()

street = models.CharField(max_length=100)

city = models.CharField(max_length=100)

state = models.USStateField()

zipcode = models.ForeignKey(Zipcode)

objects = models.GeoManager()


Sunday, October 24, 2010

Spatial Lookups


Sunday, October 24, 2010

Spatial Relationships

Overlaps Within

* Images from OGC spec

Crosses


Sunday, October 24, 2010

Spatial Lookup Types

Lookup PostGIS Oracle MySQL

bbcontains X X

bboverlaps X X

contains X X X

contained X X

coveredby X X

covers X X

crosses X X

disjoint X X X

equals X X X

exact X X X

intersects X X X

overlaps X X X

relate X X


Sunday, October 24, 2010

Spatial Lookup Types

Lookup PostGIS Oracle MySQL

same_as X X X

touches X X X

within X X X

left X

right X

overlaps_left X

overlaps_right X

overlaps_above X

overlaps_below X

strictly_above X

strictly_below X


Sunday, October 24, 2010

Lookup Parameters

• Spatial lookup types take a GEOS geometry

as the parameter

• The parameter may be any one of the

following:

• GEOS Geometry

• WKT

• HEX

• GeoJSON


Sunday, October 24, 2010

Automatic Transform

• If the lookup geometry has an SRID

different from the model field (a different

coordinate system), then transformation

SQL is automatically added

• If no SRID is specified in the geometry,

then that of the model field is assumed


Example

>>> from census.models import Zipcode

>>> from django.contrib.gis.geos import Point

# One point in WGS84 (lat/lon), the other in

# NAD83 / California zone 3 (US Survey Feet)

>>> pnt1 = Point(-122.084, 37.422)

>>> pnt2 = Point(6101703.20, 1980018.07, srid=2227)

>>> z1 = Zipcode.objects.get(mpoly__contains=pnt1)

>>> z2 = Zipcode.objects.get(mpoly__contains=pnt2)

>>> print z1, z2

94043, 94043

Sunday, October 24, 2010


Sunday, October 24, 2010

LayerMapping


LayerMapping

• Automates the tedium that goes into importing

data from a spatial data source into a GeoDjango

model.

>>> from django.contrib.gis.utils import LayerMapping

Sunday, October 24, 2010


Sunday, October 24, 2010

Measurement

Objects


Distance, D

• This object eases conversion between

distance units of measure.

>>> from django.contrib.gis.measure import D

>>> dist = D(ft=5280)

>>> dist.mi

1.0

>>> dist.km

1.609344

Sunday, October 24, 2010


Area, A

• For area (square) units of measure

>>> from django.contrib.gis.measure import Area

>>> a = Area(sq_mi=1)

>>> a.sq_km

2.589988110336

Sunday, October 24, 2010


Sunday, October 24, 2010


Sunday, October 24, 2010

Distance Queries


• Selection of the SRID for

geographic fields is very

important.

Limitations

• Remember: the world is not

flat!

• PostGIS can only do distance

comparisons between Point

Sunday, October 24, 2010

geometries at this time.

• PostGIS 1.5+ geography

type and Oracle do not

have this limitation.


Example

# Distances will be calculated from this point,

# which does _not_ have to be projected.

>>> pnt = Point(-96.876369, 29.905320, srid=4326)

# If numeric parameter, units of field (meters in this case)

# are assumed.

>>> qs = SouthTexasCity.objects.filter(

point__distance_lte=(pnt, 7000))

# Find all Cities w/in 7km of pnt

>>> qs = SouthTexasCity.objects.filter(

point__distance_lte=(pnt, D(km=7)))

# Find all Cities > 20 miles away from pnt.

>>> qs = SouthTexasCity.objects.filter(

point__distance_gte=(pnt, D(mi=20)))

# More obscure units, such as chains, are supported.

>>> qs = SouthTexasCity.objects.filter(

point__distance_gte=(pnt, D(chain=100)))

Sunday, October 24, 2010


Sunday, October 24, 2010

GeoQuerySet

Methods


Sunday, October 24, 2010

What are they?

• Methods that perform a spatial operation

on each geographic field in the

GeoQuerySet.

• Generally, output is stored in an attribute

on the model, usually the same name as the

method.

• Not available on MySQL.


Sunday, October 24, 2010

Keywords

• field_name

• By default, the first geographic field in the

model is used. Use this to specify a

different geo field on the model or a geo

field by ForeignKey relation.

• model_att

• Use this to customize the attribute name

stored on the model.





Sunday, October 24, 2010

Aggregate Methods

extent() / Extent


Returns a 4-tuple that is the geographic extent

of the queryset

extent3d() / Extent3D


Returns a 6-tuple that is the 3D extent of the

queryset. Django 1.2 and PostGIS only.

make_line() / MakeLine


Returns a LineString geometry constructed from

the point fields in the queryset




Sunday, October 24, 2010

Aggregate Methods

unionagg() / Union


Returns the union (a geometry) of every

geometry field in the queryset

collect() / Collect



Collect every geometry field into a single

geometry collection

Faster than a union but boundaries aren’t

dissolved



Sunday, October 24, 2010

Output Methods

Each of these methods attach a string

representation of the geometry field in the format

specified by the method:

• gml()

• kml()

• svg()

• geojson()

• geohash()


Sunday, October 24, 2010

Measurement Methods

• area()

• Attaches the area of each geometry field in the queryset

as an Area object.

• distance(geom)

• Attaches the distance from the geometry field to the

geometry parameter as a Distance object. Same

limitations apply as for distance queries.

• length()

• Attaches the length of each line string field in the

queryset as a Distance object.

• perimeter()

• Attaches the perimeter of each geometry field in the

queryset as a Distance object.


Sunday, October 24, 2010

Geometry Operations

• Each of these methods takes a geometry as

a parameter, and attaches the result of the

operation to each model in the queryset:

• difference(geom)

• intersection(geom)

• sym_difference(geom)

• union(geom)


Sunday, October 24, 2010

Geometry Methods

• centroid()

• Attaches the centroid (Point) of the geometry

field.

• envelope()

• Attaches the envelope (Polygon) of the

geometry field.

• point_on_surface()

• Attaches a Point guaranteed to be on the

surface of the geometry field.




Sunday, October 24, 2010

Geometry Methods

scale(x, y, z=0)


Attaches a geometry scaled according to the

given parameters.

translate(x, y, z=0)


Attaches a geometry moved according to the

given parameters.

• transform(srid)

• Transforms the geometry field to the given

SRID. No geometry is attached.


# Getting KML, GML, and SVG output at

# once on this model instance.

>>> z = Zipcode.objects

>>> z.kml

.gml().kml().svg()

.get(code='94043')

u' ...

>>> z.gml

u' ...

>>> z.svg

u'M -122.033972 -37.40544 -122.034372 ...

Sunday, October 24, 2010


# Getting the centroid, and attaching to

# an attribute named 'center'.

>>> z = Zipcode.objects

.centroid(model_att='center')

.get(code='94043')

>>> z.center.wkt

'POINT (-122.06289859 37.41981630)'

Sunday, October 24, 2010


# Getting neighboring ZIP codes using a

# buffer geometry, and returning the union.

>>> buf = z.mpoly.buffer(0.001)

>>> u = Zipcode.objects.filter(mpoly__intersects=buf)

.unionagg()

>>> u


Sunday, October 24, 2010


settings.py

DATABASES = {

'default': {

'ENGINE':'django.db.backends.postgresql_psycopg2',

'NAME': 'ukraine',

'USER': 'ukraine',

}

}

INSTALLED_APPS = (

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.sites',

'django.contrib.messages',

'django.contrib.admin',

)

Sunday, October 24, 2010


settings.py

DATABASES = {

'default': {

'ENGINE':'django.contrib.gis.db.backends.postgis',

'NAME': 'ukraine',

'USER': 'ukraine',

}

}

INSTALLED_APPS = (

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.sites',

'django.contrib.messages',

'django.contrib.admin',

'django.contrib.gis',

)

Sunday, October 24, 2010


from django.db import models

class Oblast(models.Model):

ua_name = models.CharField(max_length=50)

en_name = models.CharField(max_length=50)

Sunday, October 24, 2010

models.py

def __unicode__(self):

return u'%s (%s)' %

(self.ua_name, self.en_name)


from django.contrib.gis.db import models

class Oblast(models.Model):

ua_name = models.CharField(max_length=50)

en_name = models.CharField(max_length=50)

mpoly = models.MultiPolygonField()

Sunday, October 24, 2010

models.py

objects = models.GeoManager()

def __unicode__(self):

return u'%s (%s)' %

(self.ua_name, self.en_name)


load.py

from django.contrib.gis.utils import LayerMapping

from models import Oblast

def run():

# The shapefile and mapping dictionary

oblast_shp = os.path.join(UA_DATA_DIR, 'up.shp')

oblast_mapping = {'en_name': 'ADMIN_NAME',

'mpoly': 'MULTIPOLYGON',

}

Sunday, October 24, 2010

# Loading up the Oblast boundaries.

lm = LayerMapping(Oblast,

oblast_shp,

oblast_mapping,

source_srs=4326)

lm.save()


Sunday, October 24, 2010

admin.py

from django.contrib.gis import admin

from models import Oblast

class OblastAdmin(admin.OSMGeoAdmin):

search_fields = ('ua_name', 'en_name')

admin.site.register(Oblast, OblastAdmin)


views.py

from models import Oblast

from django.contrib.gis.shortcuts import \

render_to_kml

def oblast_kml(request, oblast_id):

qs = Oblast.objects

.filter(pk=int(oblast_id)).kml()

return render_to_kml('gis/kml/placemarks.kml',

{'places': qs})

Sunday, October 24, 2010


urls.py

from django.conf.urls.defaults import *

from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',

(r'^oblast/(?P\d+).kml$',

'ukraine.views.oblast_kml'),

(r'^admin/', include(admin.site.urls)),

)

Sunday, October 24, 2010


Sunday, October 24, 2010

Open Geo Ecosystem

GeoDjango is a part of a rich open source

geospatial ‘ecosystem’

• GIS industry has practically standardized on

using Python

• e.g., Python 2.6.4 interpreter built-in to

newest version of ArcGIS (ESRI is the

MicroSoft of GIS)


Sunday, October 24, 2010

More Python

• FeatureServer

• RESTful Geographic Feature Storage

• http://featureserver.org/

• TileCache

• Web Map Tile Caching

• http://tilecache.org/

• If serving up own maps, you’ll want this


Sunday, October 24, 2010

Cartography

• Mapnik

• C++ map library, with Python bindings

• Fast, beautiful maps; pain to setup

• http://mapnik.org

• MapServer

• Original open source map-making

software

• http://mapserver.org


Sunday, October 24, 2010

Desktop Analysis

• QGIS: Quantum GIS

• http://www.qgis.org

• uDig

• http://www.refractions.net/products/udig/

• Made by Refractions, same people behind

PostGIS


Sunday, October 24, 2010

Conclusion

Justin Bronn

• jbronn@geodjango.org

• twitter.com/jbronn

• twitter.com/geodjango

• http://geodjango.org/hg/ukraine

• Any questions?

Similar magazines