Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Blocks + heatmaps

  • Loading branch information...
commit 4784205bcde8439deaca3f2e1419c76123ce2409 1 parent bb7c267
@zain authored
View
0  maps/blocks/__init__.py
No changes.
View
26 maps/blocks/load.py
@@ -0,0 +1,26 @@
+from django.contrib.gis.utils import LayerMapping
+from blocks.models import Block, Water
+
+block_mapping = {
+ 'poly' : 'POLYGON',
+}
+
+def blocks():
+ lm = LayerMapping(Block, '../data/blocks/tl_2010_06075_tabblock10.shp', block_mapping,
+ transform=False, encoding='iso-8859-1')
+ lm.save(silent=True)
+
+
+water_mapping = {
+ 'poly': 'POLYGON'
+}
+
+def water():
+ lm = LayerMapping(Water, '../data/water/tl_2009_06075_areawater.shp', water_mapping,
+ transform=False, encoding='iso-8859-1')
+ lm.save(silent=True)
+
+
+def clean():
+ for w in Water.objects.all():
+ Block.objects.filter(poly__intersects=w.poly).delete()
View
15 maps/blocks/models.py
@@ -0,0 +1,15 @@
+from django.contrib.gis.db import models
+
+class Block(models.Model):
+ poly = models.PolygonField()
+
+ objects = models.GeoManager()
+
+ def __unicode__(self):
+ return "Block #%s" % self.id
+
+
+class Water(models.Model):
+ poly = models.PolygonField()
+
+ objects = models.GeoManager()
View
16 maps/blocks/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
View
1  maps/blocks/views.py
@@ -0,0 +1 @@
+# Create your views here.
View
1  maps/settings.py
@@ -118,6 +118,7 @@
'django.contrib.staticfiles',
'maps.crime',
+ 'maps.blocks',
)
# A sample logging configuration. The only tangible logging
View
22 maps/templates/crime.html
@@ -2,25 +2,11 @@
<head>
<title>Maps Tutorial @ PyCon 2012</title>
- <link rel="stylesheet" href="http://code.leafletjs.com/leaflet-0.3.1/leaflet.css" />
+ <link rel="stylesheet" href="http://leaflet.cloudmade.com/dist/leaflet.css" />
<style type="text/css">
body { height:100% }
#mapdiv { display:block; position:absolute; top:0; left:0; width:100%; height:100%; }
-
-
- /*@-webkit-keyframes blinky {
- from { fill: red; stroke: red;}
- to { fill: green; stroke: green; }
- }
-
- .leaflet-clickable {
- -webkit-animation-name: blinky;
- -webkit-animation-duration: 2s;
- -webkit-animation-timing-function: ease;
- -webkit-animation-iteration-count: infinite;
- -webkit-animation-direction: alternate;
- }*/
</style>
</head>
@@ -28,7 +14,7 @@
<div id="mapdiv"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js" type="text/javascript"></script>
- <script src="http://code.leafletjs.com/leaflet-0.3.1/leaflet.js"></script>
+ <script src="http://leaflet.cloudmade.com/dist/leaflet.js"></script>
<script type="text/javascript">
@@ -43,7 +29,9 @@
crime_ids = new Array();
var sanfran = new L.LatLng(37.77540, -122.41941);
- map.addLayer(layers.midnight).setView(sanfran, 16);
+ map.addLayer(layers.midnight).setView(sanfran, 13);
+
+ map.addLayer(new L.TileLayer("http://localhost:8080/crime-heatmap/{z}/{x}/{y}.png", {opacity: 0.5}));
function crime_dot(latlng) {
return new L.Circle(latlng, 10, {color: "#F8CA00"});
View
0  maps/tileserver/__init__.py
No changes.
View
65 maps/tileserver/provider.py
@@ -0,0 +1,65 @@
+from blocks.models import Block
+from crime.models import Crime
+from django.contrib.gis.geos import Polygon
+from PIL import Image, ImageDraw, ImageFilter
+import ModestMaps
+
+
+GREEN = (90, 75, 40)
+RED = (0, 100, 40)
+WHITE = "rgb(255, 255, 255)"
+HEATMAP_MIN = 5
+HEATMAP_MAX = 15
+
+
+class CrimeHeatmapProvider:
+ def __init__(self, layer, *args, **kwargs):
+ self.layer = layer
+ self.provider = ModestMaps.OpenStreetMap.Provider()
+
+ def renderArea(self, width, height, srs, xmin, ymin, xmax, ymax, zoom):
+ # first, figure out the bounding box of the tile we're rendering
+ nw = self.layer.projection.projLocation(ModestMaps.Core.Point(xmin, ymin))
+ se = self.layer.projection.projLocation(ModestMaps.Core.Point(xmax, ymax))
+ max_lat = max(nw.lat, se.lat)
+ min_lat = min(nw.lat, se.lat)
+ max_lon = max(nw.lon, se.lon)
+ min_lon = min(nw.lon, se.lon)
+
+ bbox = Polygon.from_bbox((min_lon, min_lat, max_lon, max_lat))
+
+ # this obj is used to translate between lat/lon and pixel space
+ bound1 = ModestMaps.Geo.Location(min_lat, min_lon)
+ bound2 = ModestMaps.Geo.Location(max_lat, max_lon)
+ mmap = ModestMaps.mapByExtentZoom(self.provider, bound1, bound2, zoom)
+
+ # start drawing each block
+ pil_map = Image.new("RGBA", (width, height), (255,255,255, 0))
+ pil_draw = ImageDraw.Draw(pil_map)
+
+ for block in Block.objects.filter(poly__intersects=bbox):
+
+ # shape
+ locs = []
+ for c in block.poly.coords[0]:
+ pt = ModestMaps.Geo.Location(c[1], c[0])
+ loc = mmap.locationPoint(pt)
+ locs.append((loc.x, loc.y))
+
+ # color
+ count = Crime.objects.filter(pt__within=block.poly).count()
+
+ if count <= HEATMAP_MIN:
+ h, s, l = GREEN
+ elif count >= HEATMAP_MAX:
+ h, s, l = RED
+ else:
+ scale = float(count - HEATMAP_MIN) / float(HEATMAP_MAX - HEATMAP_MIN)
+
+ # scale all channels linearly between START_COLOR and END_COLOR
+ h, s, l = [int(scale*(end-start) + start) for start, end in zip(GREEN, RED)]
+
+ block_color = "hsl(%s, %s%%, %s%%)" % (h, s, l)
+ pil_draw.polygon(locs, fill=block_color)
+
+ return pil_map
View
14 maps/tileserver/tilestache.cfg
@@ -0,0 +1,14 @@
+{
+ "cache": { "name": "Test" },
+ "layers": {
+ "crime-heatmap": {
+ "provider": { "class": "tileserver.provider.CrimeHeatmapProvider" },
+ "preview": {
+ "lat": 37.78,
+ "lon": -122.42,
+ "zoom": 13,
+ "ext": "png"
+ }
+ }
+ }
+}
View
4 requirements.txt
@@ -6,3 +6,7 @@
Django==1.3.1
psycopg2==2.4.4
+TileStache==1.28.0
+PIL==1.1.7
+Werkzeug==0.8.3
+ModestMaps==1.4.0
Please sign in to comment.
Something went wrong with that request. Please try again.