Chapter 9. Web Frameworks for Python Geo-Spatial Development

In this chapter, we will examine various options for developing web-based geo-spatial applications. We will explore a number of important concepts used by web applications, and geo-spatial web applications in particular, as well as studying some of the important open protocols used by these applications and a number of tools that you can use to implement your own web-based geo-spatial systems.

In particular, we will:

  • Examine the architecture used by web applications
  • Learn about web application stacks
  • Explore the concept of a "full stack" web application framework
  • Learn about web services
  • See how map rendering can be implemented as a standalone web service
  • Learn how tile caching can be used to improve performance
  • See how web servers act as a frontend to a web application
  • Explore how JavaScript user interface libraries can enhance a web application's user interface
  • See how "slippy maps" can be created using an application stack
  • Examine the web frameworks available for developing geo-spatial applications
  • Learn about some of the important open protocols for working with geo-spatial data within a web application
  • Explore some of the major tools and frameworks available for building your own geo-spatial web applications

Web application concepts

In this section, we will examine a number of important concepts related to web-based application development in general, as well as concepts specific to developing geo-spatial applications that are accessed via a web server.

Web application architecture

There are many ways you can approach the development of a web-based application. You can write your own code by hand, for example as a series of CGI scripts, or you can use one of the many web application frameworks that are available. In this section, we will look at the different ways web applications can be structured so that the different parts work together to implement the application's functionality.

A bare-bones approach

In Chapter 7, we created a simple web application named DISTAL. This web application was built using CGI scripts to provide distance-based identification of towns and other features. DISTAL is a good example of a "bare bones" approach to web application development, using nothing more than a web server, a database, and a collection of CGI scripts:

A bare-bones approach

The advantage of this approach is simplicity: you don't need any special tools or knowledge to write a web application in this way. The disadvantage is that you have to do all the low-level coding by hand. It's a very tedious and slow way of building a web application, especially a complex one with lots of features.

Web application stacks

To simplify the job of building web-based applications, you generally make use of existing tools that allow you to write your application at a higher level. For example, you might choose to implement a complex web application in the following way:

Web application stacks

This "stack" of tools works together to implement your application: at the lowest level, you have a data tier that deals with the storage of data. In this case, the application uses MySQL for the database and SQLAlchemy as an object-relational mapper to provide an object-oriented interface to this database. The application tier contains the application's business logic, as well as various libraries to simplify the job of building a stateful and complex web application. Finally, the presentation tier deals with the user interface, serving web pages to the users, mapping incoming URLs to the appropriate calls to your business logic, and using a sophisticated JavaScript library to build complex user interfaces within the user's web browser.

Note

Different terms are sometimes used for these three tiers. For example, the data tier is sometimes called the data access layer, and the application tier is sometimes called the business logic layer. The concept is the same, however.

Don't be too concerned about the details of this particular application's architecture—the main thing to realize is that there is a "stack" of tools all working together, where each tool makes use of the tools below it. Also, notice the complexity of this system: this application depends on a lot of different tools and libraries. Developing, deploying, and upgrading an application like this can be challenging because it has so many different parts.

Web application frameworks

To avoid the complexity of mixing and matching so many different parts, web developers have created various frameworks that combine tools to provide a complete web development system. Instead of having to select, install, and deploy ten different libraries, you can simply choose a complete framework that brings a known good set of libraries together, and adds its own logic to provide a complete "batteries included" web development experience. Most of these toolkits provide you with built-in logic to handle tasks such as:

  • Defining and migrating your database schema
  • Keeping track of user sessions, and handling user authentication
  • Building sophisticated user interfaces, often using AJAX to handle complex widgets within the user's browser
  • Automatically allowing users to create, read, update, and delete records in the database (the so-called CRUD interface)
  • Simplifying the creation of database-driven applications through standard templates and recipes

There is a lot more to these frameworks, but the important thing to remember is that they aim to provide a "full stack" of features to allow developers to quickly implement the most common aspects of a web application with a minimum of fuss. They aim to provide rapid application development (RAD) for web-based systems.

There are a number of Python-based web application frameworks available, including TurboGears, Django, Zope, Web2py, and Webware. Some of these frameworks also include extensions for developing geo-spatial web applications.

Web services

A web service is a piece of software that has an application programming interface (API) that is accessed via the HTTP protocol. Web services generally implement the behind-the-scenes functionality used by other systems; they don't generally have an interface that allows end users to access them directly.

Web services are accessed via a URL; other parts of the system send a request to this URL and receive back a response, often in the form of XML or JSON encoded data, which is then used for further processing.

Tip

Types of web services

There are two main types of web services you are likely to encounter: RESTful web services, which use parts of the URL itself to tell the web service what to do, and "big web services" that typically use the SOAP protocol to communicate with the outside world.

REST stands for REpresentational State Transfer. This protocol uses sub-paths within the URL to define the request to be made. For example, a web service might use the following URL to return information about a customer:

http://myserver.com/webservice/customer/123

In this example, customer defines what type of information you want, and 123 is the internal ID of the desired customer. RESTful web services are very easy to implement and use, and are becoming increasingly popular with web application developers.

A "big web service", on the other hand, has just one URL for the entire web service. A request is sent to this URL as an XML-format message, and the response is sent back, also as an XML-formatted message. The SOAP protocol is often used to describe the message format and how the web service should behave. Big web services are popular in large commercial systems, despite being more complex than their RESTful equivalent.

Let's take a look at a simple but useful web service. This CGI script, called greatCircleDistance.py, calculates and returns the great-circle distance between two coordinates on the Earth's surface. Here is the full source code for this web service:

#!/usr/bin/python

import cgi
import pyproj

form = cgi.FieldStorage()

lat1 = float(form['lat1'].value)
long1 = float(form['long1'].value)
lat2 = float(form['lat2'].value)
long2 = float(form['long2'].value)

geod = pyproj.Geod(ellps="WGS84")
angle1,angle2,distance = geod.inv(long1, lat1, long2, lat2)

print 'Content-Type: text/plain'
print
print distance

Because this is intended to be used by other systems rather than end users, the two coordinates are passed as query parameters, and the resulting distance (in meters) is returned as the body of the HTTP response. Because the returned value is a single number, there is no need to encode the results using XML or JSON; instead, the distance is returned as plain text.

Let's now look at a simple Python program that calls this web service:

import urllib

URL = "http://127.0.0.1:8000/cgi-bin/greatCircleDistance.py"

params = urllib.urlencode({'lat1'  : 53.478948, # Manchester.
                           'long1' : -2.246017,
                           'lat2'  : 53.411142, # Liverpool.
                           'long2' : -2.977638})

f = urllib.urlopen(URL, params)
response = f.read()
f.close()

print response

Running this program tells us the distance in meters between these two coordinates, which happen to be the locations of Manchester and Liverpool in England:

% python callWebService.py 
49194.46315

While this might not seem very exciting, web services are an extremely important part of web-based development. When developing your own web-based geo-spatial applications, you may well make use of existing web services, and potentially implement your own web services as part of your web application.

Map rendering

We saw in Chapter 8 how Mapnik can be used to generate good-looking maps. Within the context of a web application, map rendering is usually performed by a web service that takes a request and returns the rendered map image file. For example, your application might include a map renderer at the relative URL /render that accepts the following parameters:

  • minX, maxX, minY, maxY

    The minimum and maximum latitude and longitude for the area to include on the map.

  • width, height

    The pixel width and height for the generated map image.

  • layers

    A comma-separated list of layers that are to be included on the map. The available predefined layers are: coastline, forest, waterways, urban, and street.

  • format

    The desired image format. Available formats are: png, jpeg, and gif.

This hypothetical /render web service would return the rendered map image back to the caller. Once this has been set up, the web service would act as a black box providing map images upon request for other parts of your web application.

As an alternative to hosting and configuring your own map renderer, you can choose to use an openly available external renderer. For example, OpenStreetMap provides a freely-available map renderer for OpenStreetMap data at:

Tile caching

Because creating an image out of raw map data is a time- and processor-intensive operation, your entire web application can be overloaded if you get too many requests for data at any one time. As we saw with the DISTAL application in Chapter 7, there is a lot you can do to improve the speed of the map-generation process, but there are still limits on how many maps your application can render in a given time period.

Because the map data is generally quite static, you can get a huge improvement in your application's performance by caching the generated images. This is generally done by dividing the world up into tiles, rendering tile images as required, and then stitching the tiles together to produce the desired map:

Tile caching

Tile caches work in exactly the same way as any other cache:

  • When a tile is requested, the tile cache checks to see if it contains a copy of the rendered tile. If so, the cached copy is returned right away.
  • Otherwise, the map rendering service is called to generate the tile, and the newly-rendered tile is added to the cache before returning it back to the caller.
  • As the cache grows too big, tiles that haven't been requested for a long time are removed to make room for new tiles.

Of course, tile caching will only work if the underlying map data doesn't change. As we saw when building the DISTAL application, you can't use a tile cache where the rendered image varies from one request to the next.

One interesting use of a tile cache is to combine it with map overlays to improve performance even when the map data does change. Because the outlines of countries and other physical features on a map don't change, it is possible to use a map generator with a tile cache to generate the base map onto which changing features are then drawn as an overlay:

Tile caching

The final map could be produced using Mapnik, by drawing the overlay onto the base map, which is accessed using a RasterDataSource and displayed using a RasterSymbolizer. If you have enough disk space, you could even pre-calculate all of the base map tiles and have them available for quick display. Using Mapnik in this way is a fast and efficient way of combining changing and non-changing map data onto a single view—though there are other ways of overlaying data onto a map, as we shall see in the section on OpenLayers.

Web servers

In many ways, a web server is the least interesting part of a web application: the web server listens for incoming HTTP requests from web browsers and returns either static content or the dynamic output of a program in response to these requests:

Web servers

There are many different types of web servers, ranging from the pure-Python SimpleHTTPServer included in the Python Standard Library, through more fully-featured servers such as CherryPy, and of course the most popular industrial-strength web server of them all: Apache.

One of the main consequences of your choice of web server is how fast your application will run. Obviously, a pure-Python web server will be slower than a compiled high-performance server such as Apache. In addition, writing CGI scripts in Python will cause the entire Python interpreter to be started up every time a request is received—so, even if you are running a high performance web server, your application can still run slowly if you don't structure your application correctly. A slow web server doesn't just affect your application's responsiveness: if your server runs slowly, it won't take many requests to overload the server.

Another consequence of your choice of web server is how your application's code interacts with the end user. The HTTP protocol itself is stateless—that is, each incoming request is completely separate, and a web page handler has no way of knowing what the user has done previously unless you explicitly code your pages in such a way that the application's state is passed from one request to the next (for example, using hidden HTML form fields as we did in our implementation of the DISTAL application in Chapter 7).

Because some web servers run your Python code only when a request comes in, there is often no way of having a long-running process sitting in the background that keeps track of the user's state or performs other capabilities for your web page handlers. For example, an in-memory cache might be used to improve performance, but you can't easily use such a cache with CGI scripts as the entire interpreter is restarted for every incoming HTTP request.

One of the big advantages of using a web application framework is that you don't need to worry about these sorts of issues: in many cases, the web framework itself will include a simple web server you can use for development, and provides a standard way of using industry-standard web servers when you deploy your application. The challenges of performance, keeping track of the user's state, and using long-running processes will all have been solved for you by the web framework. It is, however, worthwhile to understand some of the issues involved in the choice of a web server, and to know where the web server fits within the overall web application. This will help you to understand what your web framework is doing, and how to configure and deploy it to achieve the best possible performance.

User interface libraries

While it is easy to build a simple web-based interface in HTML, users are increasingly expecting web applications to compete with desktop applications in terms of their user interface. Selecting objects by clicking on them, drawing images with the mouse, and dragging-and-dropping are no longer actions restricted to desktop applications.

AJAX (Asynchronous JavaScript and XML) is the technology typically used to build complex user interfaces in a web application. In particular, running JavaScript code on the user's web browser allows the application to dynamically respond to user actions, and make the web page behave in ways that simply can't be achieved with static HTML pages.

While JavaScript is ubiquitous, it is also hard to program in. The various web browsers in which the JavaScript code can run all have their own quirks and limitations, making it hard to write code that runs the same way on every browser. JavaScript code is also very low level, requiring detailed manipulation of the web page contents to achieve a given effect. For example, implementing a pop-up menu requires the creation of a<DIV> element that contains the menu, formatting it appropriately (typically using CSS), and making it initially invisible. When the user clicks on the page, the pop-up menu should be shown by making the associated<div> element visible. You then need to respond to the user mousing over each item in the menu by visually highlighting that item and un-highlighting the previously-highlighted item. Then, when the user clicks, you have to hide the menu again before responding to the user's action.

All this detailed low-level coding can take weeks to get right—especially when dealing with multiple types of browsers and different browser versions. Since all you want to do in this case is have a pop-up menu that allows the user to choose an action, it just isn't worth doing all this low-level work yourself. Instead, you would typically make use of one of the available user interface libraries to do all the hard work for you.

These user interface libraries are written in JavaScript, and you typically add them to your website by making the JavaScript library file(s) available for download, and then adding a line like the following to your HTML page to import the JavaScript library:

<script type="text/javascript" src="library.js">

If you are writing your own web application from scratch, you would then make calls to the library to implement the user interface for your application. However, many of the web application frameworks that include a user interface library will write the necessary code for you, making even this step unnecessary.

There are many different types of user interface libraries that you can make use of. As well as general UI libraries such as Dojo and script.aculo.us that provide a desktop-like user experience, there are other libraries specifically designed for implementing geo-spatial web applications. We will explore some of these later in this chapter.

The "slippy map" stack

The "slippy map" is a concept popularized by Google Maps: a zoomable map where the user can click-and-drag to scroll around and double-click to zoom in. Here is an example of a Google Maps slippy map showing a portion of Europe:

The "slippy map" stack

(Image copyright Google; map data copyright Europa Technologies, PPWK, Tele Atlas).

Slippy maps have become extremely popular, and much of the work done on geo-spatial web application development has been focused on creating and working with slippy maps.

The slippy map experience is typically implemented using a custom software stack, as shown in the following image:

The "slippy map" stack

Starting at the bottom, the raw map data is typically stored in a Shapefile or database. This is then rendered using a tool such as Mapnik, and a tile cache is used to speed up repeated access to the same map images. A user-interface library such as OpenLayers is then used to display the map in the user's web browser, and to respond when the user clicks on the map. Finally, a web server is used to allow web browsers to access and interact with the slippy map.

The geo-spatial web application stack

The slippy map stack is intended to display a slippy map within a web page, allowing the user to view a map but not generally to make any changes. A more comprehensive solution allows the user to not only view maps, but also to make changes to geo-spatial data from within the web application itself and perform other functions such as analyzing data and performing spatial queries. A complete geo-spatial web application stack would consist of a web application framework with an integrated slippy map stack and built-in tools for editing, querying, and analyzing geo-spatial data.

In many ways, the geo-spatial web application stack is the epitomé of geo-spatial web development: it allows for rapid development of geo-spatial applications with a minimum of coding, and using existing libraries to do almost all the hard work. While you still need to understand how the web application framework (and its geo-spatial extensions) operate, and there are bugs and technical issues to be considered, these frameworks can save you a tremendous amount of time and effort compared with a "roll your own" solution.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.183.10