I have the following DataFrame
converted into GeoDataFrame
:
import pandas as pd
import geopandas as gpd
data = {
'lat':[-34.661412, -38.700402],
'lng':[-58.366424, -62.294023],
'buffer_value':[1000000000000,100000000000]
}
df = pd.DataFrame(data)
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(far.lng, far.lat))
I want to create a buffer based on "buffer_value"
distance which is different for each column.
Using:
gdf['buffer_0'] = gdf.buffer(10, resolution=16)
creates the same distance buffer for all rows, and not different buffers for each row.
I tried the following two different alternatives:
gdf['buffer_1'] = gdf.apply(lambda row: row.geometry.buffer(row.buffer_value, resolution=16), axis=1)
and
def buffer(row):
return row.geometry.buffer(row.buffer_value)
gdf['buffer_2'] = gdf.apply(buffer, axis=1)
But both alternatives create an object column, not a geometry column.
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 lat 2 non-null float64
1 lng 2 non-null float64
2 buffer_value 2 non-null int64
3 geometry 2 non-null geometry
4 buffer_1 2 non-null object
5 buffer_2 2 non-null object
6 buffer_0 2 non-null geometry
dtypes: float64(2), geometry(2), int64(1), object(2)
memory usage: 240.0+ bytes
What am I doing wrong?
2 Answers 2
Here you go:
import pandas as pd
import geopandas as gpd
# dataframe
data = {
'lat':[-34.661412, -38.700402],
'lng':[-58.366424, -62.294023],
'buffer_value':[1000000000000,100000000000]
}
df = pd.DataFrame(data)
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['lng'], df['lat']))
# buffering
gdf['buffer'] = gdf.buffer(gdf['buffer_value'], resolution=16)
# show data
gdf.head()
gdf.dtypes
gdf['buffer'].plot(facecolor="none", edgecolor="black")
-
This is the correct answer.
buffer
is a vectorized function and usingapply
or loop will have a significant impact on performance.martinfleis– martinfleis2021年06月04日 08:37:13 +00:00Commented Jun 4, 2021 at 8:37 -
You can use the custom function below called make_variable_buffer
. Here is a small reproducible example.
import geopandas as gpd
def make_variable_buffer(input_df,
buffer_size_col_name,
geometry_column_name='geometry'):
'''
Creates a new GeoDataFrame whose geometries are the result of generating
variable-sized buffers from the input geometries.
Parameters
----------
input_df : gpd.GeoDataFrame
Input dataframe. The function will generate a copy of this dataframe
and the geometry of each row of this new dataframe will be a buffered
version of the geometries in the input dataframe
buffer_size_col_name : str
Name of the column of the input_df that contains the sizes/magnitudes
of the variable buffer. Please note that this measure is in the same
unit as your input features' CRS.
geometry_column_name : str
Name of the column of the input_df that contains the geometries
The default is 'geometry'.
Returns
-------
buff_df : gpd.GeoDataFrame
Dataframe that contains the buffers of varying sizes.
'''
# Copying the input_df
buff_df = input_df.copy()
# Creating the varying-sized buffer
buff_df['geometry'] = input_df.apply(lambda row:
(row[geometry_column_name]
.buffer(row[buffer_size_col_name])),
axis=1)
# Returning the newly-created dataframe
return buff_df
data = {'lat':[-34.661412, -38.700402],
'lng':[-58.366424, -62.294023],
'buffer_value':[1,0.3]}
df = gpd.GeoDataFrame(data,
geometry=gpd.points_from_xy(data['lng'],
data['lat']),
crs='epsg:4326')
buff_df = make_variable_buffer(input_df=df,
buffer_size_col_name='buffer_value',
geometry_column_name='geometry')
buff_df.plot()
This yields two different buffer sizes:
Explore related questions
See similar questions with these tags.