[GIS] Copying and pasting features using PyQGIS

copyfeaturespastepyqgisqgis-3

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

Best Answer

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