4

I'm trying to measure horizontal and vertical difference between consecutive points in a layer.

In the following link you can download a WinRar file with a shapefile and my model to test in QGIS 3: https://www.mediafire.com/file/hhfmlv4arkd5jx5/KP_test.rar/file

enter image description here

I can do this in the attribute table with field calculator, using $x , $y and: attribute(get_feature_by_id('Layer',@row_number),'x0_kp'), and: attribute(get_feature_by_id('Layer',@row_number),'y0_kp'), then I calculate the differences.

However, when I attempt to do this using the processing modeler the last four columns are NULL. I believe this is because it doesnt really alter the current Layer but it works in the memory and then saves the result in an output layer. Therefore when I call x0_kp and y0_kp they dont actually exist in Layer.

I imagine there are at least two solutions for this issue:

  1. find a different method to retrieve $x and $y from the next feature.
  2. after $x and $y are calculated, output the temporary results in a temp_Layer then call this layer from the Field calculator: attribute(get_feature_by_id('temp_Layer',@row_number),'x0_kp')...

But in reality I have failed to make either happen.


The automated code from the processing modeler is shown below.

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterFeatureSink
import processing


class Pins_trials1(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterVectorLayer('interpretationpoints', 'Interpretation Points', types=[QgsProcessing.TypeVectorPoint], defaultValue=None))
        self.addParameter(QgsProcessingParameterVectorLayer('kppoints', 'KP points', types=[QgsProcessing.TypeVectorPoint], defaultValue=None))
        self.addParameter(QgsProcessingParameterVectorLayer('interpretationlines', 'Interpretation Lines', types=[QgsProcessing.TypeVectorLine], defaultValue=None))
        self.addParameter(QgsProcessingParameterFeatureSink('Test_kp', 'test_KP', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue=None))

    def processAlgorithm(self, parameters, context, model_feedback):
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(4, model_feedback)
        results = {}
        outputs = {}

        # Add X/Y fields to KP
        alg_params = {
            'CRS': QgsCoordinateReferenceSystem('EPSG:4326'),
            'INPUT': parameters['kppoints'],
            'PREFIX': '',
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['AddXyFieldsToKp'] = processing.run('native:addxyfields', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        # Field calculator x1_kp
        alg_params = {
            'FIELD_LENGTH': 15,
            'FIELD_NAME': 'x1_kp',
            'FIELD_PRECISION': 3,
            'FIELD_TYPE': 0,
            'FORMULA': 'attribute(get_feature_by_id(\'Calculated\',@row_number),\'x0_kp\')',
            'INPUT': outputs['AddXyFieldsToKp']['OUTPUT'],
            'NEW_FIELD': True,
            'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
        }
        outputs['FieldCalculatorX1_kp'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)

        feedback.setCurrentStep(2)
        if feedback.isCanceled():
            return {}

        # Field calculator y1_kp
        alg_params = {
            'FIELD_LENGTH': 15,
            'FIELD_NAME': 'y1_kp',
            'FIELD_PRECISION': 3,
            'FIELD_TYPE': 0,
            'FORMULA': 'attribute(get_feature_by_id(\'Calculated\',@row_number),\'y0_kp\')',
            'INPUT': outputs['FieldCalculatorX1_kp']['OUTPUT'],
            'NEW_FIELD': True,
            'OUTPUT': parameters['Test_kp']
        }
        outputs['FieldCalculatorY1_kp'] = processing.run('qgis:fieldcalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
        results['Test_kp'] = outputs['FieldCalculatorY1_kp']['OUTPUT']

        feedback.setCurrentStep(3)
        if feedback.isCanceled():
            return {}

        return results

    def name(self):
        return 'PINS_trials1'

    def displayName(self):
        return 'PINS_trials1'

    def group(self):
        return 'F'

    def groupId(self):
        return 'Fu'

    def createInstance(self):
        return Pins_trials1()
  • Welcome to GIS SE! I don't know how to recreate the model from the Python script. Can you paste in your post the contents of the model file (.model3 extension)? It is an XML file, you can open it with any notepad, and you can save a copy in an "easy to locate" folder from the model builder.. – Gabriel De Luca Dec 16 '19 at 14:59
  • [link] @GabrielDeLuca mediafire.com/file/hhfmlv4arkd5jx5/KP_test.rar/file Hi could you please try this link? thanks – Ame ZL Dec 17 '19 at 14:09
1

To access the input layer in the expression, use the @layer variable.

To access the id of the feature, use the function $id.


You can calculate the difference between the x values of the following id feature and the current feature with the following expression:

attribute(
  get_feature_by_id(
    @layer,
    $id + 1),
  'x') - 
attribute(
  $currentfeature,
  'x') 

Note than the $currentfeature parameter is not necessary, you can use the attribute('x') variant.


Here is the model to test the x difference:

<!DOCTYPE model>
<Option type="Map">
  <Option type="Map" name="children">
    <Option type="Map" name="native:addxyfields_2">
      <Option value="true" type="bool" name="active"/>
      <Option name="alg_config"/>
      <Option value="native:addxyfields" type="QString" name="alg_id"/>
      <Option value="Add X/Y fields to KP" type="QString" name="component_description"/>
      <Option value="351.7406720872316" type="double" name="component_pos_x"/>
      <Option value="504.71744827318093" type="double" name="component_pos_y"/>
      <Option name="dependencies"/>
      <Option value="native:addxyfields_2" type="QString" name="id"/>
      <Option name="outputs"/>
      <Option value="false" type="bool" name="outputs_collapsed"/>
      <Option value="true" type="bool" name="parameters_collapsed"/>
      <Option type="Map" name="params">
        <Option type="List" name="CRS">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="ProjectCrs" type="QString" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="INPUT">
          <Option type="Map">
            <Option value="kppoints" type="QString" name="parameter_name"/>
            <Option value="0" type="int" name="source"/>
          </Option>
        </Option>
        <Option type="List" name="PREFIX">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="" type="QString" name="static_value"/>
          </Option>
        </Option>
      </Option>
    </Option>
    <Option type="Map" name="qgis:fieldcalculator_1">
      <Option value="true" type="bool" name="active"/>
      <Option name="alg_config"/>
      <Option value="qgis:fieldcalculator" type="QString" name="alg_id"/>
      <Option value="Field calculator dx" type="QString" name="component_description"/>
      <Option value="526.7406720872316" type="double" name="component_pos_x"/>
      <Option value="623.7174482731809" type="double" name="component_pos_y"/>
      <Option name="dependencies"/>
      <Option value="qgis:fieldcalculator_1" type="QString" name="id"/>
      <Option type="Map" name="outputs">
        <Option type="Map" name="dx">
          <Option value="qgis:fieldcalculator_1" type="QString" name="child_id"/>
          <Option value="dx" type="QString" name="component_description"/>
          <Option value="716.7406720872316" type="double" name="component_pos_x"/>
          <Option value="698.7174482731809" type="double" name="component_pos_y"/>
          <Option type="invalid" name="default_value"/>
          <Option value="false" type="bool" name="mandatory"/>
          <Option value="dx" type="QString" name="name"/>
          <Option value="OUTPUT" type="QString" name="output_name"/>
        </Option>
      </Option>
      <Option value="true" type="bool" name="outputs_collapsed"/>
      <Option value="true" type="bool" name="parameters_collapsed"/>
      <Option type="Map" name="params">
        <Option type="List" name="FIELD_LENGTH">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="0" type="int" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="FIELD_NAME">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="dx" type="QString" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="FIELD_PRECISION">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="0" type="int" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="FIELD_TYPE">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="0" type="int" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="FORMULA">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="attribute(&#xd;&#xa;  get_feature_by_id(&#xd;&#xa;    @layer,&#xd;&#xa;&#x9;$id + 1),&#xd;&#xa;  'x') - &#xd;&#xa;attribute(&#xd;&#xa;  $currentfeature,&#xd;&#xa;  'x') " type="QString" name="static_value"/>
          </Option>
        </Option>
        <Option type="List" name="INPUT">
          <Option type="Map">
            <Option value="native:addxyfields_2" type="QString" name="child_id"/>
            <Option value="OUTPUT" type="QString" name="output_name"/>
            <Option value="1" type="int" name="source"/>
          </Option>
        </Option>
        <Option type="List" name="NEW_FIELD">
          <Option type="Map">
            <Option value="2" type="int" name="source"/>
            <Option value="true" type="bool" name="static_value"/>
          </Option>
        </Option>
      </Option>
    </Option>
  </Option>
  <Option name="help"/>
  <Option name="modelVariables"/>
  <Option value="" type="QString" name="model_group"/>
  <Option value="difference_against_next_feature_attribute" type="QString" name="model_name"/>
  <Option type="Map" name="parameterDefinitions">
    <Option type="Map" name="kppoints">
      <Option type="List" name="data_types">
        <Option value="0" type="int"/>
      </Option>
      <Option type="invalid" name="default"/>
      <Option value="KP points" type="QString" name="description"/>
      <Option value="0" type="int" name="flags"/>
      <Option name="metadata"/>
      <Option value="kppoints" type="QString" name="name"/>
      <Option value="vector" type="QString" name="parameter_type"/>
    </Option>
    <Option type="Map" name="qgis:fieldcalculator_1:dx">
      <Option value="true" type="bool" name="create_by_default"/>
      <Option value="-1" type="int" name="data_type"/>
      <Option type="invalid" name="default"/>
      <Option value="dx" type="QString" name="description"/>
      <Option value="0" type="int" name="flags"/>
      <Option name="metadata"/>
      <Option value="qgis:fieldcalculator_1:dx" type="QString" name="name"/>
      <Option value="sink" type="QString" name="parameter_type"/>
      <Option value="true" type="bool" name="supports_non_file_outputs"/>
    </Option>
  </Option>
  <Option type="Map" name="parameters">
    <Option type="Map" name="kppoints">
      <Option value="kppoints" type="QString" name="component_description"/>
      <Option value="188" type="double" name="component_pos_x"/>
      <Option value="397" type="double" name="component_pos_y"/>
      <Option value="kppoints" type="QString" name="name"/>
    </Option>
  </Option>
</Option>


1


2

|improve this answer|||||
  • It worked well, instead of ' $currentfeature,'x' ' I used '$x' . thanks! – Ame ZL Dec 19 '19 at 9:04
  • [question] @GabrielDeLuca just so I understand better for future processing, the '@layer' variable, what does it represent? when can I use it? it is not in the field calculator list of functions – Ame ZL Dec 19 '19 at 9:15
  • 1
    When you calculate the X/Y fields, I seen in your model that you use the project CRS, take care than the layer is in the same CRS if you then will use $x for the difference. I think that @layer variable refers to the parent layer and it depends on the environmet where it is called. I found it in the examples for the decode_uri function: i.stack.imgur.com/VvY2q.png . – Gabriel De Luca Dec 19 '19 at 10:44

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.