1 votos

Modelador gráfico de QGIS 3: Crear campo calculado

Quiero automatizar un flujo de trabajo que incluya la creación de un nuevo campo en una capa de puntos vectoriales. Quiero que el nuevo campo contenga la distancia entre cada punto y el anterior, por lo que la expresión sería

distance(($geometry),geometry(get_feature_by_id( @layer_name, $id-1)))

¿Es posible hacer esto como parte de un flujo de trabajo automatizado?

2voto

Lakshman Prasad Puntos 156

Como sugirió MrXsquared en su comentario, podría utilizar PyQGIS para crear una herramienta de procesamiento que puede utilizar en su modelo.

Ejemplo de caja de herramientas

from qgis.PyQt.QtCore import QCoreApplication

from qgis.core import (
    QgsField,
    QgsFeatureRequest,
    QgsProcessingParameterField,
    QgsProcessingParameterVectorLayer,
    QgsProcessingParameterString,
    QgsProcessingAlgorithm,
)

from PyQt5.QtCore import QVariant

def calculate_distance(layer, sorting_field, field_name="DISTANCE"): 
    """ Calculates distance between points along a path """

    layer.startEditing()

    try:

        layer_provider = layer.dataProvider()

        if field_name not in layer.fields().names():
            layer_provider.addAttributes(
                [QgsField(field_name, QVariant.Double)]
            )
            layer.updateFields()

        fields = layer.fields().names()
        field_index = fields.index(field_name)

        sort_request = QgsFeatureRequest().addOrderBy(
            sorting_field, 
            True,   # sorted by asc
            False,  # None value at the end
        )
        feature_iterator = layer.getFeatures(sort_request)

        changes = {}

        last = None
        for current in feature_iterator:

            distance = 0
            if last:
                distance = last.geometry().distance(current.geometry())

            changes[current.id()] = {
                field_index: distance
            }

            last = current

        layer_provider.changeAttributeValues(changes)
        layer.commitChanges()

    except Exception:

        layer.rollBack()
        raise Exception("Script failed")

class CalculateDistance(QgsProcessingAlgorithm):

    LAYER = "LAYER"
    SORTING_FIELD = "SORTING_FIELD"
    FIELD_NAME = "FIELD_NAME"

    def __init__(self):
        super().__init__()

    def tr(self, string):
        return QCoreApplication.translate("Processing", string)

    def name(self):
        return "CalculateDistance"

    def displayName(self):
        return "Calculates distance between points along a path"

    def group(self):
        return "Example Scripts"

    def groupId(self):
        return "playground"

    def createInstance(self):
        return type(self)()

    def initAlgorithm(self, config=None):

        self.addParameter(
            QgsProcessingParameterVectorLayer(
                self.LAYER, 
                self.tr("Layer"),
                optional=False
            )
        )
        self.addParameter(
            QgsProcessingParameterField(
                self.SORTING_FIELD,
                self.tr("Sorting Field"),
                parentLayerParameterName=self.LAYER,
                type=QgsProcessingParameterField.Any,
                optional=False
            )
        )
        self.addParameter(
            QgsProcessingParameterString(
                self.FIELD_NAME,
                self.tr("Field Name"),
                defaultValue="DISTANCE",
                optional=False
            )
        )

    def processAlgorithm(self, parameters, context, feedback):

        calculate_distance(
            self.parameterAsVectorLayer(parameters, self.LAYER, context), 
            self.parameterAsString(parameters, self.SORTING_FIELD, context),
            self.parameterAsString(parameters, self.FIELD_NAME, context)
        )

        return {}

Resultado

¿Cómo añadir el script a la caja de herramientas de procesamiento?

  1. Abrir QGIS
  2. En su caja de herramientas de procesamiento, haga clic en el icono de Python
  3. Entonces Create New Script...

  1. Escriba su script, o copie/pegue el ejemplo anterior y guárdelo
  2. Por último, encontrará el script en su caja de herramientas de Processing en Scripts :

Ejemplo de script con PyQGIS

Aquí el mismo script de ejemplo pero independiente y no como herramienta de procesamiento:

from qgis.core import QgsField, QgsProject, QgsFeatureRequest
from PyQt5.QtCore import QVariant

layer_name = "RR_POINT_10K"
sorting_field = "OBJECTID"

field_name = "DISTANCE"

def calculate_distance(layer, sorting_field, field_name="DISTANCE"): 
    """ Calculates distance between points along a path """

    layer.startEditing()

    try:

        layer_provider = layer.dataProvider()

        if field_name not in layer.fields().names():
            layer_provider.addAttributes(
                [QgsField(field_name, QVariant.Double)]
            )
            layer.updateFields()

        fields = layer.fields().names()
        field_index = fields.index(field_name)

        sort_request = QgsFeatureRequest().addOrderBy(
            sorting_field, 
            True,   # sorted by asc
            False,  # None value at the end
        )
        feature_iterator = layer.getFeatures(sort_request)

        changes = {}

        last = None
        for current in feature_iterator:

            distance = 0
            if last:
                distance = last.geometry().distance(current.geometry())

            changes[current.id()] = {
                field_index: distance
            }

            last = current

        layer_provider.changeAttributeValues(changes)
        layer.commitChanges()

    except Exception:

        layer.rollBack()
        raise Exception("Script failed")

if __name__ == "__main__":

    layers = QgsProject.instance().mapLayersByName(layer_name)

    if not layers:
        raise Exception(f"Layer {layer_name} does not exist")

    calculate_distance(layers[0], sorting_field, field_name)

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X