Grok, the Paleolithic Geographer

Update (2008-02-19)

The batlas demo is gone. Please see instead http://sgillies.net/kw/demo.

I've wanted to make an easily deployed and transparent application to demonstrate what can be done with zgeo.geographer and friends, the new geospatial packages for Zope, and finally inspiration struck. I chose to write a Grok project using the aptly named grokproject. Grok aims to simplify Zope to the degree that a caveman could use it. Convention over configuration and all that. It certainly allows a developer a clear view of the zgeo.* packages in action.

The paleolithic geographer isn't concerned about fancy geographic information systems. He wants a know-where-things-are system; hence the name of my demo app: Knowhere (pronounced "Oog"). Knowhere annotates resources with geographic location metadata and publishes them using GeoRSS (Atom, specifically) or KML so that a even a caveman can visualize them in the context of other geographic information on the Web.

Building and launching Knowhere is a 5 step process that requires Python 2.4, gmake, gcc, etc. Within 15 minutes you can be publishing geo-referenced content. Start by getting the code from the PrimaGIS Subversion repository:

$ svn co http://svn.gispython.org/svn/zope/Knowhere/trunk Knowhere

Cd into that new directory and bootstrap the project:

$ /usr/bin/python2.4 bootstrap.py

Build it out:

$ ./bin/buildout

This downloads and builds 2 C/C++ libraries (GEOS and spatialindex), and fetches a heap of eggs. It will take a few minutes.

When the build out is complete, edit 2 configuration files. In parts/zopectl/zope.conf, set the port number to an open value. In parts/app/site.zcml, change the management password from "admin" to one less obvious. That done, start up the application:

$ ./bin/zopectl fg

Browse to http://localhost:8080 (let's presume that's where it's at), authenticate, and you should see a Grok management page like this:

http://sgillies.net/images/knowhere-apps.jpg

Add a new application named "cities" as shown, and then browse to http://localhost:8080/cities where you'll be faced with one of the ugliest forms ever seen. Fill it out like so

  • name: fort-collins
  • title: Fort Collins
  • description: Fort Collins, Colorado, USA
  • text: The little geospatial hothouse on the prairie
  • geometry type: Point
  • coordinates: [-105.08, 40.59]

using a GeoJSON coordinate representation, and submit. Click through to the new placemark page, which should be something like this. There are 5 fields on that page. Look at the Knowhere model (src/knowhere/app.py) and you'll see that the Placemark class actually only has one attribute:

class Placemark(grok.Model):

    def __init__(self, text=None):
        self.text = text

Where are the other fields? Grok gives you Dublin Core metadata annotations automatically. No configuration required. Peek into the model's configuration (src/knowhere/configure.zcml) and you'll see that adding geographic location metadata from zgeo.geographer to any model class is as simple as:

...
<include package="zgeo.geographer"/>

<class class=".app.Placemark">
  <implements interface="zgeo.geographer.interfaces.IGeoreferenceable"/>
</class>
...

The zgeo.kml package provides KML representations of containers of georeferenceable objects. Browse to http://localhost:8080/cities/@@kml-document for an example. The zgeo.atom package provides Atom entry and feed document views with GeoRSS. For examples, browse to http://localhost:8080/cities/fort-collins/@@atom-link-entry and http://localhost:8080/cities/@@atom-search-feed.

Knowhere also includes an R-Tree spatial index from zgeo.spatialindex. Containers of the model can be made indexable as easily as:

...
<include package="zgeo.spatialindex"/>

<class class=".app.Demo">
  <implements interface="zgeo.spatialindex.interfaces.ISpatiallyIndexable"/>
</class>
...

Browse to http://localhost:8080/cities/@@manage-index to see the index management form. Future versions of Knowhere will include georeferencing event handlers, but for now you must rebuild the index manually after adding placemarks. Lame indeed, but this is just a demo (I already have a working handler for Plone AT content types). The management screen in the image below is from my demo application at http://sgillies.net/kw/batlas, which had 2 placemarks at the time I wrote this post.

http://sgillies.net/images/knowhere-zmi.jpg

The spatial index allows fast bounding box queries. The atom search feed accepts a bbox parameter of the form minimum_longitude,minimum_latitude,maximum_longitude,maximum_latitude. For example, see http://sgillies.net/kw/batlas/@@atom-search-feed?bbox=-5,50,5,55 [map].

http://sgillies.net/images/knowhere-ge.jpg

As you can see in the image above, zgeo.* can handle polygon geometries as well as lines and points. View that demo application in Google Earth using http://sgillies.net/kw/batlas/@@kml-document.

There's more work to do on Knowhere and zgeo.*. The index might be better as a local utility, and I should be using an integer id utility instead of hashing content names. The HTML is wretched and the URLs cry out for rewriting (which Grok supports right out of the box). Any Zope user that can look past those warts might start to get some good ideas from Knowhere.