4

I am new in PyQGIS and am having trouble programming how to copy features between layers.

Goal: from a robust layer (with more fields) copy its features to a 'simple' version layer.

from qgis.core import *

mapLayer = QgsProject.instance().mapLayersByName("MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g',tables=avenida_rua|layername=avenida_rua")[0]

# selecionar estrutura dos fields name
# criar um feature
# clonar os 
if (mapLayer.isValid()):
    layer = QgsVectorLayer("D:\\workstation\\qgis\\temp\\fid_62.shp", 'lay', 'ogr')

    if(layer.isValid()) :
        print('init')
        features = []
        for feature in layer.getFeatures():
            features.append(feature)

        mapLayer.startEditing()
        dataP = mapLayer.dataProvider()
        dataP.addFeatures(features)
        mapLayer.commitChanges()

Mean while I get this error:

exec(open('C:/Users/LUISMH~1/AppData/Local/Temp/tmp2vbxv1cy.py'.encode('utf-8')).read())
Traceback (most recent call last):
  File "D:\OSGeo4W\apps\Python37\lib\code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
  File "<string>", line 3, in <module>
IndexError: list index out of range

I don't know if I would have to create a feature for the destination layer. And pass on the attributes features from the layer to destination feature. if so how?

main layer

destination layer

1
2

So I think you need to drop the fields that you don't need from the new features you are creating in order for it to 'fit' into your simplified dataset. We can do this by finding the indexes of the fields that you would like to keep. As per this answer: https://gis.stackexchange.com/a/266431/91833:

field_ids = []
# Fieldnames to keep
fieldnames = set(['fid','nome','max_speed','codego_nacional','place','highway','super_sug_id','oneway','tool','admin_level'])
for field in layer.fields():
    if field.name() not in fieldnames:
      field_ids.append(layer.fields().indexFromName(field.name()))

And then creating a new vectorLayer in memory with:

L = QgsVectorLayer("Linestring?crs=EPSG:4326","foo","memory")

Append the original layers features to the new memory layer, and delete the attribues you don't want:

for feature in layer.getFeatures():
            features.append(feature)

L.startEditing()
L_data = L.dataProvider()
L_data.addFeatures(features)
L_data.deleteAttribues(field_ids)
L_data.updateFields()

simplified_features = [f for L.getFeatures()]

mapLayer.startEditing()
dataP = mapLayer.dataProvider()
dataP.addFeatures(simplified_features)
mapLayer.commitChanges()

I have not tested this but your code should look like this:

from qgis.core import *

mapLayer = QgsProject.instance().mapLayersByName("MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g',tables=avenida_rua|layername=avenida_rua")[0]

# selecionar estrutura dos fields name
# criar um feature
# clonar os 
if (mapLayer.isValid()):
    layer = QgsVectorLayer("D:\\workstation\\qgis\\temp\\fid_62.shp", 'lay', 'ogr')

    if(layer.isValid()) :

        field_ids = []

        fieldnames = set(['fid','nome','max_speed','codego_nacional','place','highway','super_sug_id','oneway','tool','admin_level'])

        for field in layer.fields():
            if field.name() not in fieldnames:
                field_ids.append(layer.fieldNameIndex(field.name()))

        L = QgsVectorLayer("Linestring?crs=EPSG:4326","foo","memory")

        for feature in layer.getFeatures():
                    features.append(feature)

        L.startEditing()
        L_data = L.dataProvider()
        L_data.addFeatures(features)
        L_data.deleteAttribues(field_ids)
        L_data.updateFields()

        simplified_features = [f for f in L.getFeatures()]

        mapLayer.startEditing()
        dataP = mapLayer.dataProvider()
        dataP.addFeatures(simplified_features)
        mapLayer.commitChanges()
2
  • Unfortunately not at a machine I can test this on. – Michael Cohen Feb 13 '20 at 12:14
  • Qgis crashes on deleteAttributes – Luis Mhula Junior Feb 14 '20 at 23:49
0

from qgis.core import *

dest_layer = QgsProject.instance().mapLayersByName("MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g' avenida_rua")[0]

if(dest_layer.isValid()):
    lcl_layer = QgsVectorLayer("D:\\workstation\\qgis\\temp\\fid_62.shp", 'lcl_layer', 'ogr')

    if(lcl_layer.isValid()):

        dest_features = []

        for feature in lcl_layer.getFeatures():
            temp_feature = QgsFeature()
            temp_feature.setFields(dest_layer.fields())

            temp_feature['fid'] = feature['fid']
            temp_feature['self_id'] = feature['self_id']
            temp_feature['nome'] = feature['name']
            temp_feature['max_speed'] = feature['maxspeed']
            temp_feature['codego_nacional'] = feature['codego_nac']
            temp_feature['place'] = feature['place']
            temp_feature['highway'] = feature['highway']
            temp_feature['super_sug_id'] = feature['super_sug_']
            temp_feature['oneway'] = feature['oneway']
            #temp_feature['tool'] = feature['tool']
            temp_feature['admin_level'] = -1
            temp_feature.setGeometry(feature.geometry())

            dest_features.append(temp_feature)

        dest_layer.startEditing()
        dataP = dest_layer.dataProvider()
        print('adding features to data provider')
        dataP.addFeatures(dest_features)
        dest_layer.commitChanges()
        print('done!')

Based in your code and some tweeks, i achieve the goal by as it follows on code. Though using many layers it dosent copy all the features, going through debug

Many thanks

0

Python is complaining about your line 3:

mapLayer = QgsProject.instance().mapLayersByName("MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g',tables=avenida_rua|layername=avenida_rua")[0]

Are you shure that your layer name is "MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g',tables=avenida_rua|layername=avenida_rua"??? It looks like that is a uri to a layer in a DB, not a name...

QgsProject.instance().mapLayersByName('layer name') will return a list that contains all layers with the same 'layer name'. Try to change "MySQL:forexeasy,host=localhost,port=3306 authcfg='z4s291g',tables=avenida_rua|layername=avenida_rua" to "avenida_rua".

1
  • Yes its source name. I got to correct. Might have done some info in some process. – Luis Mhula Junior Feb 16 '20 at 5:27

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