5

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()
Taras
  • 32,823
  • 4
  • 66
  • 137
James B
  • 2,139
  • 14
  • 30

2 Answers2

5

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

OPTION A: Using iface object

  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.

Note that 1, 3 and 5 could be done programmatically as well, which is well covered by the PyQGIS Cookbook.

OPTION B: Using 'AppendFeaturesToLayer' plugin

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

Germán Carrillo
  • 36,307
  • 5
  • 123
  • 178
2

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 ("==================================================")