Geospatial Web Frameworks with Relational Databases and Python


How can emerging open source technologies be used to create functional, dynamic spatial applications for the web?

To provide one answer to this question, this Python web app, which takes advantage of functionality provided by Flask and PostGIS, as well as several other third-party modules, was developed to model a compelling industry use-case.

This app displays the contents of a relational spatial database using the Leaflet web mapping library. Using the same database, a functional spatial REST API has also been constructed to return the results of user-defined queries in GeoJSON form. This application was developed locally on a Centre of Geographic Sciences student laptop and then deployed to a live production environment allowing it to be accessed via the internet.

This product is produced as a portion of the requirements of the Geographic Sciences Program at the Centre of Geographic Sciences, NSCC, Lawrencetown, Nova Scotia. The product is unedited, unverified and intended for educational purposes only. © 2019 COGS

Produced by: Nicole White
Date: March 2019

Guelph Urban Tree Visualization API Reference

This API provides tree inventory details for the city of Guelph, Wellington County, Ontario.

Sample Request and Reponse

The following example requests all ash (Fraxinus genus) trees in poor health, within Ward 1. This query could be used to identify specimens vulnerable to the Emerald Ash Borer, informing pest management strategies.

http://nico13.xyz/flaskapp/tree_inv/api/v0.1/tree?genus=Fraxinus&health=Poor&ward=1

This request can be tested by entering it as a URL in your web browser.

Guide

An API request uses the following form:

http://nico13.xyz/flaskapp/tree_inv/api/v0.1/tree?parameters

Please ensure that the URL is properly encoded, with no invalid characters. Any number of additional parameters may be added using the & symbol. All parameters are optional, and if none are supplied, the entire tree inventory dataset will be returned.

The following parameters are available:

common_name - Tree species common name, e.g., Kentucky Coffee Tree
genus - Genus to which the specimen belongs, e.g., Acer for maple.
species - The botanical species name of the tree, e.g., saccharinum is the species name for sugar maple. This parameter is most effective when a genus is also specified, due to completely different populations that share a species name (e.g., Red Maple, Acer rubrum, and Red Mulberry, Morus rubrum.)
family - The name of a specimens' botanical family. Example: Rosaceae, the rose family, includes apples, peaches, and plums.
division - This parameter has four possible options:
  • Magnoliophyta (Flowering Plants)
  • Coniferophyta (Conifers)
  • Other
  • Unknown
Note: Some browsers may require that the spaces be replaced with %20, i.e., Magnoliophyta%20(Flowering%20Plants)

owner - Possible inputs:
  • Boundary
  • City
  • Private
  • Unknown


health - Possible inputs:
  • Excellent
  • Good
  • Fair
  • Poor
  • Dead


ward The municipal ward area the tree can be found in. This is an integer value from 1 to 6, representing the ward's ID number. Performs a geometric intersection of a polygon wards layer to retrieve the results dynamically.

oh_util - Are overhead utilities (power lines, etc.) present?
  • Yes
  • No
  • Unknown


Responses


Responses are served in GeoJSON format and are ready to be used within a desktop GIS client or within a web map.

Example output for http://www.nico13.xyz/flaskapp/tree_inv/api/v0.1/tree?genus=Gingko&health=Excellent&ward=1:

{
  "features": [
    {
      "geometry": {
        "coordinates": [
          -80.220270197,
          43.561350074
        ],
        "type": "Point"
      },
      "properties": {
        "id": 208,
        "name": 121
      },
      "type": "Feature"
    },
    {
      "geometry": {
        "coordinates": [
          -80.236551202,
          43.55716402
        ],
        "type": "Point"
      },
      "properties": {
        "id": 1657,
        "name": 121
      },
      "type": "Feature"
    },
    {
      "geometry": {
        "coordinates": [
          -80.22269701,
          43.559982509
        ],
        "type": "Point"
      },
      "properties": {
        "id": 1693,
        "name": 22
      },
      "type": "Feature"
    },
    {
      "geometry": {
        "coordinates": [
          -80.21558168,
          43.574105444
        ],
        "type": "Point"
      },
      "properties": {
        "id": 1776,
        "name": 121
      },
      "type": "Feature"
    }
  ],
  "type": "FeatureCollection"
}

Other Request Forms

A known specimen may be queried by its ID number like so:

/tree_inv/api/v0.1/tree/

A specific ward may be queried by its number, returning all trees within that ward:

/tree_inv/api/v0.1/ward/

Use With Leaflet

The following code demonstrates how the data might be incorporated into a web map using the Leaflet JavaScript library and Ajax:

var map = L.map('map').setView([43.542003, -80.248199], 13);
    	L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}{r}.{ext}', {
    	attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    	subdomains: 'abcd',
    	minZoom: 1,
    	maxZoom: 18,
      ext: 'png'
    	}).addTo(map);
tree_url = 'http://nico13.xyz/flaskapp/tree_inv/api/v0.1/tree?genus=Fraxinus&health=Poor&ward=1';
var tree = new L.GeoJSON.AJAX(tree_url).addTo(map);



The Leaflet example on this page also demonstrates how interactive functionality could be added with the addition of a form for user input.

Use the form below to filter results:

Genus: Health: Overhead Utilities Present:
Click here to download the complete technical report.