In this chapter, we will cover the following recipes:
Installing QGIS for development
Using the QGIS Python console
Using Python's ScriptRunner plugin
Setting up your QGIS IDE
Debugging QGIS Python scripts
Navigating the PyQGIS API
Creating a QGIS plugin
Distributing a plugin
Building a standalone application
Storing and reading global preferences
Storing and reading project preferences
Accessing the script path from within your script
This chapter explains how to configure QGIS for automation using Python. In addition to setting up QGIS, we will also configure the free Eclipse Integrated Development Environment (IDE) with the PyDev plugin to make writing, editing, and debugging scripts easier. We will also learn the basics of different types of QGIS automated Python scripts through the PyQGIS API. Finally, we'll examine some core QGIS plugins that significantly extend the capability of QGIS.
QGIS has a set of Python modules and libraries that can be accessed from the Python console within QGIS. However, they can also be accessed from outside QGIS to write standalone applications. First, you must make sure that PyQGIS is installed for your platform, and then set up some required system environment variables.
In this recipe, we will walk you through the additional steps required beyond the normal QGIS installation to prepare your system for development. The steps for each platform are provided, which also include the different styles of Linux package managers.
QGIS uses slightly different installation methods for Windows, GNU/Linux, and Mac OS X. The Windows installers install everything you need for Python development, including Python itself.
However, on Linux distributions and Mac OS X, you may need to manually install the Python modules for the system installation of Python. On Mac OS X, you can download installers for some of the commonly used Python modules with QGIS from http://www.kyngchaos.com/software/python.
On Linux, you have the option to compile from the source or you can just specify the Python QGIS interface to be installed through your package manager.
Now, we must set the PYTHONPATH
to the PyQGIS directory. At the same time, append the path to this directory to the PATH
variable so that you can use the PyQGIS modules with an external IDE.
Set the
PYTHONPATH
variable in a command prompt to thebin
directory of the QGIS installation:set PYTHONPATH="C:\Program Files\QGIS Brighton\bin"
Next, append QGIS's
bin
directories to the system'sPATH
variable:set PATH="C:\Program Files\QGIS Brighton\bin";"C:\Program Files\QGIS Brighton\bin\apps\qgis\bin";%PATH%
Set the
PYTHONPATH
variable in a command prompt to thebin
directory of the QGIS installation:export PYTHONPATH=/usr/share/qgis/python
Now, append the QGIS shared library directory to the runtime search path. Note that this location can vary depending on your particular system configuration:
export LD_LIBRARY_PATH=/usr/share/qgis/python
The QGIS installation process and package managers set up the Python module's configuration internal to QGIS. When you use the Python console inside QGIS, it knows where all the PyQGIS modules are. However, if you want to use the PyQGIS API outside QGIS, using a system Python installation on Windows or Linux, it is necessary to set some system variables so that Python can find the required PyQGIS modules.
This recipe uses the default QGIS paths on each platform. If you aren't sure which PyQGIS path is for your system, you can figure this out from the Python console in QGIS.
The libraries on Windows are stored in a different location than in the case of other platforms. To locate the path, you can check the current working directory of the Python console:
Start QGIS.
Select Python Console from the Plugins menu, which appears in the lower-right corner of the QGIS application window, as shown in the following screenshot:
Use the
os
module to get the current working directory:import os os.getcwd()
Verify that the current working directory of the Python console is returned.
The QGIS Python console allows you to interactively control QGIS. You can test out ideas or just do some quick automation. The console is the simplest way to use the QGIS Python API.
In the following steps, we'll open the QGIS Python console, create a vector layer in memory, and display it on the map:
Start QGIS.
From the Plugins menu, select Python Console.
The following code will create a point on the map canvas:
layer = QgsVectorLayer('Point?crs=epsg:4326', 'MyPoint' , 'memory') pr = layer.dataProvider() pt = QgsFeature() point1 = QgsPoint(20,20) pt.setGeometry(QgsGeometry.fromPoint(point1)) pr.addFeatures([pt]) layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayers([layer])
This example uses a memory
layer to avoid interacting with any data on disk or a network to keep things simple. Notice that when we declare the layer type, we add the parameter for the Coordinate Reference System (CRS) as EPSG:4326. Without this declaration, QGIS will prompt you to choose one. There are three parts or levels of abstraction to create even a single point on the map canvas, as shown here:
First, create a layer that is of the type geometry. Next, set up a data provider to accept the data source.
Then, create a generic feature object, followed by the point geometry.
Next, stack the objects together and add them to the map.
The layer type is memory
, meaning that you can define the geometry and the attributes inline in the code rather than in an external data source. In this recipe, we just define the geometry and skip the defining of any attributes.
The QGIS Python ScriptRunner plugin provides a middle ground for QGIS automation, between the interactive console and the overhead of plugins. It provides a script management dialog that allows you to easily load, create, edit, and run scripts for large-scale QGIS automation.
Install the ScriptRunner plugin using the QGIS plugin manager. Then, run the plugin from the Plugin menu to open the ScriptRunner dialog. Configure a default editor to edit scripts using the following steps:
Find the gear icon that represents the ScriptRunner Preferences settings dialog box and click on it.
In the General Options section, check the Edit Scripts Using: checkbox.
Click on the … button to browse to the location of a text editor on your system.
Click on the Open button.
Click on the OK button in the Preferences dialog.
In the ScriptRunner dialog, click on the New Script icon, as shown in the following screenshot:
Browse to the directory where you can save your script, name the script, and save it.
Right-click (or control-click on a Mac) on the script name in ScriptRunner and select Edit Script in External Editor.
In the editor, replace the template code with the following code:
from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * def run_script(iface): layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'Mississippi' , "memory") pr = layer.dataProvider() poly = QgsFeature() geom = QgsGeometry.fromWkt("POLYGON ((-88.82 34.99,-88.09 34.89,-88.39 30.34,-89.57 30.18,-89.73 31,-91.63 30.99,-90.87 32.37,-91.23 33.44,-90.93 34.23,-90.30 34.99,-88.82 34.99))") poly.setGeometry(geom) pr.addFeatures([poly]) layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayers([layer])
Click on the Run Script icon, which is represented by a green-colored arrow.
Close the ScriptRunner plugin.
Verify that the memory layer polygon was added to the QGIS map, as shown in the following screenshot:
ScriptRunner is a simple but powerful idea. It allows you to build a library of automation scripts and use them from within QGIS, but without the overhead of building a plugin or a standalone application. All the Python and system path variables are set correctly and inherited from QGIS; however, you must still import the QGIS and Qt libraries.
The Eclipse IDE with the PyDev plugin is cross-platform, has advanced debugging tools, and is free.
Note
You can refer to http://pydev.org/manual_101_install.html in order to install PyDev correctly.
This tool makes an excellent PyQGIS IDE. Eclipse allows you to have multiple Python interpreters configured for different Python environments. When you install PyDev, it automatically finds the installed system Python installations. On Windows, you must also add the Python interpreter installed with PyQGIS. On all platforms, you must tell PyDev where the PyQGIS libraries are.
This recipe uses Eclipse and PyDev. You can use the latest version of either package that is supported by your operating system. All platforms besides Windows rely on the system Python interpreter. So, there is an extra step in Windows to add the QGIS Python interpreter.
The following steps will walk you through how to add the QGIS-specific Python interpreter to Eclipse in order to support the running standalone QGIS applications or to debug QGIS plugins.
The process used to add the QGIS Python interpreter to Eclipse on Windows is different from the process used on Linux. The following steps describe how to set up the interpreter on the Windows version of Eclipse:
Open Eclipse.
From the Window menu, select Preferences. On OS X, you must click on the Eclipse menu to find the preferences menu.
In the pane on the left-hand side of the Preferences window, click on the plus sign next to PyDev.
From the list of PyDev preferences, select Interpreter Python.
In the pane labelled Python Interpreters, click on the New button.
In the Select interpreter dialog, name the interpreter
PyQGIS
.Browse to the location of the QGIS Python interpreter called
python.exe
within thebin
folder of the QGIS program folder. On OS X and Linux, you use can use the system Python installation. On Windows, Python is included with QGIS. The default location on Windows isC:\Program Files\QGIS Brighton\bin\python.exe
, as shown in the following screenshot:When you click on the OK button, Eclipse will attempt to automatically add every Python library it finds to the Python path for this interpreter configuration. We need to control which libraries are added to prevent conflicts. Click on the Deselect All button and then click on OK:
Eclipse will issue a warning dialog because you haven't selected any core libraries. Click on the Proceed anyways button, as shown here:
Apart from adding the Python interpreter, you must also add the module paths needed by PyQGIS using the following steps. These steps will require you to switch back and forth between QGIS and Eclipse:
Start QGIS.
Start the QGIS Python Console from the Plugins menu.
Use the
sys
module to locate the PyQGIS Python path, as described in the previous recipe, Setting the environment variables:import sys sys.path
We also want to add the PyQGIS API. Next, find that path using the QGIS Python Console by typing the following command:
qgis
For each path in the returned lists, click on the New Folder button in Eclipse's Libraries pane for your QGIS interpreter, and browse to that folder until all the paths have been added. If a given folder does not exist on your system, simply ignore it, as shown here:
To take full advantage of Eclipse's features, including code completion, we will add the QGIS and Qt4 modules to the PyQGIS Eclipse interpreter preferences. The following steps will allow Eclipse to suggest the possible methods and properties of QGIS objects as you type; this feature is known as autocomplete:
You will also need to create a PATH
variable, which points to the QGIS binary libraries, DLLs on Windows, and other libraries needed by QGIS at runtime on all platforms.
In the PyDev preferences dialog, ensure that the PyQGIS interpreter is selected in the list of interpreters.
Select the Environment tab.
Click on the New button.
In the Name field, enter PATH.
For the Value field, add the path to the QGIS program directory and to any QGIS directories containing binaries separated by a semicolon. The following is an example from a Windows machine:
C:\Program Files\QGIS Brighton;C:\Program Files\QGIS Brighton\bin;C:\Program Files\QGIS Brighton\apps\qgis\bin;C:\Program Files\QGIS Brighton\apps\Python27\DLLs
Eclipse and PyDev use only the information you provide to run a script in the Eclipse workspace. This approach is very similar to the popular Python tool virtualenv, which provides a clean environment when writing and debugging code to ensure that you don't waste time troubleshooting issues caused by the environment.
In this recipe, we will configure Eclipse to debug QGIS Python scripts.
Both QGIS and Eclipse must be configured for debugging so that the two pieces of software can communicate. Eclipse attaches itself to QGIS in order to give you insights into the Python scripts running in QGIS. This approach allows you to run scripts in a controlled way that can pause execution while you monitor the program to catch bugs as they occur.
The following steps will add two plugins to QGIS, which allows Eclipse to communicate with QGIS. One plugin, Plugin Reloader, allows you to reload a QGIS plugin into memory without restarting QGIS for faster testing. The second plugin, Remote Debug, connects QGIS to Eclipse.
Remote Debug is an experimental plugin, so you must ensure that experimental plugins are visible to the QGIS plugin manager in the list of available plugins.
Start QGIS.
Under the Plugins menu, select ManageandInstallPlugins…
In the left pane of the Plugins dialog, select the Settings tab.
Scroll down in the Settings window and ensure that the Show also experimental plugins checkbox is checked, as shown in the following screesnhot:
Click on the OK button.
Select the tab labeled All in the pane on the left-hand side of the Plugins window.
In the Search dialog at the top of the window, search for Plugin Reloader.
Select Plugin Reloader from the search results and then click on the Install Plugin button.
Next, search for the Remote Debug plugin and install it as well.
Finally, install the HelloWorld plugin as well.
Now that QGIS is configured for debugging in Eclipse, we will configure Eclipse to complete the debugging communication loop, as shown in the following steps:
Start Eclipse.
In the File menu, select New and then click on Project.
Select General and then click on Project from the NewProject dialog.
Click on the Next> button.
Give the project the name HelloWorldPlugin.
Click on the Finish button.
Select the new HelloWorldPlugin project in project explorer and select New; then, click on Folder from the File menu.
In the New Folder dialog, click on the Advanced>> button.
Choose the Link to alternate location (Linked Folder) radio button.
Click on the Browse button and browse to the location of the
HelloWorldPlugin
folder, as shown in the following screenshot:Click on the Finish button.
The previous parts of this recipe configured Eclipse and QGIS to work together in order to debug QGIS plugins. In this section, we will test the configuration using the simplest possible plugin, HelloWorld, to run Eclipse using the Debug Perspective. We will set up a break point in the plugin to pause the execution and then monitor plugin execution from within Eclipse, as follows:
Under the
HelloWorld
folder, open the fileHelloWorld.py
.From the Eclipse Window menu, select OpenPerspective and then click on Other…
From the OpenPerspective dialog, select Debug.
Click on the OK button.
Scroll to the first line of the
hello_world()
function and double-click on the left-hand side of the line number to set a break point, which is displayed as a green-icon:From the Pydev menu, select Start Debug Server.
Verify that the server is running by looking for a message in the Debug console at the bottom of the window, similar to the following:
Debug Server at port: 5678
Switch over to QGIS.
From the QGIS Plugins menu, select RemoteDebug and then select the RemoteDebug command.
Verify that the QGIS status bar in the lower-left corner of the window displays the following message:
Python Debugging Active
Now, select HelloWorld from the QGIS Plugins menu and then select HelloWorld.
Switch back to Eclipse.
Verify that the
hello_world()
function is highlighted at the break point.From the Run menu, select Resume.
Switch back to QGIS.
Verify that the HelloWorld dialog box has appeared.
The RemoteDebug plugin acts as a client to the PyDev debug server in order to send the Python script's execution status from QGIS to Eclipse. While it has been around for several versions of QGIS now, it is still considered experimental.
The PluginReloader plugin can reset plugins that maintain state as they run. The HelloWorld plugin is so simple that reloading is not needed to test it repeatedly. However, as you debug more complex plugins, you will need to run it in order to reset it before each test. This method is far more efficient and easier to use than closing QGIS, editing the plugin code, and then restarting.
Note
You can find out more about debugging QGIS, including using other IDEs, at http://docs.qgis.org/2.6/en/docs/pyqgis_developer_cookbook/ide_debugging.html.
The QGIS Python API, also known as PyQGIS, allows you to control virtually every aspect of QGIS. The ability to find the PyQGIS object you need in order to access a particular feature of QGIS is critical to automation.
The PyQGIS API is based on the QGIS C++ API. The C++ API is kept up to date online and is well-documented.
Note
The QGIS API's web page is located at http://qgis.org/api/2.6/modules.html.
Notice the version number, 2.2, in the URL. You can change this version number to the version of QGIS you are using in order to find the appropriate documentation.
The PyQGIS API documentation is not updated frequently because it is nearly identical to the structure of the C++ API. However, the QGIS project on github.com maintains a list of all the PyQGIS classes for the latest version. The PyQGIS 2.6 API is located at https://github.com/qgis/QGIS/blob/master/python/qsci_apis/Python-2.6.api.
You can locate the documented class in the main C++ API and read about it. Then, look up the corresponding Python module and class using the PyQGIS API listing. In most cases, the C++ API name for a class is identical in Python.
In this recipe, we'll locate the PyQGIS class that controls labels in QGIS.
We will perform the following steps to see in which PyQGIS module the QGIS Label object and QgsLabel are located in:
Go to the QGIS API page at http://qgis.org/api/2.6/index.html.
Click on the Modules tab.
Click on the link QGIS Core Library.
Scroll down the list of modules in alphabetical order until you see QgsLabel.
Click on the QgsLabel link to access the label object documentation.
Now, go to the PyQGIS API listing at https://github.com/qgis/QGIS/blob/master/python/qsci_apis/Python-2.6.api.
Scroll down the alphabetical class listing until you see
qgis.core.QgsLabel.LabelField
.
The QGIS API is divided into five distinct categories, as follows:
Core
GUI
Analysis
Map composer
Network analysis
Most of the time, it's easy to find the class that targets the functionality you need with most of QGIS being contained in the catch-all Core module. The more you use the API, the quicker you'll be able to locate the objects you need for your scripts.
If you're having trouble locating a class containing the keyword you need, you can use the search engine on the QGIS API website.
Plugins are the best way to extend QGIS, as they can be easily updated and reused by other people.
The easiest approach to creating a plugin is to use the Plugin Builder plugin to jumpstart development. You can find it in the main QGIS plugin repository and install it.
Perform the following steps to create a simple plugin that displays a dialog box with a custom message:
Start QGIS.
From the Plugins menu, select Plugin Builder and then click on Plugin Builder under the submenu.
In the QGIS Plugin Builder dialog, name the class
MyPlugin
.Name the plugin
My Plugin
.Type a short description, such as
A demonstration on building a QGIS Plugin.
Enter
myplugin
for the Module name.Leave the default version numbers as they are.
Enter
My Plugin
in the Text for the menu item field.Enter your name and email address for author information.
Ensure that the checkbox labelled Flag the plugin as experimental is checked, as shown in the following screenshot:
Click on the OK button.
A file browser dialog will appear; you can choose a folder in which you want to create your plugin. Select one of the folders called
plugins
within thepython
folder in either the main user directory or the QGIS program directory. The following examples are from a Windows machine. You should use the folder in your user directory, which is the preferred place for third-party plugins. QGIS standard plugins go in the main program directory:C:\Documents and Settings\Joel\.qgis2\python\plugins C:\Program Files\QGIS Brighton\apps\qgis\python\plugins
Close the follow-on Plugin Builder information dialog by clicking on the OK button.
Using the command prompt, navigate to your new plugin template folder.
Use the
pyrcc4
command to compile the resource file:pyrcc4 –o resources_rc.py resources.qrc
In a text editor, such as Windows Notepad or vi on Linux, open the user interface XML file named
myplugin_dialog_base.ui
.Insert the following XMLfor a custom label near line 31 and just before the last
</widget>
tag. Save the file after this edit:<widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>120</x> <y>80</y> <width>201</width> <height>20</height> </rect> </property> <property name="font"> <font> <pointsize>14</pointsize> </font> </property> <property name="text"> <string>Geospatial Python Rocks!</string> </property> </widget>
Now, compile the
ui
file using thepyuic4
tool:pyuic4 –o ui_myplugin.py ui_myplugin.ui
Your plugin is now ready. Restart QGIS.
Select My Plugin from the Plugins menu and then select My Plugin from the submenu to see the dialog you created within QGIS, as shown here:
This recipe shows you the bare bones needed to make a working plugin. Although we haven't altered it, the code for the plugin's behavior is contained in myplugin.py
. You can change the icon and the GUI, and just recompile any time you want. Note that we must compile the Qt4
portion of the plugin, which creates the dialog box. The entire QGIS GUI is built on the Qt4
library, so the pyrrc4
compiler and pyuic4
is included to compile the GUI widgets.
You can download the completed plugin with both the source and compiled ui
and resource files at https://geospatialpython.googlecode.com/svn/MyPlugin.zip.
Note
You can find out more about QGIS plugins, including the purpose of the other files in the directory, in the QGIS documentation at http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/plugins.html.
We have edited the myplugin_dialog_base.ui
XML file by hand to make a small change. However, there is a better way to use Qt Creator. Qt Creator is a fully-fledged, open source GUI designer for the Qt framework. It is an easy what-you-see-is-what-you-get editor for Qt Widgets, including PyQGIS plugins, which uses the included Qt Designer interface. On Windows, Qt Designer can be found in the QGIS program directory within the bin
directory. It is named designer.exe
. On other platforms, Qt Designer is included as part of the qt4-devel package.
Note
You can also download Qt Creator, which includes Qt Designer, from http://qt-project.org/downloads.
When you run the installer, you can uncheck all the installation options, except the Tools category to install just the IDE.
Distributing a QGIS plugin means placing the collection of files on a server as a ZIP
file, with a special configuration file, in order to allow the QGIS plugin manager to locate and install the plugin. The QGIS project has an official repository, but third-party repositories are also permitted. The official repository is very strict regarding how the plugin is uploaded. So, for this recipe, we'll set up a simple third-party repository for a sample plugin and test it with the QGIS plugin manager to avoid polluting the main QGIS repository with a test project.
In order to complete this recipe, you'll need a sample plugin and a web-accessible directory. You'll also need a zip
tool such as the free 7-zip program (http://www.7-zip.org/download.html). You can use the MyPlugin example from the Creating a QGIS plugin recipe as the plugin to distribute. For a web directory, you can use a Google Code repository, GitHub repository, or an other online directory you can access. Code repositories work well because they are a good place to store a plugin that you are developing.
In the following steps, we will package our plugin, create a server configuration file for it, and place it on a server to create a QGIS plugin repository:
First, zip up the plugin directory to create a
.ZIP
file.Rename the
.ZIP
file to contain the plugin's version number:Myplugin.0.1.0.zip
Upload this file to a publicly accessible web directory.
Upload the
icon.png
file from your plugin directory to the web directory.Next, customize a
plugins.xml
metadata file for your plugin. Most of the data you need can be found in themetatdata.txt
file in your plugin directory. The following example provides some guidance:<?xml version = '1.0' encoding = 'UTF-8'?> <?xml-stylesheet type="text/xsl" href="" ?> <plugins> <pyqgis_plugin name="My Plugin" version="0.1.0" plugin_id="227"> <description> <![CDATA[Demonstration of a QGIS Plugin]]> </description> <about></about> <version>0.1.0</version> <qgis_minimum_version>1.8.0</qgis_minimum_version> <qgis_maximum_version>2.9.9</qgis_maximum_version> <homepage> <![CDATA[https://code.google.com/p/geospatialpython]]> </homepage> <file_name>MyPlugin.0.1.0.zip</file_name> <icon> http://geospatialpython.googlecode.com/svn/icon_227.png </icon> <author_name><![CDATA[Joel Lawhead]]></author_name> <download_url> http://geospatialpython.googlecode.com/svn/MyPlugin.0.1.0.zip </download_url> <uploaded_by><![CDATA[jll]]></uploaded_by> <create_date>2014-05-16T15:31:19.824333</create_date> <update_date>2014-07-15T15:31:19.824333</update_date> <experimental>True</experimental> <deprecated>False</deprecated> <tracker> <![CDATA[http://code.google.com/p/geospatialpython/issues]]> </tracker> <repository> <![CDATA[https://geospatialpython.googlecode.com/svn/]]> </repository> <tags> <![CDATA[development,debugging,tools]]></tags> <downloads>0</downloads> <average_vote>0</average_vote> <rating_votes>0</rating_votes> </pyqgis_plugin> </plugins>
Upload the
plugins.xml
file to your web directory.Now, start QGIS and launch the plugins manager by going to the Plugins menu and selecting Manage and Install Plugins….
In the Settings tab of the plugins settings dialog, scroll down and click on the Add… button.
Give the plugin a name and then add the complete URL to your
plugins.xml
in the URL field.Click on the OK button.
To make things easier, disable the other repositories by selecting the repository name, clicking on the Edit button, and unchecking the Enable checkbox.
Click on the OK button.
Click on the Not Installed tab.
Your test plugin should be the only plugin listed, so select it from the list.
Click on the Install Plugin button in the bottom-right corner of the window.
Click on the Close button.
Go to the Plugins menu and select your plugin to ensure that it works.
QGIS is a complete desktop GIS application. However, with PyQGIS, it can also be a comprehensive geospatial Python library to build standalone applications. In this recipe, we will build a simple standalone script that creates a map with a line on it.
All you need to do to get ready is ensure that you have configured Eclipse and PyDev for PyQGIS development, as described in the Setting up your QGIS IDE recipe.
In PyDev, create a new project called MyMap
with a Python script called MyMap.py
, as follows:
In the Eclipse File menu, select New and then click on PyDev Project.
In the PyDev project's Name field, enter
MyMap
.Next, select the Python radio button from the Project Type list.
From the Interpreter pull-down menu, select PyQGIS.
Leave the radio button checked for Add project directory to the PYTHONPATH.
Click on the Finish button.
Now, select the project in the PyDev package explorer.
From the File menu, select New and then click on File.
Name the file
myMap.py
.Click on the Finish button.
Add the following code to the file that is open in the editor:
from qgis.core import * from qgis.gui import * from qgis.utils import * from PyQt4.QtCore import * from PyQt4.QtGui import * app = QgsApplication([], True) app.setPrefixPath("C:/Program Files/QGIS Brighton/apps/qgis", True) app.initQgis() canvas = QgsMapCanvas() canvas.setWindowTitle("PyQGIS Standalone Application Example") canvas.setCanvasColor(Qt.white) layer = QgsVectorLayer('LineString?crs=epsg:4326', 'MyLine' , "memory") pr = layer.dataProvider() linstr = QgsFeature() geom = QgsGeometry.fromWkt("LINESTRING (1 1, 10 15, 40 35)") linstr.setGeometry(geom) pr.addFeatures([linstr]) layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayer(layer) canvas.setExtent(layer.extent()) canvas.setLayerSet([QgsMapCanvasLayer(layer)]) canvas.zoomToFullExtent() canvas.freeze(True) canvas.show() canvas.refresh() canvas.freeze(False) canvas.repaint() exitcode = app._exec() QgsApplication.exitQgis() sys.exit(exitcode)
From the Run menu, select Run.
Verify that the standalone QGIS map appears in a new window, as shown here:
This recipe uses as little code as possible to create a map canvas and to draw a line in order to demonstrate the skeleton of a standalone application, which can be built up further to add more functionality.
To create the line geometry, we use Well-Known Text (WKT), which provides a simple way to define the line vertices without creating a bunch of objects. Towards the end of this code, we use a workaround for a bug in QGIS 2.2 by freezing the canvas. When the canvas is frozen, it does not respond to any events which, in the case of this bug, prevent the canvas from updating. Once we refresh the canvas, we unfreeze it and then repaint it to draw the line. This workaround will still work in QGIS 2.4 and 2.6 but is not necessary.
The standalone application can be compiled into an executable that can be distributed without installing QGIS, using py2exe or PyInstaller:
You can find our more about py2exe at http://www.py2exe.org.
You can learn more about PyInstaller at https://github.com/pyinstaller/pyinstaller/wiki.
PyQGIS allows you to store application-level preferences and retrieve them.
This code can be run in any type of PyQGIS application. In this example, we'll run it in the QGIS Python console for an easy demonstration. In this example, we'll change the default CRS for new projects and then read the value back from the global settings.
In this recipe, we will set the default projection used by QGIS for new projects using the Python console:
Start QGIS.
From the Plugins menu, select Python Console.
We will need to import the Qt core library, as follows:
from PyQt4.QtCore import *
In the Python console, run the following code:
settings = QSettings(QSettings.NativeFormat, QSettings.UserScope, 'QuantumGIS', 'QGis') settings.setValue('/Projections/projectDefaultCrs', 'EPSG:2278') settings.value('/Projections/projectDefaultCrs')
This API is actually the Qt API that QGIS relies on for settings. In the QSettings object, we specify the NativeFormat for storage, which is the default format for the platform. On Windows, the format is the registry; on OS X, it's the plist
files; and on Unix, it's the text files. The other QSettings parameters are the
organization and the application, often used as a hierarchy to store information. Note that even after changing these settings, it may be that none of the properties in the QGIS GUI change immediately. In some cases, such as Windows, the system must be restarted for registry changes to take effect. However, everything will work programmatically.
The QGIS application settings are stored using the Qt API. However, QGIS project settings have their own object. In this recipe, we'll set and read the project title and then set and read a custom preference for a plugin.
We are going to set a plugin preference using the sample plugin created in the previous recipe, Creating a QGIS plugin. You can substitute the name of any plugin you want, however. We will also run this recipe in the QGIS Python console for quick testing, but this code will normally be used in a plugin.
In this recipe, we will first write and then read the title of the current project. Then, we will create a custom value for a plugin called splash
, which can be used for the plugin startup splash screen if desired.
Start QGIS.
From the Plugins menu, select Python Console.
In the console, run the following code:
proj = QgsProject.instance() proj.title("My QGIS Project") proj.title() proj.writeEntry("MyPlugin", "splash", "Geospatial Python Rocks!") proj.readEntry("MyPlugin", "splash", "Welcome!")[0]
In the first two lines, we change the title of the current active project and then echo it back. In the next set of two lines, we set up and read custom settings for a plugin. Notice that the readEntry()
method returns a tuple with the desired text and a boolean, acknowledging that the value is set. So, we extract the first index to get the text. The read method also allows the default text in case that property is not set (rather than throw an exception which must be handled) as well as the boolean value False
to inform you that the default text was used because the property was not set. The values you set using this method are stored in the project's XML file when you save it.
The QgsProject
object has a number of methods and properties that may be useful. The QGIS API documentation details all of them at http://qgis.org/api/2.6/classQgsProject.html.
Sometimes, you need to know exactly where the current working directory is so that you can access external resources.
This code uses the Python built-in library and can be used in any context. We will run this recipe in the QGIS Python console.
In this recipe, we will get the current working directory of the Python console, which can change with configuration:
Start QGIS.
From the Plugins menu, select Python Console.
In the Python console, run the following code:
import os os.getcwd()
QGIS relies heavily on file system paths to run the application and to manage external data. When writing cross-platform QGIS code, you cannot assume the working directory of your script.
On his blog, one of the QGIS developers has an excellent post about the various aspects of path variables in QGIS beyond just the execution directory; you can check it out at http://spatialgalaxy.net/2013/11/06/getting-paths-with-pyqgis/.