QGIS Spatial Join – How to Perform a Spatial Join from Points to Polygons Using GeoPandas

geopandaspythonqgissjoinspatial-join

I have the following points and polygons layers:
enter image description here

There is exactly one point attributed to each polygon, all accordingly within the corresponding polygon boundaries.

The points layer contains a binary attribute called "Sufficient" that either has a 1 or 0 value for each point. The corresponding polygons for each of those points do not contain this attribute.

What I want to do is "transfer" that "Sufficient" attribute from the points layer to the polygons layer, and so providing each polygon with a "Sufficient" value from its corresponding point.

Logically, this would mean for each polygon to grab the "Sufficient" attribute value from the corresponding point "within" the polygon boundaries, or in other words, the point it "contains" within its boundaries.

To accomplish this, I am using the geopandas library in python.

Here is my code:

import pandas as pd
import numpy as np
import geopandas as gpd

polygons = gpd.read_file('C:/Users/MyName/Documents/polygons.shp')

points = gpd.read_file('C:/Users/MyName/Documents/points.shp')

pointInPoly = gpd.sjoin(points, polygons, op='within')

pointInPoly.to_file("C:/Users/MyName/Documents/sufficient_polygons.shp")

However, when I go to load this new poinInPoly shapefile in QGIS, I see that the layer is a points layer, when I wanted a polygons layer, with the original polygon geometries. This new points layer is also missing the "Sufficient" attribute in its attribute table.

I have also tried this modification to .sjoin, but this also does not work:

pointInPoly = points.sjoin(polygons, how="left", predicate="within")

How can I modify my code so that I produce the intended polygons layer with the "Sufficient" attribute appended?

Best Answer

The join is from right to left, so your first attempt is points <- polygons (i.e join the polygon gdf to the points gdf) and thus you get points as the output.

Swap the order around and change the predicate to "contains" as polygons aren't "within" points, they "contain" them.

pointInPoly = gpd.sjoin(polygons, points, predicate='contains')

Notes:

  • op is deprecated, use predicate instead.
  • I know the question stated "exactly one point attributed to each polygon", but for future people who might find this answer useful, if you have multiple points in a polygon, you will get the same number of duplicate polygons output.