I have a location dataset (points long & lat) for events that happened around the World. I want to create 5km rings around these locations using Geopandas.buffer function. Following in a previous post How to use GeoPandas buffer function to get buffer zones in kilometers?, I first transform to meters and then compute the buffers.

I realize that EPSG:32634 is not appropriate for every country and appears to lead to distortions in the size of these buffers. Do I have to manually pick the "best" projection for each point or is there a way to code this? Or is the transformation to meters actually not needed?

I need to compute some statistics for the area within each of these buffers. I have to make sure that the size of the buffers is the same around the world. I don't need them for visualization purposes.


2 Answers 2


You can use .estimate_utm_crs method to find a suitable utm crs for each point, reproject to this and buffer:

import geopandas as gpd
import shapely

buffer_distance = 1000000 #Buffer radius in meters

#Create a point dataframe with 10 points around the world in EPSG:4326 coordinates
wkt_list = ['Point (146.66667606373533772 62.23890379786246285)', 
            'Point (34.32764669470472541 -41.38552524503352714)', 
            'Point (49.8860350310458216 -4.91479315765549529)', 
            'Point (-83.06099993189856434 14.366032762331713)', 
            'Point (-70.56585431584979062 -16.25292544986456278)', 
            'Point (-101.91449225955174995 -48.47418794019157673)', 
            'Point (-122.57824978678837624 -42.82228245839684888)', 
            'Point (-166.26390599168405515 -32.96525451181832267)', 
            'Point (-100.36153965087687823 26.92149042530141401)', 
            'Point (-125.12779657560248836 50.35334977372303911)']
geometries = [shapely.wkt.loads(x) for x in wkt_list]
df = gpd.GeoDataFrame(geometry=geometries, crs=4326)

df["id"] = range(0, df.shape[0]) #Create a unique id for each point/row

buffer_geometries = [] #A list to hold buffered points
for idnum, subframe in df.groupby("id"): #For each row
    estimated_utm = subframe.estimate_utm_crs() #Estimate a utm crs
    subframe = subframe.to_crs(estimated_utm) #Reproject the point to this
    subframe = subframe.buffer(distance=buffer_distance) #Buffer the point
    buffer_geometries.append(subframe.to_crs(4326)) #Reproject the resulting series back to 4326 and append to list

new_geoms = gpd.pd.concat(buffer_geometries) #From a list of series to a data frame

result = df.copy()
result["geometry"] = new_geoms

world_map = gpd.read_file("https://datahub.io/core/geo-countries/r/countries.geojson") #A world map for plotting (23 MB) 
ax = world_map.plot(figsize=(20,10), facecolor="honeydew", edgecolor="black")
result.plot(ax=ax, facecolor="#FFC107", edgecolor="#004D40")
df.plot(ax=ax, color="#D81B60", markersize=80)

enter image description here


EPSG 3857 is a geodetic CRS that is measured in meters. I'd recommend transforming to that projection then perform your buffer and analysis.

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.