The last implementation step ahead of us is actually placing the locations on the main QGIS canvas. This might seem like a lot of work but is actually the easiest part of our plugin.

Word of advice: you might be tempted to create a Python package named qgis in your code. It is highly not recommended as it might confuse Python interpreter package path enough that your whole plugin will not work. I’ve made this mistake so that you don’t have to! :)

When creating a new vector layer, we always need to consider what use cases our layer will cover. Especially, you should know the answer to these questions:

  • what geometry type will be used in the layer? in our case, these will always be points but QGIS supports practically any geometry type; just be warned that as soon as you start mixing geometry types, the layer management can become quite tricky - perhaps consider separating your geometry features to layers with one geometry type
  • what coordinate reference system (CRS) will be used? CRS is defined on a layer layer, so you might need to unify all your data to one common CRS by using transformations; we will use WGS 84 as this is the projection provided by API
  • how persistent do you need your data to be? each layer defines its separate data provider which serves as the geometry feature backend; in our example we will use an in-memory data provider but you’re free to use any other providers available

Consult plugin code to see in detail how a vector layer can be constructed. Look for the layers package.

Creating a vector layer is not enough because QGIS does not know yet what we intend to do with the layer. We will use a global QgsProject instance which besides other things acts as a QGIS vector layer registry:

QGIS_REGISTRY = QgsProject.instance()

class GeoapifyPluginDockWidget(QtWidgets.QDockWidget, FORM_CLASS):

  def __init__(self,
               ...,
               registry: QgsProject = QGIS_REGISTRY):
      self._registry = registry
  
  ...
  
  def _successCallback(self,
                       result: Tuple[GeoDataFrame, QgsVectorLayer]):
      geoframe, vector_layer = result
      ...
      self._registry.addMapLayer(vector_layer)

Recall that _successCallback is a function which gets executed whenever a success signal is emitted from the worker thread.

After creating and registering a new point vector layer, this is what the first working version of our plugin looks like:

vector layer

Even though we will not go into unit and integration tests for this functionality, please take the time to write them! As always, the test suite is available in the repository if you need a helping hand.

To wrap things up, we will setup a plugin documentation and polish up our release cycle.