J-Term 2021, Week 1: Getting Started

I spent this week getting acquainted with the basics of QGIS plugins and object-oriented programming in Python. Although I have experience with object-oriented programming in Java, most of my time coding in Python has been from a functional approach. I’ve also written both Processing scripts and standalone scripts in Python for QGIS, but I haven’t packaged them into a plugin before.

My first step was to follow this tutorial where Ujaval Gandhi leads you through the process of writing a basic QGIS Python plugin—in this case, one that saves the attributes of a layer as a CSV. Probably the most difficult part for me was actually getting my computer (a Mac) ready for the task: installing the Xcode command line tools, then Homebrew, then Qt Creator, and finally the PyQt package. Other than compiling and running Java code, I hadn’t previously spent much time interacting with the Terminal, so this was all pretty new for me.

Following the tutorial directions and using the Plugin Builder plugin for QGIS, I didn’t have much trouble actually making the plugin. Plugin Builder is awesome because it creates and populates all the files you need for a viable plugin—you just need to add the functional code that allows the plugin to do its work and, if applicable, to build your GUI in Qt Creator (using an empty file that Plugin Builder creates for you). I started to run into trouble only when I decided to go into the code and try to experiment with different configuration options, such as having the plugin load in the Raster menu instead of the Vector menu. Now the plugin started to load in multiple menus and the icon appeared multiple times in the plugins toolbar, and I had trouble getting those extra instances to vanish even once I reverted back to the original code. (Restarting QGIS eventually did the trick.) Later I realized that I should have paid more attention to the menu in Plugin Builder that allows you to choose the location of the plugin before you actually build it.

Once I finished building my plugin, I spent some time going through the associated files to see how things actually worked. Although I had thought I was pretty familiar with Python, I quickly realized I had a lot to learn. Basically, the plugin is implemented using a class called, in this case, SaveAttributes. This class contains a constructor and several methods that help implement, load, and unload the plugin in QGIS. Finally, there is a run method where you put the code you want the plugin to execute. I had never implemented new Python classes before, so I had to learn that __init__ denotes a constructor, that __file__ represents the path to the module currently being imported, and much more. Outside of the main file, save_attributes.py, there is __init__.py, which initializes the plugin, save_attributes_dialog.py, which connects the .ui file for the GUI, and many other files, both Python and non-Python. It’s a lot to absorb at once, but I felt like I was beginning to understand the basics.

One thing that still puzzled me was how to get my plugin loaded into the QGIS Processing Toolbox. I examined the code for QNEAT3, a QGIS plugin by Clemens Raffler with a variety of network analysis algorithms for the Processing Toolbox, to see how it worked. (If I thought my Save Attributes plugin was complicated, this one was on an entirely new level.) Upon examination of the various .py files, I realized that this plugin includes its own processing provider—in this case, Qneat3Provider, which is a child class of QgsProcessingProvider. Qneat3Provider has a method to load all of the QNEAT3 algorithms, which upon installation reside in the Processing Toolbox. My plugin will follow the same general format, although it won’t be nearly as complex as QNEAT3.

Week 2: Getting Group By Up and Running

MiMiGIS Blog Homepage


Back Home