psalama's picture
Modularize python code
b939fb6
raw
history blame
4.05 kB
import geopandas as gpd
import pandas as pd
from arcgis.features import FeatureLayer
from arcgis.geometry import Geometry
from shapely.geometry import shape
from shapely.ops import unary_union
# all data processing functions
def get_gdf_from_feature_layer(url):
# Access the ArcGIS feature layer
feature_layer = FeatureLayer(url)
# Use the query() method to get all features where 'Borough' is 'MN'
sdf = feature_layer.query(where="Borough='MN'", out_sr=4326, as_df=True)
# Convert the 'SHAPE' column from ArcGIS's JSON-based format into a Shapely geometry
sdf['geometry'] = sdf['SHAPE'].apply(lambda x: Geometry(x).as_shapely)
# Convert the SpatialDataFrame to a GeoDataFrame
gdf = gpd.GeoDataFrame(sdf, geometry='geometry')
return gdf
def process_buildings(input_gdf, sensitive_sites_gdf, default_building_height_m, multiplier_factor):
# List to store all intersected sensitive sites
intersected_sites = []
# List to store all buffers
buffers = []
intersection_desc = ""
# Iterate over each building in the input file
for idx, building in input_gdf.iterrows():
building_name = building.get('building_name', 'Unnamed building')
# If the 'building_height' field exists and its value is not null or zero for this building,
# use it as the building height. Otherwise, use the default building height provided by the user.
if 'building_height' in building and pd.notnull(building['building_height']) and building['building_height'] != 0:
building_height_m = building['building_height'] * 0.3048
else:
building_height_m = default_building_height_m
buffer_distance_m = building_height_m * multiplier_factor
# Convert building's geometry to EPSG:3857 for accurate meter-based distance measurement
building_geometry = gpd.GeoSeries([building['geometry']], crs="EPSG:4326")
building_geometry_m = building_geometry.to_crs("EPSG:3857")
# Create a buffer around the building and convert it to a GeoDataFrame
building_buffer = building_geometry_m.buffer(buffer_distance_m)
building_buffer_gdf = gpd.GeoDataFrame(geometry=building_buffer, crs="EPSG:3857")
building_buffer_gdf = building_buffer_gdf.to_crs("EPSG:4326")
# Convert back to feet for storing and printing, rounding to the nearest foot
building_height_ft = round(building_height_m / 0.3048)
buffer_distance_ft = round(buffer_distance_m / 0.3048)
# Assign additional attributes
building_buffer_gdf['building_name'] = building_name
building_buffer_gdf['building_height'] = building_height_ft
building_buffer_gdf['buffer_distance'] = buffer_distance_ft
buffers.append(building_buffer_gdf)
# Check if the buffer intersects with any sensitive sites
intersects = gpd.overlay(building_buffer_gdf, sensitive_sites_gdf, how='intersection')
if not intersects.empty:
building_intersect_desc = f"Building {idx} ({building_name}), height: {building_height_ft}, buffer distance: {buffer_distance_ft} is in the vicinity of a sensitive site."
intersected_sites.append(intersects)
else:
building_intersect_desc = f"Building {idx} ({building_name}), height: {building_height_ft}, buffer distance: {buffer_distance_ft} is not in the vicinity of any sensitive sites."
if intersection_desc == "":
intersection_desc = building_intersect_desc
else:
intersection_desc += "\n" + building_intersect_desc
return buffers, intersected_sites, intersection_desc
def get_max_extent(*gdfs): # takes in unlimited number of gdfs and calculates max/min xy extents
minx = min(gdf.total_bounds[0] for gdf in gdfs)
miny = min(gdf.total_bounds[1] for gdf in gdfs)
maxx = max(gdf.total_bounds[2] for gdf in gdfs)
maxy = max(gdf.total_bounds[3] for gdf in gdfs)
return minx, miny, maxx, maxy