mattritchey's picture
Update app.py
88c2fcc verified
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 8 03:39:02 2023
@author: mritchey
"""
import pandas as pd
import numpy as np
import streamlit as st
from geopy.extra.rate_limiter import RateLimiter
from geopy.geocoders import Nominatim
import folium
from streamlit_folium import st_folium
import geopandas as gpd
from vincenty import vincenty
st.set_page_config(layout="wide")
@st.cache_resource
def get_perimeters():
gdf_perimeters = gpd.read_file(
'https://opendata.arcgis.com/api/v3/datasets/d1c32af3212341869b3c810f1a215824_0/downloads/data?format=shp&spatialRefId=4326&where=1%3D1') # .to_crs(epsg=epsg_input)
gdf_perimeters = gdf_perimeters[['OBJECTID', 'poly_Incid', 'attr_Fir_7', 'poly_Creat',
'poly_DateC', 'poly_Polyg', 'poly_Acres', 'attr_Estim', 'geometry']].copy()
gdf_perimeters.columns = ['OBJECTID', 'Incident', 'DiscoveryDate', 'poly_Creat',
'LastUpdate', 'poly_Polyg', 'Size_acres', 'CurrentEstCost', 'geometry']
gdf_perimeters['Lat_centroid'] = gdf_perimeters.centroid.y
gdf_perimeters['Lon_centroid'] = gdf_perimeters.centroid.x
gdf_perimeters['DiscoveryDate'] = pd.to_datetime(
gdf_perimeters['DiscoveryDate'])
return gdf_perimeters
def map_perimeters(_gdf_data, address):
geojson_data = _gdf_data[['OBJECTID', 'Incident', 'DiscoveryDate',
'Miles to Fire Centroid', 'geometry']].to_json()
m = folium.Map(location=[lat, lon],
zoom_start=8,
height=500)
folium.Marker(
location=[lat, lon],
tooltip=f'Address: {address}',
).add_to(m)
folium.GeoJson(geojson_data,
tooltip=folium.GeoJsonTooltip(fields=["Incident",
"DiscoveryDate",
'Miles to Fire Centroid']),
).add_to(m)
return m
def distance(x):
left_coords = (x[0], x[1])
right_coords = (x[2], x[3])
return vincenty(left_coords, right_coords, miles=True)
def geocode(address):
try:
address2 = address.replace(' ', '+').replace(',', '%2C')
df = pd.read_json(
f'https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?address={address2}&benchmark=2020&format=json')
results = df.iloc[:1, 0][0][0]['coordinates']
lat, lon = results['y'], results['x']
except:
geolocator = Nominatim(user_agent="GTA Lookup")
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
location = geolocator.geocode(address)
lat, lon = location.latitude, location.longitude
return lat, lon
def extract_vertices_1(multipolygon):
vertices = []
for polygon in multipolygon.geoms: # Access the individual polygons
x, y = polygon.exterior.xy # Get exterior coordinates
vertices.extend(zip(x, y)) # Combine x and y coordinates
return vertices
def extract_vertices_final(gdf):
all_data = []
for idx, geom in enumerate(gdf.geometry):
if geom.geom_type == 'MultiPolygon':
vertices = extract_vertices_1(geom)
else:
x, y = geom.exterior.xy # Handle single polygons
vertices = list(zip(x, y))
df = pd.DataFrame(vertices, columns=['Lon', 'Lat'])
df['index_gdf'] = idx # Add index from GeoDataFrame
all_data.append(df[['Lat','Lon','index_gdf']])
return pd.concat(all_data).query('Lat==Lat').reset_index(drop=1).drop(columns='index_gdf')
#Side Bar
address = st.sidebar.text_input(
"Address", "407 N Macneil St, San Fernando, CA 91340")
date = st.sidebar.date_input("Date", pd.Timestamp.today(), key='date')
number_days_range = st.sidebar.selectbox(
'Within Day Range:', (60, 5, 10,30, 90, 180))
# refresh = st.sidebar.radio(
# 'Refresh Data (as of 6/7/23): Will Take Time ', (False, True))
miles_range = st.sidebar.selectbox(
'Find Fires within Range (Miles):', (None, 50, 100, 250, 500))
size = st.sidebar.radio(
'Greater than 100 Acres', ("Yes", "No"))
#Get Data
gdf = get_perimeters()
# Geocode Addreses
lat, lon = geocode(address)
#Filter Data
start_date, end_date = date - \
pd.Timedelta(days=number_days_range), date + \
pd.Timedelta(days=number_days_range+1)
start_date_str, end_date_str = start_date.strftime(
'%Y-%m-%d'), end_date.strftime('%Y-%m-%d')
gdf_cut = gdf.query(f"'{start_date_str}'<=DiscoveryDate<='{end_date_str}'")
gdf_cut['DiscoveryDate'] = gdf_cut['DiscoveryDate'].dt.strftime('%Y-%m-%d')
#Distance to Fire
gdf_cut["Lat_address"] = lat
gdf_cut["Lon_address"] = lon
gdf_cut['Miles to Fire Centroid'] = [
distance(i) for i in gdf_cut[gdf_cut.columns[-4:]].values]
gdf_cut['Miles to Fire Centroid'] = gdf_cut['Miles to Fire Centroid'].round(2)
gdf_cut['Size_acres']=gdf_cut['Size_acres'].round(1)
if miles_range is not None:
gdf_cut = gdf_cut.query(f"`Miles to Fire Centroid`<={miles_range}")
if size == 'Yes':
gdf_cut = gdf_cut.query("Size_acres>100")
gdf_cut = gdf_cut.sort_values('Miles to Fire Centroid').drop_duplicates().reset_index(drop=1)
# gdf_cut.index = gdf_cut.index+1
#Map Data
m = map_perimeters(gdf_cut, address)
#Incident Edge
indicents = list(gdf_cut['Incident'].values)
incident_edge = st.sidebar.selectbox(
'Find Distance to Closest Edge:', indicents)
vertices = extract_vertices_final(gdf_cut[gdf_cut['Incident']==incident_edge])
vertices["Lat_address"] = lat
vertices["Lon_address"] = lon
vertices['Distance'] = [
distance(i) for i in vertices.values]
closest_edge = vertices[vertices['Distance']
== vertices['Distance'].min()]
try:
lon_point, lat_point = closest_edge[['Lon', 'Lat']].values[0]
distance_edge = closest_edge['Distance'].round(2).values[0]
folium.PolyLine([[lat, lon],
[lat_point, lon_point]],
color='black',
tooltip=f'Distance: {distance_edge} Miles'
).add_to(m)
except:
pass
#Display
col1, col2 = st.columns((2, 3))
with col1:
st.header('Fire Perimeters')
st_folium(m, height=600)
with col2:
st.header('Fires')
gdf_cut2 = gdf_cut[['Incident', 'DiscoveryDate', 'Size_acres','Miles to Fire Centroid']].drop_duplicates().reset_index(drop=1)
gdf_cut2.index = gdf_cut2.index+1
gdf_cut2