Sunday 30 December 2018

qgis - Replacement of QVariant and setAttributeMap in PyQGIS


I am updating a plugin for QGIS 1.8 to QGIS 2.x. I have the code below.





  1. The setAttributeMap does not exist anymore. I have replaced it with fet.setAttributes and it seems to work.




  2. When using fet.setAttributes({0:QVariant(fid}), I get the error:




PyQt4.QtCore.QVariant represents a mapped type and cannot be instantiated.


I have tried to just remove the QVariant() and used fet.setAttributes({0:fid}), but then I get the error:



TypeError: QgsFeature.setAttributes(list-of-attributes): argument 1 has unexpected type 'dict'


The code worked well with 1.8, so what can I do to replace QVariant or setAttributeMap? I think it could be something with changing setAttributeMap to setAttributes


vl = QgsVectorLayer("MultiLineString", layerName, "memory")
pr = vl.dataProvider()
vl.startEditing()
pr.addAttributes([QgsField("id", QVariant.Int)])
fet = QgsFeature()
addRange = northRange * math.tan(abs(math.radians(bearing)))
noPoints = ((eastRange + addRange) / projEast) + 1
for i in range(0,int(math.ceil(noPoints)), 1):

fet.setGeometry( QgsGeometry.fromMultiPolyline( [[ QgsPoint(minE + offset + (projEast * i) ,minN), QgsPoint(minE + offset + (projEast * i) - addRange,maxN) ]] ))
fet.setAttributeMap({0:QVariant(fid)})
pr.addFeatures( [ fet ] )
fid = fid + 1
vl.commitChanges()
QgsMapLayerRegistry.instance().addMapLayer(vl)



I have change my code to:


vl = QgsVectorLayer("MultiLineString", layerName, "memory")

pr = vl.dataProvider()
vl.startEditing()
pr.addAttributes([QgsField("id", QVariant.Int)])
fet = QgsFeature()
fields = vl.pendingFields()
fet.setFields( fields, True )
addRange = northRange * math.tan(abs(math.radians(bearing)))
noPoints = ((eastRange + addRange) / projEast) + 1
for i in range(0,int(math.ceil(noPoints)), 1):
fet.setGeometry( QgsGeometry.fromMultiPolyline( [[ QgsPoint(minE + offset + (projEast * i) ,minN), QgsPoint(minE + offset + (projEast * i) - addRange,maxN) ]] ))

fet['id'] = fid
pr.addFeatures( [ fet ] )
fid = fid + 1
vl.commitChanges()
QgsMapLayerRegistry.instance().addMapLayer(vl)

but I still need to make an attribute named 'id' I guess before it works. If I use the setAttributes function it includes a QVariant which I am not allowed to do!


Or is it me who does not understand.




This is the final code, and it is working:



vl = QgsVectorLayer("MultiLineString", layerName, "memory")
vl.startEditing()
vl.addAttribute(QgsField("id", QVariant.Int))
fet = QgsFeature()
fields = vl.pendingFields()
fet.setFields( fields, True )
addRange = northRange * math.tan(abs(math.radians(bearing)))
noPoints = ((eastRange + addRange) / projEast) + 1
for i in range(0,int(math.ceil(noPoints)), 1):
fet.setGeometry( QgsGeometry.fromMultiPolyline( [[ QgsPoint(minE + offset + (projEast * i) ,minN), QgsPoint(minE + offset + (projEast * i) - addRange,maxN) ]] ))

fet['id'] = fid
vl.addFeatures( [ fet ] )
fid = fid + 1
vl.commitChanges()
QgsMapLayerRegistry.instance().addMapLayer(vl)

Answer



You can still use QVariant but don't use it as a type.


E.g. the following is still fine:


from PyQt4.QtCore import QVariant
vl.startEditing()

vl.addAttribute(QgsField("id", QVariant.Int))

However, it is no longer required (and no longer allowed) to use QVariant as a datatype. This means, instead of QVariant(fid) you should just use fid. You already have posted a link to the relevant section in the API changes.


The API also changed in terms of vector layer handling, which can be confused with the changes concerning QVariant but it's a different pair of shoes.


The relevant code for this is:


fet = QgsFeature()
fields = vl.pendingFields()
fet.setFields( fields, True )
fet['id'] = 42


And a minor note:



  • If you directly work on the dataprovider ( pr.addFeatures(), pr.addAttributes()) there is no need to toggle layer editing ( vl.startEditing(), vl.commitChanges()). If you want an undo stack, use the QgsVectorLayer methods instead of the QgsVectorDataProvider methods (i.e. by using vl.[method] instead of pr.[method]. If you work directly on the dataprovider, another caveat is, that events (updated features...) may not be propagated properly and lead to inconsistencies in the representation (attribute table...). TL;DR: Use vl.addFeature() instead of pr.addFeatures()


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...