3

I need to keep several polygon layers in common. So if I move a vertices on one layer the one or two layers sitting under (or in common) would also change that vert.

I hope that makes sense. I feel it should be some sort of linked group or commonality setting.

2
  • Could you elaborate as to why you need these layers separate, as opposed to having multiple attributes in a single layer?
    – jcarlson
    Mar 21, 2018 at 23:10
  • Good question, thanks for the response. The company I work for developed their own GIS for our land management purposes. We have two layers in particular that we keep in common. At this point we basically keep them separated because we deliver these layers separately to our client. So we need to keep those two exactly the same in order to maintain acres.
    – Kris
    Mar 22, 2018 at 14:02

3 Answers 3

3

One way to do this would be to use PostGIS as the back end database. You can then add a trigger function on table A to copy changes to the geometry column to the geometry column of table B. I've not tested the below, but it should get you started. It assumes that there is an id column which is common to both tables..

CREATE or replace FUNCTION fn_update_B() RETURNS trigger AS
  $BODY$
BEGIN
  UPDATE B
  SET geom = NEW.geom
  WHERE id = NEW.id;
  RETURN NEW;
END
$BODY$
LANGUAGE plpgsql;

CREATE TRIGGER tr_update_B
AFTER UPDATE 
ON A
FOR EACH ROW
EXECUTE PROCEDURE fn_update_B();
1
  • Hey! Thanks very much I'm going to give that a try. It seems like something that should exist but i can see why it doesn't. That's what the attributes are for.
    – Kris
    Mar 22, 2018 at 14:22
1

Further to my previous answer, you can use a python macro. The following has been tested in QGIS 2.18.

Go to project > Project Properties > Macros and paste the code below into the openProject() macro (remember to remove the pass statement). Change "layer1" and "layer2" to the names of your layers in the layers panel and, if needs be, change f.attribute("id") to the attribute that is common between the features in both layers).

Your macros tab should look like the one in the image below.

Next go to Settings > Options > General and enable macros at the bottom.

When you reopen the project, any changes you make to the geometry of layer2 will be automatically made to layer1, provided they have a common "id" field.

from qgis.core import QgsMapLayerRegistry, QgsFeatureRequest, QgsExpression

def updateChildLayer(parentLyrId, geoMap):
    childLyr = QgsMapLayerRegistry.instance().mapLayersByName('layer1')[0]

    for parentFeatureId in geoMap:
        for f in parentLyr.getFeatures(QgsFeatureRequest(parentFeatureId)):
            fid = f.attribute('id')

        for f in childLyr.getFeatures():
            if f.attribute('id') == fid:
                childLyr.dataProvider().changeGeometryValues({ f.id() : geoMap[parentFeatureId] })
                childLyr.updateFeature(f)

        childLyr.triggerRepaint()


parentLyr = QgsMapLayerRegistry.instance().mapLayersByName('layer2')[0]
parentLyr.committedGeometriesChanges.connect(updateChildLayer)

enter image description here

EDIT: If you don't have a matching id field, you can use the below code instead, but it will not be as quick to load up the project - especially if you have a large number of polygons...

    from qgis.core import QgsMapLayerRegistry

    childLyr = QgsMapLayerRegistry.instance().mapLayersByName('layer_1')[0]
    parentLyr = QgsMapLayerRegistry.instance().mapLayersByName('layer_2')[0]

    #dictionary to hold ids of features with matching geometries
    idDict = {}
    for cf in childLyr.getFeatures():
        for pf in parentLyr.getFeatures():
            if cf.geometry().equals(pf.geometry()):
                idDict[pf.id()] = cf.id()

    def updateChildLayer(parentLyrId, geoMap):

        #check the dictionary for matching parent id and retrieve the child id
        for parentFeatureId in geoMap:
            for id in idDict:
                if parentFeatureId == id:

                    #make the geometry change to the child
                    childLyr.dataProvider().changeGeometryValues({ idDict[id] : geoMap[parentFeatureId] })

        childLyr.triggerRepaint()

    parentLyr.committedGeometriesChanges.connect(updateChildLayer)
2
  • Firefly, thanks very much this is exactly what i was looking for, and its working perfectly. Now it created a new question for me though (if you don't have time to answer, no worries). The common ID field, is that the only way to link the shapes? I know there are tools which can select based on exact geometry. Not sure about python scripts but would it be possible to add a select by common geometry instead of common ID?
    – Kris
    Mar 23, 2018 at 16:18
  • 1
    I've updated my answer to include code for matching geometries. Be careful with this though, run a topology check before using it to make sure all your polys match in the first instance Mar 24, 2018 at 12:16
1

For somewhat similar situations that I've had, I use the Duplicate feature. I don't know if it will apply to your situation, but when I have multiple deliverables that use the same polygon placement, it's an easy enough fix.

This procedure assumes that all relevant attributes are already part of the same layer. In your Layers panel, right-click your intended layer and select Duplicate.

duplicate layer command

You can then rename and style the layers separately for their respective end products, but the underlying data will remain the same. For example, here is a single layer of Milwaukee demographic data, being duplicated and styled on different attributes.

two maps

The real benefit of using this method, and which is most applicable to your question, is that if I go in and edit the underlying data and move a vertex on one, both are updated. I don't want to actually change my existing dataset, so for an example, I'm going to create a new island in Milwaukee's harbor.

new island

Because both layers in my workspace have the same underlying data, an edit to one is necessarily an edit to the other. Since they're separate in my Layers panel, though, I don't have to reset my symbology every time I want to show the other attribute; I just turn the duplicates on or off.

In other projects I've worked on, I've had up to a dozen outputs that needed to be perfectly in sync, and making a bunch of duplicates of my main dataset saved me considerable time.

2
  • Oh man I have unintentionally used the duplicate layer function before without understanding how it worked. Thanks for your help you really went above and beyond! I appreciate the time. I think that should work for my purposes now i just need to experiment with it a bit. I am guessing this will also maintain the attribute information? Is there any way to populate the duplicated layer with unique attribute information? I could save it as a new layer after i was done editing I suppose then populated it then.
    – Kris
    Mar 22, 2018 at 17:46
  • Since it's just the same file, it'll have an identical attribute table. There won't be a way to create a unique field without first splitting it into separate files, which puts you back in the same boat of having non-synchronized layers. In that situation, the other suggestion of a PostGIS backend would probably be better.
    – jcarlson
    Mar 22, 2018 at 18:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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