PyQGIS 3 – Setting QgsVectorFileWriter.SaveVectorOptions for QGIS 3

pyqgispyqgis-3saveshapefilewriters

I wrote a processing scrip for QGIS 2.18 to create a multi-distance buffer rings using the haversine formula. Unfortunately, it no longer works after I updated to QGIS 3.4.5. I've tried updating the script wherever I can but I can't figure out how to fix the part of the code where it writes the buffers to a shapefile.

Here's my code:

from math import *
from qgis.core import *
from qgis.utils import iface
from PyQt5.QtCore import *
from PyQt5.QtGui import *

layer = iface.activeLayer()
for feat in layer.selectedFeatures():
    geom = feat.geometry()

start_x = geom.asPoint().x()
start_y = geom.asPoint().y()
sides = 64
radius = 6378137.0  # meters

# create layer
vl = QgsVectorLayer("Polygon", "Distance Buffers", "memory")
pr = vl.dataProvider()

# changes are only possible when editing the layer
vl.startEditing()

# add fields
pr.addAttributes([QgsField("Distance", QVariant.Int), QgsField("Label", QVariant.String)])

distance = [250, 500, 1000, 2000, 3000, 4000, 5000, 10000, 15000, 20000, 25000, 30000, 40000, 50000]
for i in range(len(distance)):
    points = []
    dist = distance[i]
    degrees = 0
    while degrees <= 360:
        degrees = degrees + 360 / sides

        start_lon = start_x * pi / 180
        start_lat = start_y * pi / 180
        bearing = degrees * pi / 180

        end_lat = asin((sin(start_lat) * cos(dist / radius)) + (cos(start_lat) * sin(dist / radius) * cos(bearing)))
        end_lon = start_lon + atan2(sin(bearing) * sin(dist / radius) * cos(start_lat),
                                    cos(dist / radius) - (sin(start_lat) * sin(end_lat)))

        points.append(QgsPointXY(end_lon * 180 / pi, end_lat * 180 / pi))

        fet_name = str(distance[i])
        if distance[i] < 1000:
            label = str(distance[i]) + "m"
        else:
            label = str(distance[i]/1000) + "km"

    # add a feature
    fet = QgsFeature()
    geometry = QgsGeometry.fromPolygonXY([points])
    fet.setGeometry(geometry)
    fet.setAttributes([fet_name,label])
    pr.addFeatures([fet])

# commit to stop editing the layer
vl.commitChanges()

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

myDir = QgsProject.instance().readPath("./")
file_name = 'Distance Buffers' + '.shp'
ShapefileDir = myDir + "/Shapefiles/" + file_name

_writer = QgsVectorFileWriter.writeAsVectorFormat(vl, ShapefileDir, "utf-8", None, "ESRI Shapefile")

At the last line of the code I get this error:

Traceback (most recent call last): File
"C:/PROGRA~1/QGIS3~1.4/apps/qgis-ltr/./python/plugins\processing\script\ScriptEditorDialog.py",
line 227, in runAlgorithm exec(self.editor.text(), d) File "", line
68, in TypeError: QgsVectorFileWriter.writeAsVectorFormat(): arguments
did not match any overloaded call: overload 1: argument 4 has
unexpected type 'NoneType' overload 2: argument 4 has unexpected type
'NoneType' overload 3: argument 3 has unexpected type 'str'

Based on the QGIS 3.0 documentation, I think writeAsVectorFormat now takes the following arguments: writeAsVectorFormat(layer: QgsVectorLayer, fileName: str, options: QgsVectorFileWriter.SaveVectorOptions, newFilename: str = ‘’) but I can't figure out how to set the SaveVectorOptions.

Can someone show me how this is done with this script, or with any other working examples?

Best Answer

As it happens, I have just finished updating the documentation on vector layers. The big change is that you can't pass in None as the CRS any longer, so either use an explicit one or leave it out altogether.

You now need something like:

writer = QgsVectorFileWriter("my_shapes", "UTF-8", driverName="ESRI Shapefile")

The latest docs are available which give the full list of parameters.

Related Question