4

I have two polygon layers, A and B, that have the same features but totally different attributes. I want to use the attributes from layer A, but I want them to have the more accurate geometry from layer B. How can I copy the geometry from a feature in layer B and paste it onto the attributes of the same feature in layer A?

  • If A and B have totally different attributes then joining using a common field would not be possible. Is there such a common field? If not can you state that geometries of A and B have a topological relationship? Eg centroid of A is allways within polygon of B? Are the polygons isolated rings (eg islands), or do they touch, or even overlay themself? – Detlev Feb 1 '16 at 8:12
  • They are two datasets of administrative boundaries, so the polygons touch but do not overlap. They are the same set of municipalities, so the centroids would line up; in fact, layer B is partly derived from layer A, but has been updated and corrected so the boundaries are more accurate. I think most of the features are actually identical between the two layers, but as I say the attributes are totally different. – Nathan Feb 1 '16 at 13:32
4

I propose two different ways.

  1. Using processing tools: see my answer to another question. It is not difficult to adapt it to your problem, since it is about polygon overlays

  2. A Python script to copy&paste into Python console or to run from Python editor

The script get 2 layers A, B. Replace them with the names of your layers. B is the one providing the additional attributes. The resulting features go to a new memory layer with all attributes from both layers. Then it loops over all features from A searching for features from B, that contain the centroid of the A features. If such a B is found, take the geometry from A, and attributes from A and B , and write it to memory layer AB.

# get layers
a_layer = QgsMapLayerRegistry.instance().mapLayersByName('A')[0]
b_layer = QgsMapLayerRegistry.instance().mapLayersByName('B')[0]

# prepare result layer
ab_layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'AB', 'memory')
ab_fields = a_layer.dataProvider().fields()
ab_fields.extend( b_layer.dataProvider().fields())
ab_prov = ab_layer.dataProvider()
ab_layer.startEditing()
ab_prov.addAttributes(ab_fields)
ab_layer.commitChanges()

ab_feats = []
# replace with a_layer.selectedFeatures() if you want seleted features only
for feat in a_layer.getFeatures():
    # to increase performance filter possible candidates 
    beefs = b_layer.getFeatures(QgsFeatureRequest().setFilterRect(feat.geometry().boundingBox()))
    for beef in beefs:
        # check if centroid of A is in B
        if feat.geometry().centroid().within(beef.geometry()):
            ab_feat = QgsFeature(ab_fields)
            ab_attrib = feat.attributes()
            ab_attrib.extend(beef.attributes())
            ab_feat.setAttributes(ab_attrib)
            ab_feat.setGeometry(beef.geometry())
            ab_feats.append(ab_feat)
            break

# add features to layer
ab_prov.addFeatures(ab_feats)
QgsMapLayerRegistry.instance().addMapLayers([ab_layer])

The script could be used as a template for other topological related feature comparisons as well.

  • What I'm wondering is, isn't the geometry just a list of vertices? Couldn't I just view that list as text somehow, copy it from one file and paste it into the other? Or is that not how the information is stored? – Nathan Feb 1 '16 at 18:58
  • Yes, in most cases polygons are represented as ordered list of points. Or list of lists of points, one list for each ring. Except for some ASCII formats these data structure is saved in binary files, eg as shp file. When you export such file to an ASCII format, as json, gml, or wkt, you could copy and paste these strings. But you have no common attribute, as stated above. So how do you know which geometries replace with which other? – Detlev Feb 1 '16 at 20:00
  • I would recognize them by their names, assuming those appear nearby in the ASCII file. So there's no way to view and edit the vertices as text within the GUI? – Nathan Feb 1 '16 at 21:01
  • 1
    There is a plugin with which you can view and copy the geometry as wkt (well known text). Maybe there is one which allows geometry input as wkt. With minor changes in the code of my script you can take geometry only from one layer and the attributes from the other. – Detlev Feb 1 '16 at 21:20
  • There's one called Plain Geometry Editor that looks like it may work. I just have to figure out how to convert from meters(?) to degrees. – Nathan Feb 1 '16 at 23:15
2

You've got a few options depending on how your data is organized.

You can perform a table join/relate using a common field between your data sets (with the .dbf of shape file A as the table being joined to shape B) or if your .dbf's present data for the exact same shapes in the exact same order you should be able to replace the .dbf from one to another.

If you are replacing the .dbf manually, be sure to save a copy of it in case it doesn't work and if you do perform a table join, you'll want to make your shape file editable so as to remove any redundant columns. You should end up with a shape file B that has the new geometries and the attributes from shape file A.

  • 2
    Replacing the .dbf is a smart idea. But it's not an unique identifier that joins .shp/.shx and .dbf: such an identifier does not exist. It is just the record order, which acts as connector between the different files of a shapefile. Thats the reason for some curious malfunction of shapefiles (Number of records in DBF does not match number of Shapes or attributes and geometry get out of place). – Detlev Feb 1 '16 at 8:07
  • I don't think there's any field that's common between the two datasets, at least not a unique one. Also, I would want to do this only for selected features, if possible, instead of the whole DBF. – Nathan Feb 1 '16 at 13:35
  • @Nathan In that case, you might be better off performing a spatial join. If the geometries are simple polygons, what you could try doing is calculating centroids for your shapefile A (this creates a point at the centre of each polygon that preserves the .dbf values from your polygons) and then performing a spatial join based on location values. If the data you're working with comprises complex polygons or lines/polylines, things might be a bit more complicated but still feasible. If you mention what your data is, we might be able to help more. – Trevor J. Smith Feb 1 '16 at 14:13
  • 1
    Thanks. In my case, layer A is TIGER county subdivision data from the US Census, and layer B is municipal boundaries from the state of Maine GIS office. – Nathan Feb 1 '16 at 18:55
1

Here are three easy methods I am now aware of to do this: 1. (easiest) Using the "Plain Geometry Editor" plugin, display and copy the WKT from a feature in Layer B. Then, using the same plugin, replace the WKT of a feature in Layer A with the copied WKT from Layer B. 2. (in QGIS 3.0 where the above plugin is not available) Using the GetWKT plugin, display and copy the WKT from a feature in Layer B. GetWKT does not have a paste function; so, in Layer A use the Field Calculator to update the field of a selected feature, by calling the function geom_from_wkt('[paste the copied WKT here]'). More details here. 3. Alternatively, use OpenJUMP to directly edit, copy or paste the WKT geometry.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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