Monday, November 3, 2008

GIS with Haskell 1

It's time to bite the bullet and do some GIS Haskelling.

My first project is to develop a simple map server in Haskell. Here are the ingredients:
  • PostgresSQL + PostGIS
  • Some data to put into the database. For this I sourced some Australian suburb boundaries.
  • A library for manipulation GIS geometry, GEOS. In particular this provides functions to parse WKT strings from the database into geometry structures.
  • Haskell CGI package
  • Haskell bindings to the GEOS library.
  • Extension to HaXML adding SVG combinators.
The definition of the map is specified using a set of combinators resulting in a DSL looking a lot like the MapFile format of MapServer.

The following gives a map showing the suburbs centred on the city of Melbourne.
ex0 = map (connection "host=localhost user=postgres password=postgres dbname=australia"
`u` size 700 700
`u` extents 144.897079467773 (-37.8575096130371) 0.16821284479996734 0.1410504416999956
`u` layer ( table "suburbs"
`u` geometry "the_geom"
`u` klass ( style ( outlinecolour 255 0 0 1
`u` colour 100 255 100 1))
))

The resulting SVG file when viewed looks like:
The components that make up the map definition:
  • connection - supplies the database connection parameters,
  • size - is the size of the SVG output to be generated.
  • extents - is the extents of the map in world coordinates.
  • layer - this defines a layer. The table property defines the database table to use, the geometry property defines the column name to use. The klass parameter defines the style to use for drawing the geometry.
Layers are the key to this. Basic layers associate a geometry from the database with a style to be used when drawing the geometry.

A slightly more complex example with two layers is the following:
ex1 = map (connection "host=localhost user=postgres password=postgres dbname=australia"
`u` size 700 700
`u` extents 144.897079467773 (-37.8575096130371) 0.16821284479996734 0.1410504416999956
`u` layer ( table "suburbs"
`u` geometry "the_geom"
`u` labelitem "name_2006"
`u` klass ( style ( outlinecolour 255 0 0 1
`u` colour 100 255 100 1))
`u` label (colour 255 255 0 1))
`u` layer (table "suburbs"
`u` geometry "geomunion(the_geom)"
`u` klass ( style ( outlinecolour 0 0 0 1 `u` width 4)))
)

This is the same as before but with a new layer that provides a thick border around the edge of all the suburb boundaries:

Next steps are to source some population data, to colour code the suburbs depending on population and to include a legend.

7 comments:

Mark Mansour said...

It took me ages to find those Aussie shapefiles. I'm glad they're of use to you. Haskell looks really interesting too. Nice work

Joe said...

Are the bindings to GEOS public? I have recently been wanting to use haskell for some gis work but have been stuck at this point.

Thanks,

Joe

Guilhem said...
This comment has been removed by the author.
Guilhem said...

Great stuff. Are you planning on releasing the code? A map server in Haskell would be awesome.

Poundstone said...

I'm in the process of getting the GEOS bindings package to build correctly and with a minimum of fuss.

A map server in Haskell will take a little longer :)

andrew said...

great idea! i was about to pose the construction of a haskell map server as a m.sc. thesis project, but you have already done it - great. is the code available? it would be useful for further development (open source, of course).

andrew frank
geoinformation - TU Wien

Martin said...

Good to hear there is Haskell GIS stuff happening -and in Melbourne! I know this is an old post, but just wondering whether you have released the GEOS bindings at all somewhere...
Cheers.

About Me

Melbourne, Australia
I work for GE in Melbourne Australia. All views do not necessarily represent GE.