Sahana Eden

Mapping & GIS

Seeing data located on a Map helps decision makers to be able to make more meaningful decisions. Sahana Eden's Mapping Client can combine data from both it's own database & a range of external sources to provide a rich environment for display and analysis.

The GIS community within Sahana which has it's own home on the wiki:

Map Viewing Client

Sahana Eden's mapping client is based on OpenLayers & GeoExt.

OpenLayers provides access to a wide range of data sources, from public services like OpenStreetMap, Google Maps & Bing Maps through to GIS services based on OGC standards like WMS & WFS or feeds from other systems exposed as KML or GeoRSS.

GeoExt provides UI widgets to allow the user to interface with the map.

Map Service Catalog

These different 'Layers' are defined in Sahana Eden's 'Map Service Catalog', from which users can select which layers should be active in the client.

Map Layers using data from within the database simply requests the data through Web Services formatted as GeoJSON.

If multiple markers appear at the same location then they are 'clustered' together.

A 'refresh' strategy is available to reload the layer periodically so that a wall-mounted display can just reload the active layer(s) rather than the static basemap.

Spatial Infrastructure

Sahana Eden's mapping features are even more powerful when coupled with a GeoServer installation as this can expose many different data sources, such as Shapefiles or Topography Rasters, as WMS or WFS for ready display in Sahana.

Another very useful tool to complete an infrastructure is MapProxy as this allows WMS layers from external sources to be reprojected to be compatible with other data sources (typically allowing a WGS84 service to be accessible as an overlay with a Spherical Mercator basemap, such as OpenStreetMap or Google Maps).

Tip: Sahana Eden supports multiple Projections, but can only display one at a time!

This combination is what is used for the IFRC's Resource Mapping System.


The initial configuration is defined in models/ This then populates the gis_config table which is where subsequent modification should be done for this instance.

The system configuration can be inherited for both Personal configurations & Event configurations.  There is also the option for Country-based configurations to store the labels for the different levels of the hierarchy.

Currently the selection of active layers from the Catalog is global, but this is planned to be made per-Config.

Location Hierarchy

All locations are stored in the gis_location table, to which other resources link through the location_id() reusable field (foreign key). The location records are hierarchical through the use of 'parent' & 'path' fields. There are optimised routines in modules/s3/ to populate & search these fields. This hierarchy is flexible to accomodate different countries:

  • L0: Country
  • L1: State or Province
  • L2: District or County
  • L3: City, Town or Village
  • L4: Neighborhood

Location Selector

A Location Selector widget allows a simple location_id() reusable field in a source to provide an inline form to be able to select existing locations or create new ones, which includes the hierarchy & the ability to pinpoint the location on a Map, the rough position for which can be obtained through either GeoCoding (lookup of the entered street address or hierarchy) or GeoLocation (detection of the current user's location by the browser).

The widget is defined in modules/s3/

This makes use of JavaScript in static/scripts/S3/s3.locationselector.widget.js.
(Remember that any edits won't be visible unless you are running in debug mode or run the build script & refresh your browser cache)


As well as the main Mapping Client, there is an API to allow developers to be able to display customised data output relevant to a specific module on the Map.

This functionality is avaialble via the GIS module's show_map() function.

A simple example for a controller function would be:

table = db.mymodule_myresource
query = ( > 0) & \
        ( == table.location_id)
rows = db(query).select()
queries = [{name: "MyLayer",
            query: rows}]
map = gis.show_map(feature_queries=queries)
return dict(map=map)

& the view would include:


Full documentation for this API can be found in the source code or on the wiki:

Future Plans

There are plans to make use of optimised Spatial Queries when PostGIS is available by extending Web2Py's DAL. This will open up a range of possibilities for deeper analysis.

The Cube (pivot table) output is planned to be displayable on Maps - as both Shaded Polygons and Popups within centroid Markers containing the charts for that area.

The connection to GeoServer could be made more transparent by making use of it's REST API.

We could include a tool to be able to browse & select WMS services, auto-configuring an associated MapProxy to reproject, if-necessary.