4

I have created a table join between two shapefiles which I've named 'OSMM' and 'Mastermap'. I want to copy and paste all features (polygons) without a match from the target layer ('Mastermap') into the parent shapefile ('OSMM'). I can't find any up-to-update code for QGIS 3.6.

Here is my code so far:

#1. loads the SHP files
uri = 'C:/Users/xx/Downloads/OSMM.shp'
vlayer = iface.addVectorLayer(uri,"","ogr")
uri = 'C:/Users/xx/Downloads/Mastermap.shp'
vlayer = iface.addVectorLayer(uri,"","ogr")

#2. Joins "InvoiceNum" from OSMM to Mastermap
layerToJoin = QgsProject().instance().mapLayersByName('OSMM')[0]
target = QgsProject().instance().mapLayersByName('Mastermap')[0]
myJoin = QgsVectorLayerJoinInfo()
myJoin.setJoinFieldName('InvoiceNum')
myJoin.setTargetFieldName('InvoiceNum')
myJoin.setJoinLayerId(layerToJoin.id())
myJoin.setUsingMemoryCache(True)
myJoin.setJoinLayer(layerToJoin)
myJoin.setJoinFieldNamesSubset(['InvoiceNum'])
target.addJoin(myJoin)

#3. Selects NULL features from Mastermap
params = { 'EXPRESSION' : '\"OSMM_InvoiceNum\" is NULL', 'INPUT' : 'C:/Users/xx/Downloads/Mastermap.shp', 'METHOD' : 0 }
processing.run("qgis:selectbyexpression", params)

So how do I perform the PyQGIS version of Ctrl+C on 'Mastermap' and Ctrl+V into 'OSMM'?

Presumably I will then need to use the following code:

#5. Save the changes
OSMM.commitChanges()
4
  • 2
    Try the "Append Features to Layer" plugin (documentation here) and let me know if that works for you using the algorithm's GUI (it has an option to only copy selected values). If that works, I can write a full answer on how to use it from PyQGIS below. Aug 23 '19 at 14:41
  • @GermánCarrillo - That's a neat plugin, thanks for sharing!
    – Joseph
    Aug 23 '19 at 14:58
  • @GermánCarrillo - Yes, thanks for sharing. I have tried it out and it works perfectly!
    – James B
    Aug 23 '19 at 15:22
  • Good, I'll elaborate an answer now Aug 23 '19 at 15:27
3

To copy & paste features from one layer to another layer you have a several options. These are two that I recommended:

OPTION A: Using iface

  1. Select features in source_layer.
  2. Use iface.copySelectionToClipboard(source_layer)
  3. Open the edit session in target_layer.
  4. Use iface.pasteFromClipboard(target_layer)
  5. Save changes to target_layer.

OPTION B: Using 'AppendFeaturesToLayer'

The 'Append Features to Layer' is a plugin based on the QGIS copy&paste's code.

The plugin works even if your source and target layers don't share all fields (just as QGIS copy&paste does!).

How to call it from PyQGIS

After installing the plugin, use a normal processing call depending on your use case:

1. Copy all features from source layer to target layer:

params = {'SOURCE_LAYER': source_layer, 
          'TARGET_LAYER': target_layer,
          'ACTION_ON_DUPLICATE' : 0}  # 0: Just append all features

processing.run("etl_load:appendfeaturestolayer", params)

2. Only copy selected features from source layer to target layer:

params = {'SOURCE_LAYER': QgsProcessingFeatureSourceDefinition(source_layer_path,
                                                               True), 
          'TARGET_LAYER': target_layer,
          'ACTION_ON_DUPLICATE' : 0}  # 0: Just append all features

processing.run("etl_load:appendfeaturestolayer", params)

NOTE: If you're more interested in the details, you can actually read the Python code of the algorithm. The key part is to establish a mapping between source and target layers: See the code.

This is the GUI of the algorithm:

enter image description here

5
  • There seems to be 2 open brackets here but 1 closed creating a syntax error
    – James B
    Aug 27 '19 at 9:32
  • Solved with the following: { 'INPUT' : QgsProcessingFeatureSourceDefinition('C:/Users/xx/Downloads/Mastermap.shp', True)
    – James B
    Aug 27 '19 at 9:49
  • Right, thanks for the feedback. Aug 27 '19 at 21:41
  • From PyQGIS, is that possible to use a temporary layer as source layer? What would be the "source_layer_path" argument then? Sep 29 '20 at 20:39
  • I'd run any other processing algorithm using such layer as input, and afterwards, look at the Processing History to see how Processing expects the input for a temporary layer. Sep 29 '20 at 21:25
0

Finally, here is te code to make a "Copy-Paste".

This PyQgis Script allow to Copy some selected features (in this case,; Farms (Predios)) from an Origin_Layer (Actas Trabajo), and Paste it into a Destination_Layer (Predios Lineas).

The variables was written in Spanish to make it easier to understand to my Spanish Colleges.

You must Change the names of Origen_Layer and Destination_Layer, for yours.

Enjoy... JC

#=========================================================================
# Copia los polígonos de un predio seleccionado desde la capa de "Actas"
# y los pega en la capa de "Predios por línea"
# Escrita por Juan Carlos Jerez
# Openfields.cl"
#=========================================================================

#From Layer...
CapaOrigen = QgsProject.instance().mapLayersByName("Actas Trabajo")[0]

#Destination Layer...
CapaDestino = QgsProject.instance().mapLayersByName("Predios Lineas")[0]

#Dialog Box for input "ID del Predio" to select it...
ID_Predio = QInputDialog.getText(None, 'ID del Predio', 'Input ID del Predio')
Predio = int(ID_Predio [0])   #String to Number

#select the polygons to copy from...
CapaOrigen.selectByExpression('"ID_Predio" = {}'.format(Predio), QgsVectorLayer.SetSelection)

#Store selected polygons in a list....
#to know the numbers of selected polygons...
Pol_seleccionados = CapaOrigen.selectedFeatures()
print("Número de polígonos seleccionados: ",len(Pol_seleccionados))

#Detect if there are selected polygons...
if len(Pol_seleccionados) == 0:
    print ("==================================================")
    print ("NO hay polígonos para el Predio ", Predio,"... Check.")
    print ("               FIN DEL PROCESO")
    print ("==================================================")
else:
    #===========================================================
    #Copy the selected polygons
    iface.actionCopyFeatures().trigger()
    
    #Change and Activate the Destine Layer 
    iface.setActiveLayer(CapaDestino)

    #Put the Destine Layer in Edition
    CapaDestino.startEditing()

    #Paste the selected polygons
    iface.actionPasteFeatures().trigger()

    #Zoom to selected...
    iface.mapCanvas().zoomToSelected()
        
    #Save
    CapaDestino.commitChanges()
    print ("==================================================")
    print ("Capa actualizada con el Predio ", Predio)
    print ("               PROCESO EXITOSO")
    print ("==================================================")

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.