2

I'm trying to write a script using QGIS 3.4. What I want to achieve is an Excel-style calculation where I can create a new field "field2" and calculate the difference between a current and previous row of an existing field "field1".

However, I'm stuck at the first step which is creating the new field. Attached my sample code below. The first part is how I generated my layer from an interpolation process.

    # Interpolate
        mem_layer = QgsVectorLayer("Point?crs="+vlayer.sourceCrs().authid(), 'point', 'memory')
        mem_layer.startEditing()
        fields = [field for field in csvlayer.fields()]
        prov = mem_layer.dataProvider()
        prov.addAttributes(fields)
        mem_layer.updateFields()

        chainageIdx = csvlayer.fields().indexFromName(chainage_field)

        for line in vlayer.getFeatures():
            for feat in csvlayer.getFeatures():
                new_feat = QgsFeature()
                attrs = feat.attributes()
                new_feat.setGeometry(line.geometry().interpolate(float(attrs[chainageIdx])))
                new_feat.setAttributes(attrs)
                mem_layer.addFeatures([new_feat])
        mem_layer.commitChanges()

    # Calc 1
        mem_layer.startEditing()
        datetimeField = QgsField('DateTime', QVariant.Double)
        prov = mem_layer.dataProvider()
        prov.addAttributes([datetimeField])
        mem_layer.updateFields()
        fields.append(datetimeField)

        newdatetimeIdx = mem_layer.fields().indexFromName('DateTime')

        for feat in mem_layer.getFeatures():
            #mem_layer.changeAttributeValue(feat.id(),newdatetimeIdx, 1)
            feat.setAttribute(newdatetimeIdx, 1.0)
            mem_layer.updateFeature(feat)
        mem_layer.commitChanges()

    # Output
        (sink_points, dest_id_points) = self.parameterAsSink(
            parameters,
            self.OUTPOINTS,
            context,
            fields,
            QgsWkbTypes.Point,
            vlayer.sourceCrs()
        )
        features = mem_layer.getFeatures()
        for current, feature in enumerate(features):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break
            # Add a feature in the sink
            sink_points.addFeature(feature, QgsFeatureSink.FastInsert)
            # Update the progress bar
            feedback.setProgress(int(current * total))

When I try to run this, I get a KeyError: '2' message which suggests that the field was not created hence it couldn't write the test value.

  • I'm not sure, if i understand what you want so let me do some remarks to your questions Frist you say you want to write a plugin but your code looks like a processing script. Second: in relational datasets as vector layers are you shouldn't depend of the order of rows, but use id's to connect things. Third: You use a nested for loop to create new features: are you aware that yout output will contain an amount of features equal to the multiplication of the counts of both layers? At least: where in your code does the KeyError raise? Please post the traceback of that error. – Andreas Müller Mar 20 at 10:26
  • Hi @AndreasMüller, sorry my bad, I meant processing script. I will update my question to change that. The nested for loop in the Interpolate section was intentional because the input can be multiple lines, and I want to create points along those lines. – strythe Mar 20 at 22:54
  • The part where I create the geometry works fine. I'm just having difficulty creating new fields to add to the created layer. The error occurs on this line feat.setAttribute(newdatetimeIdx, 1.0) – strythe Mar 20 at 22:56

Your Answer

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

Browse other questions tagged or ask your own question.