wiki:DeveloperGuidelines/GIS/InAction

Version 2 (modified by graeme, 10 years ago) ( diff )

--

How to use the GIS API within an application

This mini guide will show you how to use the GIS code in an Eden Application to display a map. The features that will be developed include:

  • A map of the zoomed into the area of interest
  • Markers displayed on the map for each point of interest
  • A pop-up displaying additional information when a marker is clicked
  • Multiple map layers which can be selected and deselected by the user

The code for this guide is taken from the survey module and can be found (at the time of writing) in the controllers/survey.py/series_map() function

Displaying the map

The display of the map is done with the show_map function

Code highlighting:

map = gis.show_map()
output["map"] = map

This will create a map and place it in a map container that has been added to the view. The relevant part of the view is as follows:

 <div class='survey_map-container'>
  {{try:}}
   {{=map}}
  {{except:}}
   {{pass}}
 </div>

This will display a plain map at the default zoom level. The next task will be to add some markers.

Adding the markers

The API supports two mechanisms to add markers. The first is a simple list of latitude and longitude points. This is the features parameter and it adds non-interactive points. For the survey application interactive points were required and to the slightly more complex feature_queries parameter is required. The first step is to create a query that will hold all of the points that are to be displayed. The code for this is as follows:

Code highlighting:

ctable = db.survey_complete
atable = db.survey_answer
gtable = db.gis_location

series_name = response.s3.survey_getSeriesFromID(series_id)
question_id = response.s3.survey_getLocationQuestionsIDForSeries(series_id)

query = (atable.question_id == question_id) & \
        (ctable.series_id == series_id) & \
        (atable.complete_id == ctable.id ) & \
        (atable.value == gtable.name)

response_locations =  db(query).select(atable.complete_id,
                                       gtable.uuid,
                                       gtable.id,
                                       gtable.name,
                                       gtable.lat,
                                       gtable.lon,
                                      )

The above is a query which links several tables together, the series_id has been passed into the function. The name of the series and the question_id are obtained from calls to functions defined in the model. The linking of the tables requires the series_id and the question_id, it then retrieves data from the gis_location table. Fully understanding this specific query is not essential to understanding how to add markers what is important is that you need construct a query that will return basic data from the gis_location table. The next step is to set up the features_query parameter, which can be done as follows:

Code highlighting:

feature_queries.append({ "name": "%s: Assessments" % series_name,
                         "query": response_locations,
                         "active": True })

This will create a layer with the name of the series_name and points that were set up by the query stored in response_locations. The active of true means that the layer will be turned on by default.

Finally the feature layer needs to be added to the call to show_map()

Code highlighting:

map = gis.show_map(feature_queries = feature_queries)

Adding colour to the marker

Some basic colour and shape can be added to the marker. These are added by extending the details returned by the query. A shape, size of the shape and colour of the shape can be added as follows:

Code highlighting:

response_colour_code = {-1:"#888888", # grey
                         0:"#000080", # blue
                         1:"#008000", # green
                         2:"#FFFF00", # yellow
                         3:"#FFA500", # orange
                         4:"#FF0000", # red
                         5:"#880088", # purple
                       }
if len(response_locations) > 0:
   for i in range( 0 , len( response_locations) ):
      complete_id = response_locations[i].survey_answer.complete_id
      response_locations[i].shape = "circle"
      response_locations[i].size = 5
      priority = analysisTool.priority(complete_id)
      response_locations[i].colour = response_colour_code[priority]

This will add small circular markers which are coloured depending upon a priority, which has been calculated by the call to analysisTool.priority(complete_id), again exactly how this works (and how the analysisTool object is created is not an important detail. The key is how the values are added to the response_location variable.

The shapes that are currently supported are defined in the gis_feature_query() function in models/03_gis.py as follows:

"circle", "square", "star", "x", "cross", "triangle"

The markers have now been added but when they are displayed because it is still using the default zoom they have probably been merged into a single cluster marker.

Zooming in to the required bounds

When multiple markers appear at the same location they are grouped together and replaced by a single cluster marker. If the zoom level is changed then more of the markers may take a unique location on the map and will be displayed using the feature marker. The bounds of the map can be calculated by calling the get_bounds() function as follows:

Code highlighting:

bounds = gis.get_bounds(response_locations.records)

This is then passed to the show_map function as follows:

Code highlighting:

map = gis.show_map(feature_queries = feature_queries,
                   bbox = bounds,
                  )

Adding a pop-up

The final feature to be added to the map is when clicking on the marker a pop-up appears displaying additional data. This is similar to the code that adds the marker and is placed in the same loop. The specific code is as follows:

Code highlighting:

url = URL(c="survey",
          f="series",
          args=[series_id,
                "complete",
                complete_id,
                "read"
               ]
         )
response_locations[i].popup_url = url
response_locations[i].popup_label = response_locations[i].gis_location.name

Again the details of the url is not important although it is important to have a url that will return data suitable for an ajax call.

Note: See TracWiki for help on using the wiki.