J-Term 2021, Week 3: Finishing the Plugin
This week I attacked the last two elements of my plugin: the Direction and Distance tool and installation of the Maki and National Park Service (NPS) icon sets. My first step was to convert the Direction and Distance model to a Python script. I thought this one was going to be pretty easy since the model is mostly just a bunch of Processing tools strung together—I figured I’d just need to get the script spruced up and easy to understand. There’s an Execute SQL
step in this model as well, but the query formula is much simpler than in Group By
, so it was pretty easy to get it working.
Of course I should’ve known that there’s no free lunch in programming or GIS land. I hit a snag at the step where Field Calculator
is used to calculate direction via the azimuth()
function. The model uses a formula that refers to the x- and y- coordinates of a point layer generated earlier in the model, but when you’re running Field Calculator
from a Python script on any given layer, you don’t have access to other layers. All I needed to do was find the x- and y-coordinates of the point and plug them into a string that I could then pass into the Field Calculator
. Although this task seemed incredibly simple, I couldn’t think of a straightforward way to do it.
After searching through the Processing Toolbox, I came upon a tool called Add Geometry Attributes
that adds a layer’s geometry information as additional fields. In the case of a point layer, these additional fields are just the x- and y-coordinates. I ended up using this tool to get the x- and y-coordinates of my point layer, accessing those coordinates as feature attributes, and storing them as Python variables. (I figured out how to do this from this GIS Stack Exchange discussion and the PyQGIS Developer Cookbook.) But even this approach gave me some trouble at first. I couldn’t figure out why it wasn’t working until Prof. Holler suggested that maybe I was using the wrong indices for the feature or attributes I was trying to access. It turns out that I thought the features in a layer are indexed starting at 0, when in reality the first feature has index 1. When I tried to access the feature at index 0, there wasn’t anything there. But when I switched that number to 1, per Prof. Holler’s suggestion, that part of my code suddenly worked smoothly. After I fixed a couple of small mistakes related to the definition of the output dictionary, the script ran perfectly!
Now I needed to add icons to display next to my plugin and its algorithms in the Processing Toolbox. I took a look at the QNEAT3 source code to figure out how to do this. The task ended up being pretty simple. For each algorithm as well as the provider, I just needed to use the os.path
module to find the path where the plugin files were located, add an icons folder to my plugin files, and then have the icon()
method return the path of the icon I wanted as a QIcon
object.
My final task was to figure out how to have the plugin import Prof. Holler’s folders of Maki icons and NPS icons. It took me a bit to figure out how best to approach this one. I looked at the source code for Akbar Gumbira and Håvard Tveite’s QGIS Resource Sharing plugin, which enables you to download and install a variety of resources for QGIS, including SVGs, other images, Processing scripts, R scripts, and more. I also pored over this handy GIS Stack Exchange discussion that explains how to manage the paths QGIS uses to search for SVGs. The Resource Sharing plugin has so many files and is so difficult to understand that I eventually gave up on trying to decipher its code and instead went with an approach I found in the GIS Stack Exchange discussion.
Inside __init__.py
, which initializes the plugin, I wrote some code, adapted from YoLecomte’s answer on Stack Exchange, to check if the Maki and NPS icon paths are already in the user’s SVG paths and, if not, to add the icon paths to the list of SVG paths. At first, I could tell I had messed up because my plugin stopped loading in QGIS. I couldn’t figure out what I had done wrong, so I commented out my new block of code and started uncommenting it line by line, reloading the plugin each time to see if it would show up, until I found my mistake. Finally I realized that I had just added an extra parenthesis. I removed it, and the plugin returned to my Processing Toolbox. Finally I was in business with full plugin functionality! Next week I’ll be going through my scripts to make sure they’re neat and well commented, and then I’ll be packaging the plugin as a .zip file and uploading it to GitHub. Eventually I’ll be adding it to the QGIS Plugin Repository for the entire QGIS community to access.
Visit the MiMiGIS GitHub repository here!