While QGIS itself is written in C++, it includes extensive support for Python programming. A Python interpreter is built in, and can be used interactively via the Python Console, or to run plugins written in Python. There is also a comprehensive API for querying and controlling the QGIS application using Python code.
There are three ways in which you can use Python to work with the QGIS system:
- Python Console: You can open this console, which runs the interactive Python interpreter built into QGIS, allowing you to type in commands and see the results immediately.
- Python plugin: These are Python packages designed to be run within the QGIS environment.
- External applications: You can use the QGIS Python API in your own applications. This lets you use QGIS as a geospatial processing engine, or even build your own interactive applications based on QGIS.
No matter how you use Python and QGIS, you will make extensive use of the QGIS Python libraries, which are often referred to as
PyQGIS. They provide a complete programmatic interface to the QGIS system, including calls to load data sources into layers, manipulate the map, export map visualizations, and build custom applications using the QGIS user interface. While an in-depth examination of the PyQGIS library will have to wait until Chapter 3, Learning the QGIS Python API, we will start dabbling with it right away in the next section on the Python Console.
For the remainder of this chapter, we will examine each of the three ways in which you can work with QGIS and Python.
Exploring the Python Console
The QGIS Python Console window can be accessed by using the Python Console item in the Plugins menu. When you select this command, the Python Console will appear in the lower-right corner of the QGIS window. Here's what the Python Console looks like when you first open it:
While the Python Console is an excellent tool for interacting with an existing QGIS project, we are going to use it to create a new project from scratch. Before we can do this, though, we'll need to download some geospatial data sources for our QGIS project.
We are going to need a suitable base map for our project, as well as some river and city information to display on top of this base map. Let's use the Natural Earth website to obtain the information we need. Go to http://naturalearthdata.com and click on the Downloads tab.
Firstly, we'll want to download a nice-looking base map for our project. To do this, select the Raster link under the Medium scale data, 1:50m section, choose the Natural Earth 1 dataset, and click on the Download small size link under the Natural Earth I with Shaded Relief and Water heading.
Next, we need an overlay, which will show lakes and rivers on top of our base map. To get this information, go back to the Downloads tab and select the Physical link under the Medium scale data, 1:50m section. The dataset you want is called Rivers, Lake Centerlines, so click on the Download rivers and lake centerlines link to obtain this file.
Finally, we'll want to highlight the cities on top of our base map. Go back to the Downloads page and select the Cultural link under the Medium scale data, 1:50m heading. At the bottom is a section labelled Urban Areas. Click on the Download urban areas link to download this file.
Once you've done all this, you should have the following three files:
- A raster base map in a file named
NE1_50M_SR_W.zip
- Lake and river vector data in a file named
ne_50m_rivers_lake_centerlines.zip
- Urban area vector data in a file named
ne_50m_urban_areas.zip
Since these are ZIP archives, you will need to unzip these files and store them somewhere at a convenient location on your hard disk.
Tip
You'll need to type in the full path to these datasets, so you might want to put them somewhere convenient, for example, in your home or user directory. In this way, the path you type won't be too long.
Now that we have our data, let's use the QGIS Python Console to import this data into a project. If you've already loaded some data into QGIS (for example, by following the tutorial in the QGIS User Guide), choose the New option from the Project menu to start again with a blank project. Then, type the following into the QGIS Python Console:
Make sure you replace /path/to/
with the full path to the NE1_50M_SR_W
directory you downloaded. Assuming you typed the path correctly, the Natural Earth 1 base map should appear in the QGIS window:
As you can see, our base map is a bit small right now. You can use the various panning and zooming commands in the toolbar at the top of the window to make it bigger, but let's use Python to do the same thing:
This will expand the base map to fill the entire window.
Now that we have a base map, let's add our two vector layers to the project. To do this, type the following:
Once again, make sure you replace /path/to/
with the full path to the ne_50m_urban_areas
directory you downloaded earlier. The urban areas shapefile will be loaded into the QGIS project and will appear as a series of colored areas on top of the base map. Let's zoom in to an area of California so that we can see what this looks like more clearly. To do this, type the following commands into the Python Console window:
This will zoom in on the map in so that an area of California, including Los Angeles and the southern part of San Francisco, is now shown on the map:
Finally, let's add our river and lake data to our project. To do this, enter the following into the Python Console:
If you look at the map, you'll see that the rivers and lakes are now visible. However, they are drawn in a default green color. Let's change this so that the water is now blue:
This code might be a bit confusing, but don't worry—we'll learn about renderers and symbols in Chapter 3, Learning the QGIS Python API.
Now that we are finished, you can save your project using the Save As... item in the Project menu. As you can see, it's quite possible to set up and customize your QGIS project using Python.
Examining a Python plugin
While the Python Console is a fantastic tool for interactive coding, it isn't all that useful if you want to use Python to extend the functionality of QGIS. This is where QGIS plugins come in; you can create (or download) a plugin that adds new features or changes the way QGIS works.
Because QGIS is written using the Qt framework, QGIS plugins make use of the Python bindings in Qt, which are called PyQt. We will download and install PyQt and the related tools when we start to build our own plugins in Chapter 4, Creating QGIS Plugins.
To get an idea of how a Python plugin works, let's take a look at the Zoom to Point plugin. As the name suggests, this plugin lets you zoom to display a given coordinate on the map. It's also written in Python, and is a convenient example for learning about plugins in general.
Before we can use it, we have to install this plugin. Choose the Manage and Install Plugins... item from the Plugins menu, and click on the Not Installed tab. You should see Zoom to Point listed near the bottom of the list of available plugins; click on this plugin, and then click on the Install Plugin button to download and install it.
Let's run this plugin to see how it works; with the project you created earlier still loaded, click on the Zoom to Point plugin's icon in the toolbar, which looks like this:
Try entering the longitude/latitude of your current location (if you don't know it, you might find http://itouchmap.com/latlong.html helpful). You should see the base map, urban areas, and waterways for your current location.
Tip
Don't forget that x equals longitude and y equals latitude. It's easy to get them the wrong way around.
Now that we know what the plugin does, let's see how it works. The downloaded plugins are stored in a hidden directory named .qgis2
in your user or home directory. Go to this hidden directory using your favorite file manager (for Mac OS X, you can use the Go to Folder... item in the Finder's Go menu), and find the python/plugins
subdirectory. This is where the Python plugins are stored.
Tip
Depending on your operating system and the version of QGIS you are using, the name of this hidden directory might be different. If you can't find it, look for a directory named .qgis
or .qgis2
or something similar.
You should see a directory named zoomtopoint
(the full path to this directory will be ~/.qgis2/python/plugins/zoomtopoint
). Inside this directory, you will find the various files that make up the Zoom to Point plugin:
Let's see what these various files do:
Open the zoomtopoint.py
module in your favorite text editor. As you can see, this contains the main Python code for the plugin, in the form of a ZoomToPoint
class. This class has the following basic structure:
If you open the __init__.py
module, you'll see how this class is used to define the plugin's behavior:
When the plugin is loaded, a parameter named iface
is passed to the ClassFactory
function. This parameter is an instance of QgsInterface
, and provides access to the various parts of the running QGIS application. As you can see, the class factory creates a ZoomToPoint
object, and passes the iface
parameter to the initializer so that ZoomToPoint
can make use of it.
Notice how ZoomToPoint.__init__()
, in the Zoomtopoint.py
module, stores a reference to the iface
parameter in an instance variable, so that the other methods can refer to the QGIS interface using self.iface
. For example:
This allows the plugin to interact with and manipulate the QGIS user interface.
The four methods defined by the ZoomToPoint
class are all quite straightforward:
__init__()
: This method initializes a new ZoomToPoint
object.initGui()
: This method initializes the plugin's user interface, preparing it to be used.unload()
: This method removes the plugin from the QGIS user interface.run()
: This method is called when the plugin is activated, that is, when the user clicks on the plugin's icon in the toolbar, or selects the plugin from the Plugins menu.
Don't worry too much about all the details here; we'll look at the process of initializing and unloading a plugin in a later chapter. For now, take a closer look at the run()
method. This method essentially looks like the following:
We've excluded the code that remembers the values the user entered previously, and copies those values back into the dialog when the plugin is run. Looking at the previous code, the logic seems to be fairly straightforward and is explained as follows:
- Create a
ZoomToPointDialog
object. - Display the dialog box to the user.
- If the user clicks on the OK button, extract the entered values, use them to create a new bounding rectangle, and set the extent of the map to this rectangle.
While this plugin is quite straightforward and the actual code doesn't do all that much, it is a useful example of what a Python plugin should look like, as well as the various files that are needed by a Python plugin. In particular, you should note that:
- A plugin is simply a directory that contains a Python package initialization file (
__init__.py
), some Python modules, and other files created using Qt Designer. - The
__init__.py
module must define a top-level function named ClassFactory
that accepts an iface
parameter and returns an object that represents the plugin. - The plugin object must define an
initGui()
method, which is called to initialize the plugin's user interface, and an unload()
method, which is called to remove the plugin from the QGIS application. - The plugin can interact with and manipulate the QGIS application via the
iface
object passed to the class factory. - The
resources.qrc
file lists various resources such as images, which are used by the plugin. - The
resources.qrc
file is compiled into a resources.py
file using the PyQt command-line tools. - Dialog boxes and other windows are created using a Qt Designer template, which are typically stored in a file with a name of the form
ui_Foo.ui
. - The UI template files are then compiled into Python code using the PyQt command-line tools. If the template is named
ui_foo.ui
, then the associated Python module will be named ui_foo.py
. - Once the user interface for a dialog box has been defined, you create a subclass of
QtGui.QDialog
, and load that user interface module into it. This defines the contents of the dialog box based on your template. - Your plugin can then display the dialog box as required, extracting the entered values and using the results to interact with QGIS via the
iface
variable.
Plugins are a useful way of extending and customizing QGIS. We will return to the topic of QGIS plugins in Chapter 4, Creating QGIS Plugins, where we will create our own plugin from scratch.
Writing an external application
The final way to work with Python and QGIS is to write a completely standalone Python program that imports the QGIS libraries and works with them directly. In many ways, this is an ideal way of writing your own custom mapping applications, because your program doesn't have to run within the existing QGIS user interface. There are, however, a few things you need to be aware of when you attempt to use Python and QGIS in this way:
- Your Python program needs to be able to find the QGIS Python libraries before it can be run. Since these are bundled into the QGIS application itself, you will need to add the directory where the PyQGIS libraries are installed in your Python path.
- You also need to tell the PyQGIS libraries where the QGIS application's resources are stored.
- As the application is running outside the QGIS application, you won't have access to the
iface
variable. You also can't use those parts of the PyQGIS library that assume you are running inside QGIS.
None of this is too onerous, though it can trip you up the first time you attempt to access PyQGIS from your external Python code. Let's take a look at how we can avoid these traps when writing your own Python programs.
Firstly, to allow your program to access the PyQGIS libraries, you need to modify your Python path (and possibly some other environment variables) before you can import any of the QGIS packages. For MS Windows, you can do this by running the following in the command line:
If you are running Mac OS X, the following commands will set up the Python path for you:
For computers that run a version of Linux, you can use the following:
Note
Obviously, you will need to replace /path/to/qgis
with the actual path of your QGIS installation.
If you have QGIS installed in a nonstandard location, you might need to modify these commands before they will work. To check if they have worked, start up the Python interpreter and enter the following command:
If everything goes well, you'll simply see the Python prompt:
On the other hand, you might see the following error:
In this case, the PYTHONPATH
variable has not been set up correctly, and you will have to check the commands you entered earlier to set this environment variable, and possibly modify it to allow for a nonstandard location of the QGIS libraries.
Note
Note that in some cases, this isn't enough because the Python libraries are only wrappers around the underlying C++ libraries; you might also need to tell your computer where to find these C++ libraries. To see if this is a problem, you can try to do the following:
You might get an error that looks like this:
You will to have to tell your computer where to find the underlying shared libraries. We will return to this later when we look at writing our own external applications; if you want to see the details, skip ahead to Chapter 5, Using QGIS in an External Application.
With the path set, you can now import the various parts of the PyQGIS library that you want to use, for example:
Now that we have access to the PyQGIS libraries, our next task is to initialize these libraries. As mentioned earlier, we have to tell PyQGIS where to find the various QGIS resources. We do this using the QgsApplication.setPrefixPath()
function, like this:
This uses the QGIS_PREFIX
environment variable we set earlier to tell QGIS where to find its resources. With this done, you can then initialize the PyQGIS library by making the following call:
We can now use PyQGIS to do whatever we want in our application. When our program exits, we also need to inform the PyQGIS library that we are exiting:
Putting all this together, our minimal Python application looks like this:
Of course, this application doesn't do anything useful yet—it simply starts up and shuts down the PyQGIS libraries. So let's replace the "...
" line with some useful code that displays a basic map widget. To do this, we need to define a QMainWindow
subclass, which displays the map widget, and then create and use a QApplication
object to display this window and handle the various user-interface events while the application is running.
Note
Both QMainWindow
and QApplication
are PyQt classes. We will be working extensively with the various PyQt classes as we develop our own external applications using QGIS and Python.
Let's start by replacing the "...
" line with the following code, which displays a map viewer and then runs the application's main event loop:
As you can see, a MapViewer
instance (which we will define shortly) is created and displayed, and the QApplication
object is run by calling the exec_()
method. For simplicity, we pass the name of a shapefile to display within the map viewer.
Running this code will cause the map viewer to be displayed, and the application will run until the user closes the window or chooses the Quit command from the menu.
Now, let's define the MapViewer
class. Here is what the class definition looks like:
Don't worry too much about the details of this class; we basically just create a window and place a QgsMapCanvas
object within it. We then create a map layer (an instance of QgsVectorLayer
) and add it to the map canvas. Finally, we add the canvas to the window's contents.
Notice that
QgsMapCanvas
and QgsVectorLayer
are both part of PyQGIS, while QMainWindow
, QVBoxLayout
, and QWidget
are all PyQt classes. This application uses the PyQGIS classes within a PyQt application, mixing the classes from both sources. This is possible because QGIS is built using Qt, and the various PyQGIS classes are based on PyQt.
To turn the preceding code into a working application, all we need to do is add some more import
statements to the top of the module:
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
If you run this application, the map viewer will be displayed, showing the contents of the shapefile referred to by the code. For example:
This application is still a bit ugly—you can see white space at the top and bottom this map because it doesn't take into account the aspect ratio of the map data. There's also no feature of zooming in or scrolling around the map. However, these can be added quite easily, and as you can see, it's not very difficult to create your own standalone mapping applications built on top of QGIS.