1

Does anyone know why when I’m editing my polygon (geojson) that the vertices return back to the original spot. I add them through a python script  with QgsProject.instance().addMapLayer(). I start an edit mode, move the vertex, then go move the next vertex and then first vertex moves goes back to its original position.   When I add the layer ( created from the python script) manually from the file explorer, I can edit the shape as expected.   I tried running my code directly in the QGIS python console and the editing works as expected.   So I know it has something to do with running the script from the Processing Toolbox -> Scripts.  

In the image below you can see the red outline of the original polygon when I hover over the shape. So what I did was moved vertex from (1) to (2) (which works) but then when I go to move my next vertex it still uses the old shape and when I move another vertex it will move the original back .

enter image description here

Even with this simple code. I still get the same bug.

enter image description here

from qgis.PyQt.QtCore import (QCoreApplication, QVariant)
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterString,
                       QgsProcessingParameterField,
                       QgsProcessingParameterBoolean,
                       QgsProcessingParameterFolderDestination,
                       QgsProcessingParameterFile,
                       QgsProcessingParameterVectorLayer,
                       QgsProcessingParameterEnum,
                       QgsVectorLayer,
                       QgsProject,
                       QgsVectorDataProvider,
                       QgsDistanceArea,
                       QgsField,
                       QgsUnitTypes,
                       QgsVectorFileWriter)
from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterFile


class CheckGcpPoints(QgsProcessingAlgorithm):
    
    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFile('input_csv', 'Properties CSV', behavior=QgsProcessingParameterFile.File))

        #self.addParameter(QgsProcessingParameterBoolean('thermal_parameter', 'Thermal', defaultValue=False))
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
    
    def processAlgorithm(self, parameters, context, model_feedback):
        registry = QgsProject.instance()
        
        # Define qgis instance

        # # Create Property layer
        property_layer = QgsVectorLayer(parameters['input_csv'],'Properties')
        registry.addMapLayer(property_layer)
        
        results = {}
        return ()

    def name(self):
        return 'PropertyEstimates2'

    def displayName(self):
        return 'Property Estimates2'

    def group(self):
        return 'SITE scripts'

    def groupId(self):
        return 'SITE scripts'

    def createInstance(self):
        return CheckGcpPoints()

Another case with Points. You can see that I moved the point to the right, but when I try to move it again the point is still in the original place. I have to hover with my mouse to see the red original vertex as if the point didnt really move. enter image description here

0

1 Answer 1

3

I can see a few potential problems with your script. Firstly, you have not passed a provider argument to your vector layer constructor. Secondly, your processAlgorithm() method is returning an empty tuple instead of a dictionary. And finally, an important piece of knowledge is that processing algorithms by default, are run in a background thread. Therefore, doing non thread-safe operations in the processAlgorithm() method (such as adding layers to the project) will often result in (at worst) crashes or at least unpredictable behaviour. To avoid this problem, it is necessary to re-implement the flags() method and return the QgsProcessingAlgorithm.FlagNoThreading flag.

The simplified algorithm below works for me and I am able to successfully edit vertices of the loaded layer.

from qgis.core import (QgsProcessingAlgorithm,
                    QgsProcessingParameterFile,
                    QgsProject,
                    QgsVectorLayer)

class CheckGcpPoints(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFile('input_geojson', 'Properties GEOJSON', behavior=QgsProcessingParameterFile.File, extension='geojson'))

    def processAlgorithm(self, parameters, context, model_feedback):
        project = QgsProject.instance()
        property_layer = QgsVectorLayer(parameters['input_geojson'],'Properties', 'ogr')
        project.addMapLayer(property_layer)
        
        return {}

    def flags(self):
        return QgsProcessingAlgorithm.FlagNoThreading

    def name(self):
        return 'PropertyEstimates2'

    def displayName(self):
        return 'Property Estimates2'

    def group(self):
        return 'SITE scripts'

    def groupId(self):
        return 'SITE scripts'

    def createInstance(self):
        return CheckGcpPoints()

I strongly encourage you to thoroughly read the documentation about Writing new Processing algorithms as Python scripts, especially the section on Flags.

P.S. there is one other slightly confusing element to your question in that you state you are trying to load a geojson, but your script makes several references to csv. This is confusing because delimited text layers cannot be edited directly in QGIS. Therefore, I have referenced only geojson in my answer and restricted the input file extension to 'geojson'.

Further Explanation

Of course, it doesn't make much sense to write a processing script just to load a layer. If you are doing further processing, you can just define an output parameter such as a QgsProcessingParameterFeatureSink for your algorithm, and pass it to the 'OUTPUT' parameter of the processing.run() call. This way, any output layer, either temporary or file, will be handled/loaded safely, so you don't need to return the no threading flag. For example, here we run Fix Geometries on the input layer, and output the result to the feature sink.

from qgis.core import (QgsProcessingAlgorithm,
                    QgsProcessingParameterFile,
                    QgsProcessingParameterFeatureSink,
                    QgsProject,
                    QgsVectorLayer)

import processing

class CheckGcpPoints(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFile('input_geojson', 'Properties GEOJSON', behavior=QgsProcessingParameterFile.File, extension='geojson'))
        self.addParameter(QgsProcessingParameterFeatureSink('output', 'Result layer'))

    def processAlgorithm(self, parameters, context, model_feedback):
        params = {'INPUT': parameters['input_geojson'],
                'OUTPUT': parameters['output']}
        
        fixed = processing.run("native:fixgeometries", params, context=context, feedback=model_feedback, is_child_algorithm=True)
                
        return {'RESULT': fixed['OUTPUT']}

    def name(self):
        return 'PropertyEstimates2'

    def displayName(self):
        return 'Property Estimates2'

    def group(self):
        return 'SITE scripts'

    def groupId(self):
        return 'SITE scripts'

    def createInstance(self):
        return CheckGcpPoints()
4
  • @Polygeo Wow thanks for the thorough answer. This works for me. I came from arcpy and now to qgis. Still learning the structure of pyqgis. and yeah sorry about the confusing parameters. I just didn't clean up the code, I trimmed it down just to show this issue. It's a fairly long script that runs multiple geoprocessing tools. That must explain why my QGIS crashes every so often running my scripts.
    – AdamGIS
    Nov 10, 2022 at 15:21
  • is there any downside of using QgsProcessingAlgorithm.FlagNoThreading? My code works with just adding that simple flags() method.
    – AdamGIS
    Nov 10, 2022 at 16:16
  • @AdamGIS, no worries. I suppose the downside of no threading is loss of performance/ responsiveness with long running processes. So if you have multiple processing steps, just define a proper output parameter, use temporary outputs for the intermediate steps and point the final result at the output parameter. You just shouldn't interact with project or gui from a background thread e.g. things like adding layers to project, styling layers etc.
    – Ben W
    Nov 12, 2022 at 13:45
  • You may also want to check postProcessAlgorithm() api.qgis.org/api/… There is also the api.qgis.org/api/… class for things like styling output layers which get loaded on completion.
    – Ben W
    Nov 12, 2022 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.