In this chapter, we will focus on the tools needed to write Python scripts for the PyQGIS framework. We will cover the following recipes:
Installing QGIS 2.18 for development
Using the QGIS Python console for interactive control
Automatically starting the Python console
Using Python's Script Runner plugin
Setting up your QGIS IDE
Debugging QGIS Python scripts
Navigating the PyQGIS API
Creating a traditional QGIS plugin
Creating a Processing Toolbox 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 automate QGIS using Python. In addition to setting this up, we will also configure the free Eclipse Integrated Development Environment (IDE) along with the PyDev plugin to make writing, editing, and debugging scripts easier. We will also learn the basics of different types of QGIS Python scripts through the PyQGIS API. Finally, we'll examine some core QGIS plugins that significantly extend its capability.
QGIS has a set of Python modules and libraries that can be accessed from the Python console within it. However, they can also be accessed from outside QGIS to write standalone applications. First, you must make sure that PyQGIS is installed on your platform, then set up some required environment variables.
In this recipe, we will walk you through the additional steps required beyond the normal installation process to prepare your system for development. The steps for each platform are provided, which also include the different styles of Linux package managers. The version of QGIS in your Linux package manager may be older. You can find additional detailed installation instructions at https://www.qgis.org/en/site/forusers/alldownloads.html.
QGIS uses different installation methods for Windows, GNU/Linux, and Mac OS X. The Windows installer installs everything you need for Python development, including Python itself.
However, on both Linux distributions and Mac OS X, you may need to manually install the Python modules to complete the installation process. On Mac OS X, you can download installers for some commonly used Python modules with QGIS; refer to http://www.kyngchaos.com/software/python.
On Linux, you have an option to either compile from the source or just specify the Python interface to be installed through your package manager.
For Linux distributions based on the Debian Linux package manager, which includes Ubuntu and Debian, use the following command in a shell:
sudo apt-get update
Next, install the QGIS, PyQGIS, and QGIS GRASS plugins:
sudo apt-get install qgis python-qgis qgis-plugin-grass
For Linux distributions based on the Red Hat Package Manager (RPM), first update the package manager as follows:
sudo yum update
Then, install the packages for the QGIS, PyQGIS, and QGIS GRASS plugins:
sudo yum install qgis qgis-python qgis-grass
Now we need to set 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 2.18\bin"
Next, append QGIS's
bin
directories to the system'sPATH
variable:set PATH="C:\Program Files\QGIS 2.18\bin";"C:\Program Files\QGIS 2.18";%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 a runtime search path. Note that this location can vary depending on your system configuration:
export LD_LIBRARY_PATH=/usr/share/qgis/python
The QGIS installation process and package managers set up the Python module's configuration in a way that it becomes 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 it by using a system Python installation on either Windows or Linux, it would be necessary for you set some system variables so that Python could 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, as opposed to other platforms, are stored in a different location. To locate the path, you need to check the current working directory of the Python console:
Start QGIS.
Select Python Console from the Plugins menu, which will appear in the lower-right corner of the QGIS application window, as shown in the following screenshot. You can also use the keyboard shortcut Control + Alt + P to do this:
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.
Perform the following steps to find the path needed for this recipe on all the other platforms:
Start QGIS.
Start the QGIS Python console.
Use the
sys
module to locate the PyQGIS pathimport sys sys.path
Python will return a list of paths.
Find the path that ends in
/python
, which is the location of the Python installation used by QGIS.
The 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 API.
In the following steps, we'll open the console, create a vector layer in the 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 either a disk or a network so as 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 even to create a single point on the map canvas, as shown here:
First, create a layer that is of the type geometry. Next, reference a data provider to accept the data source.
Then, create a generic feature object, followed by the point geometry.
Next, we add the feature to the layer via the underlying data provider, then add the layer to the map canvas.
The layer type is memory, meaning that you can define the geometry and attributes in the code itself rather than an external data source. In this recipe, we just define the geometry and skip defining any attributes.
As you become familiar with programming QGIS using Python, you'll want the Python console to always be available in QGIS. So, in this recipe, we'll add a Python startup script to QGIS to make sure the console starts when QGIS does.
First, you need the startup.py
file, which QGIS will read at startup. You'll be able to use this file to customize different aspects of QGIS:
In your user directory, locate the hidden
.qgis2
folder.Your user folder is typically located in
~/.qgis2
on Linux and OSX andC:\Users\<username>\.qgis2
on Windows, which you can also access the%USERPROFILE%
environment variable.Create a Python file named
startup.py
.
Open the
startup.py
file you created.Add the following lines to it:
from console import console console.console_show()
The QGIS Python Script Runner 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 Script Runner plugin using the QGIS plugin manager. Then, run the plugin from the Plugin menu to open the Script Runner dialog. Configure a default editor to edit the scripts using the following steps:
Find the gear icon that represents the Script Runner Preferences settings dialog box and click on it.
In the General Options section, check the Edit scripts using: checkbox.
Click on the ... button to navigate 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 Script Runner dialog, click on the New Script icon, as shown in the following screenshot:
Navigate to the directory where you wish to save and name your script.
Verify that the new script is loaded in Script Runner.
Right-click (or control-click on a Mac) on the script name in Script Runner 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 Script Runner plugin.
Verify that the memory layer polygon is added to the QGIS map, as shown in the following screenshot:
Script Runner is a simple but powerful idea. It allows you to build a library of automation scripts and use them from within QGIS 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 Script Runner plugin makes managing lots of scripts easier. But there is also a script editor built into the PyQGIS console. This editor is a panel in the QGIS interface that you can use to create, edit, and run scripts. You can trigger the editor using the fourth icon from the left on the PyQGIS console toolbar.
The Eclipse IDE and the PyDev plugin are cross-platform and free, and they possess advanced debugging tools.
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 Python installations. On Windows, you also need to 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 both the packages supported by your operating system. All platforms, except for Windows, rely on the Python interpreter. This means that there is an extra step in Windows to add the Python interpreter.
The following steps will walk you through the process of adding the QGIS-specific Python interpreter to Eclipse in order to support the running standalone QGIS applications or the debugging of QGIS plugins.
The process used to add a 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.
In the pane on the left-hand side of the Preferences window, click on the arrow icon next to PyDev.
From the list of PyDev preferences, select Interpreters.
In the pane labeled Python Interpreters, click on the New button.
In the Select interpreter dialog, name the interpreter
PyQGIS
.Navigate to the location of the Python interpreter called
python.exe
, placed within thebin
folder of the QGIS program folder. On OS X and Linux, you use the system's Python installation. On Windows, Python is included with QGIS. The default location on Windows isC:\Program Files\QGIS2.18\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 to configure this interpreter. 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 also need to 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.
Select 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 so the script has access to all of the QGIS functions within Eclipse. Next, find that path using the QGIS Python Console by typing the following command:
qgis
For each path in the returned list, 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:
Click on the OK button in the Preferences dialog.
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:
In the PyDev preferences for the PyQGIS interpreter, select the Forced Builtins tab, as shown in the following screenshot:
Click on the New button.
In the Builtin to add dialog, type
qgis
:Click on the OK button.
You will also need to create a PATH
variable that points to the QGIS binary libraries, DLLs on Windows, and other libraries needed by QGIS at runtime. And you'll need to create this on all platforms in the following way:
In the PyDev preferences dialog, ensure that the PyQGIS interpreter is selected from 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 that contain binaries separated by a semicolon. The following is an example from a Windows machine:
C:\Program Files\QGIS 2.18;C:\Program Files\QGIS 2.18\bin; C:\Program Files\QGIS 2.18\apps\qgis\bin;C:\Program Files\QGIS 2.18\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. This setup will allow you to interactively watch the execution of programs as well as pause the execution as needed. This kind of interactive debugging is particularly useful in a GUI program such as QGIS because in addition to the user interface, there are program functions happening behind the scenes. Debugging programs that have processes in the foreground and background can be extremely difficult. This interactive debugging approach makes the development of complex applications such as these much more efficient by stepping through each part of the program as it is executed. You can see what is happening in real time and troubleshoot more easily.
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 the execution while you monitor the program to catch bugs as they occur.
The following steps will add two plugins to QGIS; this will allow Eclipse to communicate with QGIS. The first plugin, Plugin Reloader, allows you to reload a QGIS plugin into the memory without restarting QGIS for faster testing. The second plugin, Remote Debug, connects QGIS to Eclipse. Remote Debug is an experimental plugin, so we must ensure that experimental plugins are visible to the QGIS plugin manager in the list of the available plugins. This can be done in the following way:
Start QGIS.
Under the Plugins menu, select Manage and Install Plugins...
In the left pane of the Plugins dialog, select the Settings tab.
Scroll down the Settings window and ensure that the Show also experimental plugins checkbox is checked, as shown in the following screenshot:
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 too.
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 New Project dialog.
Click on the Next> button.
Give the project the name
HelloWorld Plugin
.Click on the Finish button.
Select the new HelloWorld plugin project in the project explorer window 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 HelloWorld plugin folder.
Tip
You can find the location of the HelloWorld plugin from within the QGIS plugin manager, as shown in the following screenshot:
Click on the Finish button.
In the previous parts of this recipe, we configured Eclipse and QGIS so they could work together 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 breakpoint in the plugin to pause the execution and then monitor the plugins execution from within Eclipse, as follows:
Under the
HelloWorld
folder, open theHelloWorld.py
file.From the Eclipse Window menu, select Open Perspective and then click on Other....
From the Open Perspective 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 breakpoint, which is displayed as a green-colored 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 Remote Debug and then select the Remote Debug 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 breakpoint.From the Run menu, select Resume.
Switch back to QGIS.
Verify that the HelloWorld dialog box has appeared.
The Remote Debug 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 Plugin Reloader plugin can reset plugins that maintain the 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 it.
Note
You can find out more about debugging QGIS, including using other IDEs, at http://docs.qgis.org/testing/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 https://qgis.org/api/modules.html.
The PyQGIS API documentation is not updated frequently because it is nearly identical to the structure of the C++ API. A tool named SWIG, which creates wrappers for multiple languages for C++ libraries, is used to create the PyQGIS API, making the documentation for the C++ API highly applicable for argument types and order. However, the QGIS project on https://github.com/ maintains a list of all the PyQGIS classes for the latest version. The PyQGIS APIs for different versions are located at https://github.com/qgis/QGIS/blob/master/python/qsci_apis/.
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 to that in Python. You should note that the PyQGIS versions are tracked separately from the QGIS version and have different version numbers.
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 Qgs Label are located:
Go to the QGIS API page at http://qgis.org/api/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 QgsPoint.
Click on the QgsPoint 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/PyQGIS-2.2.api.
Scroll down the alphabetical class listing until you see qgis.core.QgsPoint?1().
The QGIS API is divided into five distinct categories, as follows:
Core
GUI
Network analysis
Server
Plugins
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. You'll also notice that the API file contains the methods for each class with the type of parameters the class accepts.
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. And as we'll see throughout this book, you can use Python to create plugins. When you create a Python-based plugin, you can usually access that plugin's functionality through the PyQGIS API.
The easiest approach to creating a plugin is to use the Plugin Builder plugin to jump-start 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 in the submenu.
In the QGIS Plugin Builder dialog, name the class
MyPlugin
.Name the plugin
MyPlugin
.Type a short description, such as
A demonstration Plugin
.Enter
myplugin
as the Module name.Leave the default version numbers as they are.
Enter your name and e-mail address for author information.
Click Next.
Enter a description of the plugin in the About field.
Click Next.
In the Text for menu item field, enter
My Plugin
.Click Next and then on the next dialog click Next again.
For the Bug Tracker field, enter https://github.com/GeospatialPython/Learn/issues.
For the Repository field, https://github.com/GeospatialPython/Learn/.
Ensure that the checkbox labeled Flag the plugin as experimental is checked.
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 to the main program directory:C:\Users\<username>\.qgis2\python\plugins or the %USERPROFILE% environment variable C:\Program Files\QGIS2.18\apps\qgis\python\plugins
On OS X or Linux machines, the
.qgis2
directory will be in your home directory.Close the Plugin Builder information dialog by clicking on the OK button.
Using 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 XML for a custom label near line 31, 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://github.com/GeospatialPython/Learn/raw/master/MyPlugin.zip.
Note
You can find out more about QGIS plugins, including the purpose of the other files in the directory, from 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 manually 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, that 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 https://www.qt.io/download/.
When you run the installer, you can uncheck all the installation options, except the Tools category, to install just the IDE.
The QGIS Processing Toolbox provides a powerful set of algorithms for QGIS Python programming, which we'll see throughout this book. You add your own scripts to the toolbox, and with the latest version of QGIS, you can now turn those scripts into plugins. You can install these plugins like any other QGIS plugin using Plugin Manager and then have those scripts appear in Processing Toolbox. This process is significantly easier than writing a traditional plugin from scratch.
First you need a script to package as a plugin. You can package multiple scripts into a single plugin, but to keep things simple, use one. This sample script will save the current map view as an image. Create the script using the following steps:
In Processing Toolbox, expand the Scripts tree.
Double-click on the Create new script tool.
In the script editor, add the following code, specifying an output directory for your map images:
from qgis.utils import iface import datetime c = iface.mapCanvas() t = '{:%Y%m%d%H%M%S}'.format(datetime.datetime.now()) img_path = '<output directory>/map{}.png' c.saveAsImage(img_path.format(t), None, 'PNG')
Click on the Save As icon to save the image in your scripts directory as
MapImage.py
.The script will then appear in the User Scripts tree under Scripts in Processing Toolbox.
Set up a map view and then double-click on the script to verify that an image has been created in the output directory.
Now you are ready to create the plugin from your sample script:
Under the script tools section in Processing Toolbox, double-click on Create script collection plugin.
Fill out the metadata fields in the dialog.
Ensure the MapImage script is checked in the Script selector dialog.
When you navigate to the output folder, create a new folder called
MapImage
:Click on the OK button
Navigate to the output folder and verify the plugin files were created.
From a functional perspective, all the script does is copy the files to your user scripts directory. But the plugin packaging allows you to distribute your work to other users using the QGIS plugin framework.
The Processing Toolbox has a script manager similar to the QGIS plugin manager, in which you can download scripts written by other users for processing, or as examples to write your own scripts. To access this script manager, expand the Scripts menu in the Processing Toolbox, then expand the Tools menu, and finally double-click Get scripts from on-line scripts collection. From there, you can browse a list of downloadable scripts.
Distributing a QGIS plugin means placing a 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. You should note that QGIS is released under the GNU General Public License (GPL), so presumably all other plugins fall under the GPL as well, based on the terms of the license.
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). Both OSX and Windows can compress and decompress zip files natively. On Linux, you may need to download a ZIP tool from your package manager. 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 other online directories 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://github.com/GeospatialPython/Learn]]> </homepage> <file_name>MyPlugin.0.1.0.zip</file_name> <icon>https://github.com/GeospatialPython/ Learn/raw/master/icon_227.png</icon> <author_name><![CDATA[Joel Lawhead]]></author_name> <download_url>https://github.com/GeospatialPython/ Learn/raw/master/MyPlugin.0.1.0.zip</download_url> <uploaded_by><![CDATA[jll]]></uploaded_by> <create_date>2016-11-19T15:31:19.824333</create_date> <update_date>2016-11-19T15:31:19.824333</update_date> <experimental>True</experimental> <deprecated>False</deprecated> <tracker> <![CDATA[https://github.com/GeospatialPython/Learn/issues]]> </tracker> <repository> <![CDATA[https://github.com/GeospatialPython/Learn/]]> </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
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 Enabled 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 will create 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 of this chapter.
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) path = "C:/Program Files/QGIS2.18/apps/qgis" app.setPrefixPath(path, True) app.initQgis() canvas = QgsMapCanvas() title = "PyQGIS Standalone Application Example" canvas.setWindowTitle(title) canvas.setCanvasColor(Qt.white) layer_info = 'LineString?crs=epsg:4326' layer = QgsVectorLayer(layer_info, 'MyLine' , "memory") pr = layer.dataProvider() linstr = QgsFeature() wkt = "LINESTRING (1 1, 10 15, 40 35)" geom = QgsGeometry.fromWkt(wkt) linstr.setGeometry(geom) pr.addFeatures([linstr]) layer.updateExtents() QgsMapLayerRegistry.instance().addMapLayer(layer) canvas.setExtent(layer.extent()) canvas.setLayerSet([QgsMapCanvasLayer(layer)]) canvas.zoomToFullExtent() canvas.show() 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 draw a line to demonstrate the skeleton of a standalone application, which you can build up further to add more functionality, as we will see in later recipes.
To create line geometry, we use Well-Known Text (WKT), which provides a simple way to define the line vertices without creating a bunch of objects. The map does not appear until you call the canvas.show()
method. This allows you to set up the map behind the scenes and then display it when it is complete.
The standalone application can be compiled into an executable that can be distributed without installing QGIS using either py2exe or PyInstaller.
You can find out 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. QGIS also has project-level preferences, which can override the application-level preferences in some cases. In this recipe, we'll focus on reading and writing the global preferences that serve as the application defaults. QGIS actually takes advantage of Qt's built-in preferences management.
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. We'll also 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. We'll do this 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') settings.sync()
This API is actually the Qt API that QGIS relies on for settings. In the QSettings object, we specify the native format 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 when you change the settings, you must call the sync()
method at the end to save them and let them take effect. Note that when you are writing a standalone QGIS application, you should use your own organization and application name for settings and not QGIS.
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 an earlier recipe, Creating a QGIS plugin, of this chapter. 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. Here are the steps to store and read project preferences:
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() msg = "Geospatial Python Rocks!" proj.writeEntry("MyPlugin", "splash", msg) 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 the 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 Qgs Project 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/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 the 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 manage external data. When writing cross-platform QGIS code, you cannot assume the working directory of your script.
You can also use Python's __file__
variable, which tells you the path of the script currently being executed. For example, path = os.path.dirname(__file__)
On his blog, one of the QGIS developers, Gary Sherman, 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/.