Changes to a newly created memory layer are affecting the original layer from which it was copied

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Changes to a newly created memory layer are affecting the original layer from which it was copied

Tom Chadwin
Sorry about the convoluted subject line. qgis2web is built from @volaya's qgis-ol3 plugin (thanks as ever, Victor). That exported layers by making temporary memory copies of them, in order to manipulate them pre-export without affecting the original layer and corrupting the user's data. This worked perfectly.

However, in building the 2.5d export functionality, something has gone wrong, and I've introduced a very nasty new bug. Somehow, changes I make to the memory layer (the copy of the original) are being written back to the original user's layer. What have I done wrong?

The function which creates the memory copy layer is:

def writeTmpLayer(layer, popup):
    usedFields = getUsedFields(layer)
    if popup != ALL_ATTRIBUTES:
        uri = TYPE_MAP[layer.wkbType()]
        crs = layer.crs()
        if crs.isValid():
            uri += '?crs=' + crs.authid()
        if popup != NO_POPUP:
            usedFields.append(popup)
        for field in usedFields:
            fieldType = layer.pendingFields().field(field).type()
            fieldType = "double" if (fieldType == QVariant.Double or
                                     fieldType == QVariant.Int) else (
                                        "string")
            uri += '&field=' + unicode(field) + ":" + fieldType
        newlayer = QgsVectorLayer(uri, layer.name(), 'memory')
        writer = newlayer.dataProvider()
        outFeat = QgsFeature()
        for feature in layer.getFeatures():
            outFeat.setGeometry(feature.geometry())
            attrs = [feature[f] for f in usedFields]
            if attrs:
                outFeat.setAttributes(attrs)
            writer.addFeatures([outFeat])
        layer = newlayer
    return layer

The snippet which calls the function above and is meant to add the fields to the memory layer is:

if (layer.type() == layer.VectorLayer)
    cleanLayer = writeTmpLayer(layer, popup)
    if is25d(layer, canvas):
        provider = cleanLayer.dataProvider()
        provider.addAttributes([QgsField("height", QVariant.Double),
                                QgsField("wallColor", QVariant.String),
                                QgsField("roofColor",
                                         QVariant.String)])
        cleanLayer.updateFields()

When the plugin runs, the new fields height, wallColor, and roofColor are appearing in the original user's layer. Each time the plugin is run, additional copies of those fields are created. Hence, a very nasty bug.

How is this affecting the original layer, rather than the newly created cleanLayer?

The actual code is here: https://github.com/tomchadwin/qgis2web/blob/master/utils.py#L63
Reply | Threaded
Open this post in threaded view
|

Re: Changes to a newly created memory layer are affecting the original layer from which it was copied

Nyall Dawson


On 16 Mar 2016 20:56, "Tom Chadwin" <[hidden email]> wrote:
>

> def writeTmpLayer(layer, popup):
>     usedFields = getUsedFields(layer)
>     if popup != ALL_ATTRIBUTES:
>         uri = TYPE_MAP[layer.wkbType()]
>         crs = layer.crs()
>         if crs.isValid():
>             uri += '?crs=' + crs.authid()
>         if popup != NO_POPUP:
>             usedFields.append(popup)
>         for field in usedFields:
>             fieldType = layer.pendingFields().field(field).type()
>             fieldType = "double" if (fieldType == QVariant.Double or
>                                      fieldType == QVariant.Int) else (
>                                         "string")
>             uri += '&field=' + unicode(field) + ":" + fieldType
>         newlayer = QgsVectorLayer(uri, layer.name(), 'memory')
>         writer = newlayer.dataProvider()
>         outFeat = QgsFeature()
>         for feature in layer.getFeatures():
>             outFeat.setGeometry(feature.geometry())
>             attrs = [feature[f] for f in usedFields]
>             if attrs:
>                 outFeat.setAttributes(attrs)
>             writer.addFeatures([outFeat])
>         layer = newlayer
>     return layer
>
> The snippet which calls the function above and is meant to add the fields to
> the memory layer is:
>
> if (layer.type() == layer.VectorLayer)
>     cleanLayer = writeTmpLayer(layer, popup)
>     if is25d(layer, canvas):
>         provider = cleanLayer.dataProvider()
>         provider.addAttributes([QgsField("height", QVariant.Double),
>                                 QgsField("wallColor", QVariant.String),
>                                 QgsField("roofColor",
>                                          QVariant.String)])
>         cleanLayer.updateFields()

>

If popup == ALL_ATTRIBUTES then your writeTmpLayer function is returning the original layer.

Nyall


_______________________________________________
Qgis-developer mailing list
[hidden email]
List info: http://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: http://lists.osgeo.org/mailman/listinfo/qgis-developer
Reply | Threaded
Open this post in threaded view
|

Re: Changes to a newly created memory layer are affecting the original layer from which it was copied

Tom Chadwin
Ah, I see it! Thank you so much. And apologies for not spotting that one myself. I blame Python and its semantic white space... Fix will follow as soon as I can.
Reply | Threaded
Open this post in threaded view
|

Re: Changes to a newly created memory layer are affecting the original layer from which it was copied

Tom Chadwin
Last follow-up on this, I hope: is there an accepted method for cloning/duplicating a vector layer? Examples online seem to involve manually creating a new layer and then iterating over the source layer's features to add to the new one. Anything simpler?
Reply | Threaded
Open this post in threaded view
|

Re: Changes to a newly created memory layer are affecting the original layer from which it was copied

PIERRE Sylvain
Select records
Copy
Paste as memory layer
?

Cheers

Sylvain


-----Message d'origine-----
De : Qgis-developer [mailto:[hidden email]] De la part de Tom Chadwin
Envoyé : vendredi 18 mars 2016 11:32
À : [hidden email]
Objet : Re: [Qgis-developer] Changes to a newly created memory layer are affecting the original layer from which it was copied

Last follow-up on this, I hope: is there an accepted method for cloning/duplicating a vector layer? Examples online seem to involve manually creating a new layer and then iterating over the source layer's features to add to the new one. Anything simpler?



--
View this message in context: http://osgeo-org.1560.x6.nabble.com/Changes-to-a-newly-created-memory-layer-are-affecting-the-original-layer-from-which-it-was-copied-tp5256690p5257138.html
Sent from the Quantum GIS - Developer mailing list archive at Nabble.com.
_______________________________________________
Qgis-developer mailing list
[hidden email]
List info: http://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: http://lists.osgeo.org/mailman/listinfo/qgis-developer
_______________________________________________
Qgis-developer mailing list
[hidden email]
List info: http://lists.osgeo.org/mailman/listinfo/qgis-developer
Unsubscribe: http://lists.osgeo.org/mailman/listinfo/qgis-developer
Reply | Threaded
Open this post in threaded view
|

Re: Changes to a newly created memory layer are affecting the original layer from which it was copied

Tom Chadwin
@Sylvain

Apologies - I meant how best to do it in Python.

Thanks

Tom