2

I am trying to plot points at specific positions along a line (which exists in the 'current layer' and is selected on the canvas) - these positions are irregular, so I am intending to loop through a list (chainage) and then add a new point layer.

I have created a python script by scrounging around various sources. You may recognise the code as mashed from yours. To get it to nearly work in QGIS 3.4 I've had to adapt some of the existing code to work with the changes to the API since some of the code was written... Introduced errors within this are mine. However, the problem appears to be that it cannot add the integer attribute, even though I used the QGIS pycookbook for that bit:

    from qgis.core import (QgsFeature, QgsGeometry,
                       QgsVectorLayer, QgsProject,
                       QgsField)
from qgis.PyQt.QtCore import QVariant
from qgis.utils import iface
#list of positions along line (chainage) - to do - read a csv file!
chainage = [0,13,34,54]
# Create a new memory layer and add a distance attribute
vl = QgsVectorLayer("Point", "distance nodes", "memory")
pr = vl.dataProvider()
pr.addAttributes( [ QgsField("distance", QVariant.Int) ] )
layer = iface.activeLayer()
selection = layer.selectedFeatures()
for feature in selection:
    geom = feature.geometry()
    # Loop though all the chainage distances
    for dist in chainage:
        fet = QgsFeature()
        fet.setGeometry(geom.interpolate(dist))
        fet.setAttributes(dist)
        pr.addFeatures([fet])
        vl.updateExtents()

QgsProject.instance().addMapLayer(vl)

This nearly works and then falls over at line 19 an error related to the integer.

TypeError: QgsFeature.setAttributes(): argument 1 has unexpected type 'int'

If I comment out that line it works, but obviously I don't have the distance as an attiribute, just the geometry.

Maybe it's because I've cherry picked from different places / versions, because I'm not a python programmer.

I've included all my code because it might be useful to others... There seem to be a few similar questions out there.

I know my code is clumsy and not 'best practice' - once I get it working I can prettify it and probably rationalise it a bit.

1

Try running the code below in the python console with your line layer and feature selected: *Assuming the distance values you want to work with are meters, ensure the layer containing your line feature is in an appropriate projected coordinate system. The code below will assign the same crs to the new memory layer.

layer = iface.activeLayer()
source_crs = layer.crs().authid()
chainage = [0, 13, 34, 54]
vl = QgsVectorLayer('Point?crs={}'.format(source_crs), 'Distance_nodes', 'memory')
pr = vl.dataProvider()
pr.addAttributes([QgsField('distance', QVariant.Int)])
vl.updateFields()
fld_idx = vl.fields().lookupField('distance')
selection = layer.selectedFeatures()
for feat in selection:
    g = feat.geometry()
    for dist in chainage:
        f = QgsFeature()
        f.setGeometry(g.interpolate(dist))
        atts = {fld_idx: dist}
        pr.addFeature(f)
        pr.changeAttributeValues({f.id(): atts})
QgsProject().instance().addMapLayer(vl)
#the two lines below are optional; they just zoom to the features of the
#new memory layer
iface.setActiveLayer(vl)
iface.zoomToActiveLayer()

The screenshots below show the 'Distance_nodes' memory layer added to the layers panel and labelled with the 'distance' field, and the attribute table with the 'distance' attributes.

enter image description here

enter image description here

I have not included the imports as they are not needed in the console. Different story if you are implementing this in a plugin... and, if you are, then an algorithm like this would be a good candidate for putting into a script for the processing toolbox.

  • Most helpful and much appreciated - I have in mind a plugin, but lack the skills to create one, good idea for the processing toolbox - I will bear in mind the imports (a trip hazard identified!) if I start stumbling in that direction. – SeeWhy Mar 7 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.