Vectorized creation of shapely Polygons from GeoPandas DataFrame

Question:

I have a GeoDataFrame with a point geometry.
From the point geometry, I want to define a square polygon geometry in a quite straightforward manner.

Given a point, the point should be the left bottom corner in a square with sides 250 units of length.
I.e, left bottom corner is the current point, right bottom corner is the current point + 250 on the x axis etc.

My naive way of doing this is the following:
Create the corners as new columns in the GeoDataFrame:
enter image description here

After that, I try to define a new columns as:

gdf['POLY'] = shapely.Geometry([gdf['BOTTOM_LEFT'], gdf['BOTTOM_RIGHT'], gdf['TOP_LEFT'], gdf['TOP_RIGHT']])

But this returns the following error message:

AttributeError: 'list' object has no attribute '__array_interface__'
Asked By: Felix Darke

||

Answers:

Let’s assume you have a GeoDataFrame with only single point. It is called gdf and it looks as follows:

X   Y   geometry
0   5   6   POINT (5.00000 6.00000)

You can access the x and y components of the point using the following lambda function:

#Access x and y components of point geometry
X = gdf.geometry.apply(lambda x: x.x)

Y = gdf.geometry.apply(lambda x: x.y)

Now you can create a square object using shapely.geometry.Polygon. You need to specify the four vertices of the square. You can do it using:

gdf_square = shapely.geometry.Polygon([[X[0], Y[0]],
                                      [X[0]+250, Y[0]],
                                     [X[0]+250, Y[0]+250],
                                     [X[0], Y[0]+250]])

You can get a square polygon object as shown below:
enter image description here

Note that if you have many points in the GeoDataFrame, modify the last function such that it creates the square polygon for point in each row one by one.

Answered By: hbstha123

Your implementation is close, but you can’t call shapely.geometry.Polygon with an array of points – it can only be done one at a time. So the trick is to use df.apply to call Polygon on every row of the DataFrame:

gdf['geometry'] = gdf.apply(
    lambda s: shapely.geometry.Polygon(
        [s['BOTTOM_LEFT'], s['BOTTOM_RIGHT'], s['TOP_LEFT'], s['TOP_RIGHT']],
        axis=1,
    )
)

You could do that with your original point using translate:

gdf['geometry'] = gdf.apply(
    lambda s: shapely.geometry.Polygon(
        [
            s['POINT'],
            s['POINT'].translate(xoff=250),
            s['POINT'].translate(yoff=250, xoff=250),
            s['POINT'].translate(yoff=250),
        ],
        axis=1,
    )
)
Answered By: Michael Delgado

In my case it was more than 5 times faster to build the triangles using list comprehension than using geopandas.apply :

polys = [Polygon(((x, y), (x, y+d), (x+d, y+d), (x+d, y))) for x in xs for y in ys]

gdf = gpd.GeoDataFrame(geometry=polys)
Answered By: fdsgththertw
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.