4

I am trying to join the attributes of bigger polygon layer to smaller polygon layer as seen below. The location geometric predicate I used in WITHIN, so that all smaller polygons within lager polygon layer will inherit the corresponding attribute a lager polygon they fall within.

enter image description here

In some case, some of the smaller polygons are fall across multiple lager polygons as seen above. In such a case, I want it to inherit the attribute of the lager polygon that contains the most percentage. So, in the case above, the selected small polygon in yellow should get the attribute of A not B since it is more within A (that is it has higher percentage in A).

How do I solve this?

1
  • You've left the realm of Join and entered Intersect-then-summary-statistics.
    – Vince
    Commented Sep 27, 2022 at 11:18

3 Answers 3

2

QGIS has a "Join attributes by location" process that includes the METHOD parameter, option 2: "Take attributes of the feature with largest overlap only (one-to-one)", use it with the "intersects" geometric predicate.

1
  • Because nothing was marked as solution, I'll say this is the most straightforward answer and the one that efficiently solved my problem. Commented Jul 14, 2023 at 9:53
0
  • Add an $id to your small features
  • Run intersect with the small features as first and the large features as second input. This a) splits your small features at the borders of the large ones, and b) adds the attributes of the large features to them.
  • Add the '$area' to your intersected features
  • Use maximum("area field",group_by:="ID") in the select by expression attribute, this selects the larger portion of each small feature
  • Create the centroids of the selected features, just to be on the safe side
  • Join attributes by location from the centroids to the original small features
  • clean up your attribute table
0

For a Python answer without QGIS, it is possible to do this with geopandas as well. Given two GeoDataframes, A and B:

geom_b: str = 'geom_b'
geom_b_area: str = 'geom_b_area'
B[geom_b] = B.geometry
B[geom_b_area] = B.geometry.area

predicate : str = 'intersects'
joint_gdf = A.sjoin(B, how=how, predicate=predicate)
joint_gdf.crs = A.crs

# Calculate overlap as proportion (NaN = A with no overlap in B)
overlap_col : str = 'overlap'
joint_gdf[overlap_col] = joint_gdf.geometry.intersection(joint_gdf.geom_b).area/joint_gdf.geometry.area

# Identify overlaps that are above a threshold
threshold : float = 0.35 # You could use 0 to accept any level of overlap
is_over_threshold = joint_gdf[overlap_col].apply(lambda x: x > threshold)

# Handle 1:M case, identify only the largest overlap
a_uid : str = 'unique_id_for_A'
is_largest_overlap = joint_gdf.groupby([a_uid])[overlap_col].transform(max) == joint_gdf[overlap_col]

# Selection
joint_gdf = joint_gdf.loc[is_largest_overlap & is_over_threshold]

output of the above, showing a spatial association based on overlap percentage

Black lines in the above image are the boundaries of B polygons, and the small, coloured polygons are members of A. A is joined to B using this process, and the colours correspond to unique IDs from B. However, the geometries of A have not been modified (i.e. there is no union).

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.