This presentation introduces you to the basics of geospatial data and guides you through two examples for Django. First, you will learn how to program a small GeoDjango project. And secondly, you will learn how to extend the project with a few lines of code to turn the Django project into an API endpoint, which can be consumed by your mobile clients or java script single page applications.
3. Why could this presentation
be interesting to you?
Location data is key today!
4. What will you know in 30 min?
• Geospatial basics
• Geocode locations and other sources
• How to make geospatial queries
• How to serve geospatial data via APIs
32. Code Example
#!/usr/bin/python
from pyexif import pyexif
"""Sample code to demonstrate pyexif"""
file_name = “your_image.JPG"
result = pyexif.Exif(file_name)
print ("Your location: %s %s" % result.lat, result.lon)
GPS Latitude 44.100339 degrees
GPS Longitude121.772294 degrees
GPS Altitude 3109.044444 m
GPS Time Stamp 21:49:20.09
GPS Speed 0.26
GPS Img Direction Ref True North
GPS Img Direction 233.1646707
GPS Dest Bearing Ref True North
GPS Dest Bearing 233.1646707
GPS Date Stamp 2015:08:15
40. How to create kml data
structures?
• Keyhole Markup Languange (KML)
• XML based
• Developed by Google for Google Earth
• Package SimpleKML
https://pypi.python.org/pypi/simplekml/1.2.8
41. Code Example
""" Example code which will generate a kml file of
Portland's neighborhoods
Execute this script with the runscript command
of the Django extensions
$ python manage.py runscript simplekml_example -v3
"""
import simplekml
from project.models import Neighborhood
def run():
kml = simplekml.Kml()
neighborhoods = Neighborhood.objects.all()
for neighborhood in neighborhoods:
# this is just bare example
# normally use neighborhood.poly.kml to the kml data
kml.newpolygon(
name=neighborhood.name,
outerboundaryis=list(
neighborhood.poly.boundary.coords[0]),
innerboundaryis=list(
neighborhood.poly.boundary.coords[0])
)
kml.save("portland_neighborhoods.kml")
44. Motionless
• pip install motionless
• Package by Ryan Cox
• Supports street, satellite, and terrain maps
• Based on Google Static Map API
• Watch out for the rate limit
45. Code Example
#!/usr/bin/python
"""Sample code to demonstrate motionless"""
import requests
from StringIO import StringIO
from PIL import Image
from slugify import slugify
from motionless import DecoratedMap, AddressMarker
address = "70 NW Couch St, Portland, OR 97209"
# generate static map object
dmap = DecoratedMap(maptype='satellite', zoom=18)
dmap.add_marker(AddressMarker(address))
# download the static image
response = requests.get(dmap.generate_url())
if response.status_code == 200:
image = Image.open(StringIO(response.content))
image.save('.'.join([slugify(address), 'png']))
else:
print ("Download error with status code %s",
response.status_code)
49. GeoDjango
• Created by Justin Bronn
• Part of the Django core
• Supports various spatial databases and libraries
• Let’s you define geospatial attributes in your
models
52. GeoDjango
Spatial Lookups
bbcontains, bboverlaps, contained, contains,
contains_properly, coveredby, covers,
crosses, disjoint, equals, exact, same_as,
intersects, overlaps, relate, touches, within,
left, right, overlaps_left, overlaps_right,
o v e r l a p s _ a b o v e , o v e r l a p s _ b e l o w,
strictly_above, strictly_below
55. GeoDjango - Example
• Simple GeoModel
• Demonstrate the GeoDjango Admin
• How to save Points
• How to search for Points within a Polygon
• Leaflet Maps
68. REST+GIS - Serializer
from .models import CallLocation
from rest_framework import serializers
from rest_framework_gis import serializers as gis_serializer
class CallSerializer(gis_serializer.GeoModelSerializer):
call_type = serializers.StringRelatedField()
class Meta:
model = CallLocation
fields = ('status_id', 'address', 'location',
'call_type', 'timestamp')
geo_field = 'point'
pip install djangorestframework-gis
69. REST+GIS - Serializer
{
"status_id": "650065994463838208",
"address": "2200 NE 36th Ave, Portland, OR 97212, USA",
"location": "SRID=4326;POINT (-122.6259952999999996 45.5384747000000019)",
"call_type": "PROPERTY LOST, FOUND, RECOVERED ",
"timestamp": "2015-10-02T21:53:05Z"
}
{
"status_id": "650864005439840258",
"address": "8900 SW 30th Ave, Portland, OR 97219, USA",
"location": {
"type": "Point",
"coordinates": [
-122.7077201,
45.4608926
]
},
"call_type": "THEFT - COLD ",
"timestamp": "2015-10-05T02:44:06Z"
}
Without the djangorestframework-gis
With the djangorestframework-gis
70. REST+GIS - View
# Django Packages
# 3rd party
from rest_framework import viewsets
# project packages
from .models import CallLocation
from .serializers import CallSerializer
class CallLocationViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
serializer_class = CallSerializer
No magic here.
71. REST+GIS - Front end
$scope.getMarkers = function () {
$scope.state.markers = [];
Call.query().$promise.then(function(data) {
data.forEach(function(call){
$scope.state.markers.push((
[call.location.coordinates[1],
call.location.coordinates[0]]))
});
}, function(errResponse) {
console.log('REST error');
});
};
...
<div class="container-fluid">
<map
zoom="10" center="[45.5200, -122.6819]"
on-center-changed="getMarkers()">
<marker ng-repeat="p in state.markers"
position="{{ p }}"></marker>
</map>
</div>
AngularJS with ngmap
73. Limit requests by the
using bounding box
# views.py
from rest_framework import viewsets
from rest_framework_gis.filters import InBBOXFilter
class CallLocationViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
serializer_class = CallSerializer
# bbox defines which column is used to select the objects
returned
# to the frontend
bbox_filter_field = 'location'
# filter settings
filter_backends = (InBBOXFilter, )
# the overlapping allows polygons to be partially be part of the
bbox
bbox_filter_include_overlapping = True # not needed for
PointFields
pip install django-filters
74. Limit requests by the
using bounding box
// Change AngularJS call
_getPolygonStr = function (map){
var bounds = [];
bounds[0] = map.getBounds().getSouthWest().lng(); // min lon
bounds[1] = map.getBounds().getSouthWest().lat(); // min lat
bounds[2] = map.getBounds().getNorthEast().lng(); // max lon
bounds[3] = map.getBounds().getNorthEast().lat(); // max lat
return bounds.join(",");
};
...
if ($scope.map) {
bounds = _getPolygonStr($scope.map);
};
...
Call.query({in_bbox: bounds}).$promise.then(function(data) {
data.forEach(function(call){
…
});
}
/api/calls/?in_bbox=-123.093887304,45.327228800,-122.269912695,45.71211299
75. Recap
• SRID, Projections
• How to get geodata (geocoding)
• How to store it
• How to query it
• How to create an API endpoint