I have a GeoDataFrame of a (tiny) street network and want to buffer with no overlap.
Thus far I have:
#- get the stuff
rd = gpd.read_file('./data/roads-cput_proj.geojson')
rd.set_crs(epsg=32734, inplace=True, allow_override=True)
rd['lanes'] = rd['tags'].apply(lambda x: x.get('lanes'))
rd['lanes'] = pd.to_numeric(rd['lanes'])
#- clean
rd = rd[rd['geometry'].type != 'Polygon']
rd = rd[rd.geometry.length > 10]
rd.dropna(subset=['lanes'], inplace=True)
rd_buffer = rd.copy()
#- buffer_func
def buffer(row):
#return row.geometry.buffer(row.lanes * 1.5)
return row.geometry.buffer(round(float(row['lanes']) * 1.5, 2),
cap_style=2, join_style=2)
#-- loop through and trim each geometry based on how it overlaps
for i, row in rd_buffer.iterrows():
#-- the entire street network without this one segment at i
rd_copy = rd.copy()
#-- delete one street
rd_copy.drop(i, axis=0, inplace=True)
rd_copy['geometry'] = rd_copy.apply(buffer, axis=1)
#-- union
union = rd_copy.explode().dissolve()
#-- now the single steet at i that needs to be trimmed
g = row.geometry.buffer(round(float(row['lanes']) * 1.8, 2),
cap_style=2)
g = gpd.GeoDataFrame(index=[0], crs=jparams['crs'], geometry=[g])
#-- difference: g minus union
g = gpd.overlay(g, union, how='difference')
#- I want the result to be a polygon so overwrite the geometry at that index
rd_buffer.at[i, 'geometry'] = g.geometry[0]
#break
If I uncomment the break
I get (zoomed):
—where the buffered green polygon represents one street segment trimed back from the its perpendicular connection; it would overlap with when that road is buffered.
Without the break
; I get:
Overlaps remain (nothing is trimmed).
Where has the loop gone wrong?
the data is here ~ 79KB.
Best Answer
Use unary_union (Shapely unary_union)
Buffer with intersections
Four polygons without intersection
But you lose the original attributes.