5

I am using QGIS.

I have two exports of vector data created some 6 months apart.

How do I find any new objects added in the 6 months, and any attribute changes in the original objects?

An asset_id field exists in both tables as a unique identifier, and will carry through both tables. I can use the "Difference" tool to get geometry changes but can't get the attribute table changes too.

0

3 Answers 3

9

In QGIS, you have a number of options:

  1. From the Processing Toolbox use Orfeo's MultivariateAlterationDetector (just type 'change' into the search box to find it) - see the documentation here.
  2. From the Processing Toolbox use SAGA's Change Detection tool (find it in the same way as above).
  3. Grass has an r.change.info module but you may not be able to see that in a standard QGIS install (search this site on how to extend GRASS tools - I recall there's a number of posts about it).
  4. Roll-your-own-solution. All the ArcGIS Combine tool is doing is ascribing a new code that represents the combination of the codes in the 'before' and 'after' rasters. This is blindingly simple to replicate. Let's say your codes are integers running from 1-99. Simply multiply one set by a big value (say 100) and then add the two rasters in the raster calculator. An area that has a code of (say) 1 and is unchanged will get an output code of 101 and so on. Thus, any codes that are 'palindromic' are unchanged and any that are not are changed and encapsulate the 'before' and 'after' states in the code (choose a multiplier that is big enough to achieve this obviously - so in our example a multiplier of 10 is insufficient but 100 or even 1000 is fine). So you can quickly style your map for all unchanged areas (by giving all palendromic numbers the same style) and highlight just the changes.

Rasters are better suited for change detection so you are best advised to convert the vectors to rasters and follow the above options. If you MUST use vectors for some reason, then simply intersect the vectors (ensuring you keep the relevant code fields). You can then label your polygons as to whether the 'before' and 'after' codes match. Using vectors is likely to result in slivers, so a style that has no outline to the polygons would be best to reduce the noise on your map (it will look a lot like the out put of the raster above, so...). Note, if your vectors cover different areas, you may want to look at the Union tool - in either case go Vector->Geoprocessing Tools

0
4

For QGIS there is the tool Detect Dataset Changes available (introduced with QGIS 3.12):

https://www.qgis.org/en/site/forusers/visualchangelog312/index.html#feature-add-new-algorithm-detect-dataset-changes

https://docs.qgis.org/testing/en/docs/user_manual/processing_algs/qgis/vectorgeneral.html#detect-dataset-changes-312

Using this tool you are able to select your two vector layers as input (Original layer and Revised layer) and select the fields which you want to compare (Attributes consider to match).

The output of this tool are three layers as shown on the following screenshot (unchanged, added and deleted features).

enter image description here

1
  • As of QGis 3.34.3 the tool outputs wrong results when both attributes are NULL (considers the two records to be different).
    – Nicu Tofan
    Commented Mar 17 at 8:35
1

The following script might help you to detect changes between two layers having the same structure.

The algorithm works as follows:

  • get a reference to layers to be compared
  • write their common unique identifiers to a dict for faster access
  • check if the new version has some identifiers not being in the set of old identifiers
  • compare the other features having the same unique identifiers first by geometry, and if geometry is equal then on a field by field basis
  • select all detected features on layer new

To write the selected features to a new layer "save layer as" with "selected only" option.

The script can be extended to report the differences found in more detail, eg. report wether geometry or attribute differ, and which attributes.

To run the script replace old_layer_name and new_layer_name in line 2-3, copy the code and paste it into Python console.

# get layers
old = QgsMapLayerRegistry.instance().mapLayersByName('old_layer_name')[0]
new = QgsMapLayerRegistry.instance().mapLayersByName('new_layer_name')[0]

# get the key field and feature id for faster access
old_feats = {feat['asset_id']:feat.id() for feat in old.getFeatures()}
new_feats = {feat['asset_id']:feat.id() for feat in new.getFeatures()}

# compare new fid with old fid; such fid being in the new set 
# but not in the old represent new features
old_fid = set(old_feats.keys())
new_fid = set(new_feats.keys())
added_fid = new_fid.difference(old_fid)
# features added since old version
added_ids = [new_feats[fid] for fid in added_fid]
# features being in old AND new set
exist_fid = new_fid.difference(added_fid)

# get count of fields to compare
field_count = len(new.dataProvider().fields())
# list for changed features
changed_ids = []

# join the remainders by fid and compare them field by field
for fid in exist_fid:
    old.setSelectedFeatures([old_feats[fid]])
    new.setSelectedFeatures([new_feats[fid]])
    old_feat = old.selectedFeatures()[0]
    new_feat = new.selectedFeatures()[0]

    # compare geometry and fields
    if old_feat.geometry().equals(new_feat.geometry()):
        for fi in range(field_count):
            if old_feat[fi] != new_feat[fi]:
                changed_ids.append(new_feats[fid])
                break
    else:
        changed_ids.append(new_feats[fid])

# combine list of added and changed features
diff_ids = list(added_ids)
diff_ids.extend(changed_ids)
# select all different features
new.setSelectedFeatures(diff_ids)
# to simplify the process save new with selected only option to a result layer

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