33. Developing QGIS Plugin#

33.1. Quickstart to develop a processing plugin#

  1. Create a plugin template with the QGIS plugin “Plugin Builder”. We will create a processing plugin, where I am just going to use the default GUI given by QGIS to develop the plugin. The plugin will appear in Processing -> Toolbox -> gis3d

  2. Copy and paste the plugin folders to the qgis plugin folders with the following command.

    cp -r /where/your/plugin/is /home/your_usr_name/.local/share/QGIS/QGIS3/profiles/default/python/plugins
    
  3. Open QGIS, the plugin should appear in the processing toolbox window

  4. Repeat 1- 3 as you make changes to your plugin. Download the plugin “Plugin Reloader”. So that you can just reload the plugin without shutting down QGIS.

33.2. Add logo and decide which menu the plugin reside in#

33.3. How to edit the input layer#

An example script showing how to edit the input layer.

def initAlgorithm(self, config):
    ....
    ....
    ....

    self.addParameter(
        QgsProcessingParameterFeatureSource(
            self.TREE_HEIGHT,
            self.tr('Tree Grid Layer'),
            [QgsProcessing.TypeVectorAnyGeometry]
        )
    )

    ....
    ....
    ....

def processAlgorithm(self, parameters, context, feedback):
    ....
    ....
    ....

    tree = self.parameterAsVectorLayer(parameters, self.TREE_HEIGHT, context)
    tree_data = tree.dataProvider()
    tree_data.addAttributes([QgsField(tree_height_name, QVariant.Double)])
    tree.updateFields()

    tree_features = tree.getFeatures()
    tree_fields = tree.fields().names()
    tree_height_field_id = tree_fields.index(tree_height_name)

    total = 100.0 / tree.featureCount() if tree.featureCount() else 0

    for cnt, feature in enumerate(tree_features):
        # Stop the algorithm if cancel button has been clicked
        if feedback.isCanceled():
            break
        
        # Update the progress bar
        feedback.setProgress(int(cnt * total))
        
        fid = feature.id()
        attrs = {tree_height_field_id: 15.2}
        tree_data.changeAttributeValues({fid:attrs})
        
    ....
    ....
    ....

33.4. How to create a new layer and populate it with new features and attributes#

An example script showing how to create a new sink layer.

def initAlgorithm(self, config):
    ....
    ....
    ....

    self.addParameter(QgsProcessingParameterFeatureSource(self.TREE_HEIGHT,
                                                        self.tr('Tree Grid Layer'),
                                                        [QgsProcessing.TypeVectorAnyGeometry])

    self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
                                                        self.tr('Tree Height Layer'),
                                                        QgsProcessing.TypeVectorPolygon))
    
    ....
    ....
    ....

def processAlgorithm(self, parameters, context, feedback):
    ....
    ....
    ....

    tree = self.parameterAsSource(parameters, self.TREE_HEIGHT, context) #QgsProcessingFeatureSource
    fields = tree.fields()
    fields.append(QgsField(tree_height_name, QVariant.Double))
    tree_features = tree.getFeatures()
    total = 100.0 / tree.featureCount() if tree.featureCount() else 0

    (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, fields, tree.wkbType(), tree.sourceCrs())
    for cnt,feature in enumerate(tree_features):
        # Stop the algorithm if cancel button has been clicked
        if feedback.isCanceled():
            break
        
        # Update the progress bar
        feedback.setProgress(int(cnt * total))

        feature.setFields(fields)
        feature[tree_height_name] = 15.3
        sink.addFeature(feature, QgsFeatureSink.FastInsert)

    ....
    ....
    ....

33.5. Submitting your plugin to QGIS plugin repository#

33.6. Geopandas and laspy#