# -*- 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(refresh=False): if refresh: gdf_perimeters = gpd.read_file( 'https://opendata.arcgis.com/api/v3/datasets/5e72b1699bf74eefb3f3aff6f4ba5511_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']) else: gdf_perimeters = gpd.read_parquet( "wildfire_perimeters.parquet").query("geometry==geometry") 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=6, 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", "1315 10th St, Sacramento, CA 95814") date = st.sidebar.date_input("Date", pd.Timestamp(2021, 7, 14), key='date') number_days_range = st.sidebar.selectbox( 'Within Day Range:', (5, 10, 30, 90, 180)) refresh = st.sidebar.radio( 'Refresh Data (as of 3/7/24): 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(refresh) # 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