How to build custom plugins in QGIS

When I needed to change a part on my 4WD expedition truck, there was no spanner known to man that could get the job done. So, I welded one up out of scrap material I had laying around, and while it wasn’t pretty, it did the job. Now, whenever I need to undo that part again, I have it in my toolbox. 

The great news is that we can do the same thing with mapping software! 

QGIS, a free and open source Geographic Information System, has a lot of inbuilt tools - but sometimes there isn't an elegant way to achieve what you want using only these tools. For instance, you might have a repetitive task to do, or have the same sequence of geospatial processing for some common analysis that you need to run day in and day out. But there’s good news: these tasks can be scripted using the PyQGIS Python library.

 

What is PyQGIS? 

PyQGIS is a Python library we can use to talk to the QGIS application. It connects to the interface itself, including the buttons, menus and data layers. PyQGIS also allows us to connect to the background processing algorithms included in QGIS. 

More specifically, we can: 

  •       Customise the QGIS User Interface (UI) 
  •       Add and remove layers
  •       Change which layers are visible
  •       Programmatically change symbology
  •       Edit the geometry of features
  •       Edit attribute tables of layers
  •       Run geoprocessing tools with full control of inputs, outputs and parameters
  •       Access data from other Web APIs and add it to new layers in your project

How do we use this PyQGIS thing? 

There are a few ways to use PyQGIS. To start exploring, open the Python Console within QGIS. The PyQGIS library will be automatically imported for you:

PIcture 1

PIcture 2

In this example, I typed iface.mapCanvas().layers() to get a list of the layers that are in my map canvas. This is extremely useful in scripts, which are a series of Python commands. 

Thankfully, QGIS also comes with a Python script editor - which allows us to chain together a series of commands and run them. These scripts can be saved and uploaded into different QGIS projects, which makes daily workloads a little bit faster and seamless:

Picture 3

In this example, I used PyQGIS to get the name of the active layer, and the number of features in the active layer. I then displayed this to the user in a message. The commands are:

layer = iface.activeLayer()

layerName = layer.name()

featureCount = layer.feautreCount ()

iface.messageBar().pushMessage(f’Thelayer {layerName} has {featureCount} features.’)

Here are some steps I followed to get here: 

  1. I stored a reference to the active layer object in a variable called ‘layer’
  2. I used the layer reference to get the name of this layer and store it in a variable called ‘layerName
  3. I used the layer reference once again to get the number of features using the featureCount() method, and store that into a variable called featureCount
  4. Finally, I used string interpolation to make a display message for the user on the QGIS interface. 

These little scripts are the best way to start experimenting with PyQGIS. But the cool thing is, they are also the building blocks of plugins. Plugins include custom Python scripts - but they show up in our QGIS application as a clickable tool button, and can have a fully customised Graphical User Interface (GUI). 



So, now we should decide what we want to automate. What does our tool need to do? What functions in the PyQGIS library can help us achieve that?

Tip 1: Test the PyQGIS functions we need to use in the QGIS Python Console.

My first tip will help you to see how to use the functions. Specifically, you will need to experiment with them to find out what arguments you need to provide to the functions, and what data they return. So try out your PyQGIS functions in the console. Test each PyQGIS function you want to use in your code, but test them on their own in the console, and try to manipulate the application. You will quickly learn how each one works, before things get any more complex.

Let's say we have a plan figured out and we know what PyQGIS functions we need to use. But how do we then incorporate these functions into the plugin code? Enter tip two. 

Tip 2: Install the QGIS Builder plugin. This will generate a boilerplate, or skeleton code for your plugin. 

picture 5

Follow the prompts in the dialog box, and make sure to save the code it generates to your local QGIS plugins folder. I put mine here:

C:/Users/username/AppData/Roaming/QGIS/QGIS3/profiles/default/python/plugin/HERE

There are a lot of files within the generated boilerplate, but don’t be intimidated, you only need to edit two of them. This is what the file structure looks like:


We are going to put all of our working Python code in the file called `example_plugin.py`. Don’t worry about this for now, before we continue with PyQGIS functions we need to do some work on the user interface of the plugin first! To do that we edit the `example_plugin_dialog_base.ui` file. 

 

The GUI

The GUI of a plugin is built using Qt. Qt is a cross-platform framework for UI development on QGIS, so it is handy to know. 

We need to edit the file called `example_plugin_dialog_base.ui`. We could edit this in code, but I find it easier to create user interface items graphically with the Qt editor. 

On Windows, the OSGEO4W installer comes with a copy of Qt Designer, but on Mac you need to download and install this separately. On Linux, I have only used Qt Creator, which is a more feature-rich version of the software and works just as well. 

Once you have Qt installed, open the example_plugin.ui file in Qt Designer. Here are my tips for the GUI design component:

  • Put everything in a grid! This helps with resizing and different screen resolution
  • Rename the object name for each element to something that makes sense to you
  • Make use of the QGIS Custom Widgets that comes with the OSGEO4W installer
  • Adding images and logos can be tricky. See this link for help and assistance.
  • After making changes, save the .ui file, find and install the ‘plugin reloader’ plugin in QGIS, and check your changes
  • Use a Top Level Layout (see below)

Using a ‘Top Level Layout’ means that all of your GUI content (including any grids) is locked into a global container, and will deal with any resizing of the plugin window and different screen resolutions.

picture 7

 

Python Code

Almost all of the code for editing will be in the file called example_plugin.py. 

I use a free Integrated Development Environment (IDE) called Visual Studio Code to edit this file, but just use any text editor or IDE that you are comfortable with. You can’t easily run or debug the file within Visual Studio Code anyway, so we are mostly just using it as a text editor with some nice highlighting. 

The basic workflow is to make some changes to this file, and then open the plugin in QGIS and see the result of your changes there. 

 

Tip 4: After each change you make in your plugin, use the ‘plugin reloader’ to reload it and test straight in QGIS.

When it comes to the boilerplate, most of your code will go at the bottom of the example_plugin.py file. All the main running code will go in the run(self) method. I generally put my other custom methods above this. Here is an example:

This shows how the first time the plugin is run, the Dialog will be instantiated. We also do some tricky button disconnect if the plugin is loaded a second time, to avoid things happening twice that shouldn’t – you will learn these tricks as you go along, don’t worry! We then check to see if we have saved our API key in memory, something specific to this plugin that I built. We then go through and connect all the buttons in the UI to the specific methods that we want them to trigger. Then we show the dialog! Here are some of the specific methods that I have put above the run(self) method.

For example, when you click the button on the UI called forgetButton, this will call the forgetApiKey() method. Starting to make sense? 

 

Tip 5: You should really think about modularising your code so that you can have the UI buttons call discrete methods that do specific things.

For example, in this Fulcrum plugin I made, I have the following custom methods.



Tip 6: Use the Python console to test your custom methods. 

You can interact with any of the active plugins in a QGIS project using PyQGIS and the Python console. All you have to do is store a reference to the plugin in a variable, and then call the plugin’s methods to test them. This is where you can save a reference to the plugin in a variable called `plug`: 

Now, you can call any of the custom methods you made from the console, using the syntax `plug.method(parameters)`. This isolates the Python code from the UI, which is useful for testing and personally, saved me a lot of time.

Finally, I'd like to share some links to set you on the right path to develop your own QGIS plugins. Good luck!

 

Tip 7: Pathway to QGIS plugin development success

  1. This course for building a Python plugin is really easy and covers a lot of this blog: https://www.qgistutorials.com/en/docs/3/building_a_python_plugin.html
  2. Then go through this to learn PyQGIS library in more detail: https://courses.spatialthoughts.com/pyqgis-in-a-day.html
  3. Refer to the docs if you get stuck: https://qgis.org/pyqgis/3.0/
  4. Set up a GIS StackExchange account and ask for advice here: https://gis.stackexchange.com/
  5. For more in-depth learning, check this out next: https://docs.qgis.org/3.16/en/docs/pyqgis_developer_cookbook/index.html

Want to brush up on your QGIS skills?  

To get the most from QGIS, it is worth taking a training course to keep your skills sharp.

NGIS offers training for the fundamentals of QGIS and QGIS for local government. The one-day courses cover all the necessary skills to begin creating, editing and managing the software, setting you up to unleash the power of QGIS for your next geospatial project. 

Read about our QGIS courses here.

WANT TO READ MORE GIS TECH BLOGS LIKE THIS? 

Sign up to receive our fortnightly Geotech Friday newsletter.

 

About the author: Stafford Smith

Stafford is a GIS Analyst-Developer at NGIS.

Back To News Stories

Connect with us

Perth office
1a/53 Burswood Road,
Burswood WA 6100,
Australia
Sydney office
Level 24, Three International Towers,
300 Barangaroo Ave,
Sydney NSW 2000,
Australia