5

I want part of my plugin to multiple value of length and add it to table.Basing on this question: How to use QGIS field calculator in python? , I made script that works fine for some filed: I can multiple values of another field (integer) but I can't multiple values ot the 'length' field (double type). I don't know why, but when I'm trying to do : 'length *2' the result is NULL. The 'length' is calculated also inside the plugin.

I'm not sure if the question is understandable, hope code snippets will help:

This is how I calculate length to the 'length' field:

layer = QgsMapLayerRegistry.instance().mapLayersByName("memory:temp_layer") [0]

layer.dataProvider().addAttributes([QgsField("length", QVariant.Double,len = 6, prec = 2)])
layer.updateFields()

idx = layer.fieldNameIndex('length')

layer.startEditing()

for feat in layer.getFeatures():
    lengths = feat.geometry().length()
    layer.changeAttributeValue(feat.id(), idx, lengths)

layer.commitChanges()

This is how I want to multiple:

layer = QgsMapLayerRegistry.instance().mapLayersByName("memory:temp_layer")[0]

layer.startEditing()

layer.dataProvider().addAttributes([QgsField('n', QVariant.Double,)])
layer.updateFields()

idx = layer.fieldNameIndex('n')

e = QgsExpression ("length * 2")
e.prepare(layer.pendingFields())

for f in layer.getFeatures():
    f[idx] = e.evaluate(f)
    layer.changeAttributeValue(f.id(),idx, e.evaluate(f))

layer.commitChanges()   

I came up with idea that the problem may be that lengths type is float while Qvariant type of field is double. Even if, I don't know how to handle this.

I can multiple 'length' field using standard field calculator, not via Python script and the result is fine.

Any ideas?

  • 2
    Apparently, the problem is that you cannot use the word 'length' as name of field. It is a reserved word. See my answer. – xunilk Mar 6 '16 at 18:01
4

The real problem lies in this line:

e = QgsExpression ("length * 2")

This creates an expression length * 2. However, length is a function name in QGIS expressions and expects to be used with an argument (eg length(some_geometry) or length('some_string')).

If your column is named length, you need to escape this name and enclose it in quotation marks so that QGIS knows you are referring to a column and not the internal function.

Accordingly, the expression should be "length" * 2, and the offending line in your script needs to be updated to:

e = QgsExpression( "\"length\" * 2 " )

Note that in general it's always good practice to escape any field name like this, regardless of whether or not it collides with functions names. It will also resolve cases when field names are complex and contain spaces or other non-alphanumeric characters.

  • Thanks for the tip. Good to know about names of fields. I'm sure this knowledge will be useful in future. Maybe I'll change the question somehow (to include the fields' names issue) to make the solution easier to find for others. – antonio Mar 6 '16 at 22:41
3

I tried out your code with a shapefile and it worked.

First:

from PyQt4.QtCore import *

layer = iface.activeLayer()

layer.dataProvider().addAttributes([QgsField("l", QVariant.Double,len = 6, prec = 2)])
layer.updateFields()

idx = layer.fieldNameIndex('l')

layer.startEditing()

for feat in layer.getFeatures():
    lengths = feat.geometry().length()
    layer.changeAttributeValue(feat.id(), idx, lengths)

layer.commitChanges()

for creating the field 'l' (not 'length').

Afterwards, I ran the next code to evaluate the expression and it worked perfectly; as it can be observed at the attributes table of next image for my shapefile.

from PyQt4.QtCore import *

layer = iface.activeLayer()

layer.startEditing()

layer.dataProvider().addAttributes([QgsField('n', QVariant.Double,)])
layer.updateFields()

idx = layer.fieldNameIndex('n')

e = QgsExpression ("l * 2")
e.prepare(layer.pendingFields())

for f in layer.getFeatures():
    f[idx] = e.evaluate(f)
    layer.changeAttributeValue(f.id(),idx, e.evaluate(f))

layer.commitChanges()

enter image description here

The problem is that, apparently, you cannot use the word 'length' as name of field. It is a reserved word.

  • Wow. So simple. SO SIMPLE! Of course, it works perfectly. To be honest I tried changing name of the column before. But it was 'length_[m]'. So probably still too close to 'length', right? Anyway, @xunilk thanks a lot for your help! – antonio Mar 6 '16 at 19:14
  • You're welcome and yes. It still too close to 'length'. Probably it would work with something as 'my_length'; for example. – xunilk Mar 6 '16 at 19:28
  • 1
    I've added an explanation about the reserved column names in an answer below – ndawson Mar 6 '16 at 21:11

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.