mattritchey commited on
Commit
852419d
·
1 Parent(s): 0df5573

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +186 -0
  2. requirements.txt +8 -0
  3. wildfire_perimeters.parquet +3 -0
app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Thu Jun 8 03:39:02 2023
4
+
5
+ @author: mritchey
6
+ """
7
+
8
+ import pandas as pd
9
+ import numpy as np
10
+ import streamlit as st
11
+ from geopy.extra.rate_limiter import RateLimiter
12
+ from geopy.geocoders import Nominatim
13
+ import folium
14
+ from streamlit_folium import st_folium
15
+ import geopandas as gpd
16
+ from vincenty import vincenty
17
+
18
+ st.set_page_config(layout="wide")
19
+
20
+ @st.cache_resource
21
+ def get_perimeters(refresh=False):
22
+ if refresh:
23
+ gdf_perimeters = gpd.read_file(
24
+ 'https://opendata.arcgis.com/api/v3/datasets/5e72b1699bf74eefb3f3aff6f4ba5511_0/downloads/data?format=shp&spatialRefId=4326&where=1%3D1') # .to_crs(epsg=epsg_input)
25
+ gdf_perimeters = gdf_perimeters[['OBJECTID', 'poly_Incid', 'attr_Fir_7', 'poly_Creat',
26
+ 'poly_DateC', 'poly_Polyg', 'poly_Acres', 'attr_Estim', 'geometry']].copy()
27
+ gdf_perimeters.columns = ['OBJECTID', 'Incident', 'DiscoveryDate', 'poly_Creat',
28
+ 'LastUpdate', 'poly_Polyg', 'Size_acres', 'CurrentEstCost', 'geometry']
29
+ gdf_perimeters['Lat_centroid'] = gdf_perimeters.centroid.y
30
+ gdf_perimeters['Lon_centroid'] = gdf_perimeters.centroid.x
31
+ gdf_perimeters['DiscoveryDate'] = pd.to_datetime(
32
+ gdf_perimeters['DiscoveryDate'])
33
+
34
+ else:
35
+ gdf_perimeters = gpd.read_parquet(
36
+ "wildfire_perimeters.parquet").query("geometry==geometry")
37
+ return gdf_perimeters
38
+
39
+
40
+ def map_perimeters(_gdf_data, address):
41
+ geojson_data = _gdf_data[['OBJECTID', 'Incident', 'DiscoveryDate',
42
+ 'Miles to Fire Centroid', 'geometry']].to_json()
43
+
44
+ m = folium.Map(location=[lat, lon],
45
+
46
+ zoom_start=6,
47
+ height=500)
48
+ folium.Marker(
49
+ location=[lat, lon],
50
+ tooltip=f'Address: {address}',
51
+ ).add_to(m)
52
+
53
+ folium.GeoJson(geojson_data,
54
+ tooltip=folium.GeoJsonTooltip(fields=["Incident",
55
+ "DiscoveryDate",
56
+ 'Miles to Fire Centroid']),
57
+ ).add_to(m)
58
+ return m
59
+
60
+ def distance(x):
61
+ left_coords = (x[0], x[1])
62
+ right_coords = (x[2], x[3])
63
+ return vincenty(left_coords, right_coords, miles=True)
64
+
65
+ def geocode(address):
66
+ try:
67
+ address2 = address.replace(' ', '+').replace(',', '%2C')
68
+ df = pd.read_json(
69
+ f'https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?address={address2}&benchmark=2020&format=json')
70
+ results = df.iloc[:1, 0][0][0]['coordinates']
71
+ lat, lon = results['y'], results['x']
72
+ except:
73
+ geolocator = Nominatim(user_agent="GTA Lookup")
74
+ geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
75
+ location = geolocator.geocode(address)
76
+ lat, lon = location.latitude, location.longitude
77
+ return lat, lon
78
+
79
+ def extract_vertices(gdf):
80
+ g = [i for i in gdf.geometry]
81
+ all_data = []
82
+ for i in range(len(g)):
83
+ try:
84
+ try:
85
+ x, y = g[i].exterior.coords.xy
86
+ except:
87
+ x, y = g[i].coords.xy
88
+ df = pd.DataFrame({'Lat': y, 'Lon': x})
89
+ except:
90
+ all_data2 = []
91
+ try:
92
+ for j in range(len(g[i])):
93
+ try:
94
+ x, y = g[i][j].exterior.coords.xy
95
+ except:
96
+ x, y = g[i][j].coords.xy
97
+ all_data2.append(pd.DataFrame({'Lat': y, 'Lon': x}))
98
+ df = pd.concat(all_data2)
99
+ except:
100
+ df = pd.DataFrame({'Lat': [np.nan],
101
+ 'Lon': [np.nan], })
102
+ df['index_gdf'] = i
103
+ all_data.append(df)
104
+ return pd.concat(all_data).query('Lat==Lat').reset_index(drop=1).drop(columns='index_gdf')
105
+
106
+
107
+ #Side Bar
108
+ address = st.sidebar.text_input(
109
+ "Address", "Sacramento, CA")
110
+ date = st.sidebar.date_input("Date", pd.Timestamp(2021, 7, 14), key='date')
111
+ number_days_range = st.sidebar.selectbox(
112
+ 'Within Day Range:', (5, 10, 30, 90, 180))
113
+
114
+ refresh = st.sidebar.radio(
115
+ 'Refresh Data (as of 6/7/23): Will Take Time ', (False, True))
116
+ miles_range = st.sidebar.selectbox(
117
+ 'Find Fires within Range (Miles):', (None, 50, 100, 250, 500))
118
+
119
+ size = st.sidebar.radio(
120
+ 'Greater than 100 Acres', ("Yes", "No"))
121
+
122
+ #Get Data
123
+ gdf = get_perimeters(refresh)
124
+
125
+ # Geocode Addreses
126
+ lat, lon = geocode(address)
127
+
128
+ #Filter Data
129
+ start_date, end_date = date - \
130
+ pd.Timedelta(days=number_days_range), date + \
131
+ pd.Timedelta(days=number_days_range+1)
132
+ start_date_str, end_date_str = start_date.strftime(
133
+ '%Y-%m-%d'), end_date.strftime('%Y-%m-%d')
134
+ gdf_cut = gdf.query(f"'{start_date_str}'<=DiscoveryDate<='{end_date_str}'")
135
+ gdf_cut['DiscoveryDate'] = gdf_cut['DiscoveryDate'].dt.strftime('%Y-%m-%d')
136
+
137
+
138
+ #Distance to Fire
139
+ gdf_cut["Lat_address"] = lat
140
+ gdf_cut["Lon_address"] = lon
141
+ gdf_cut['Miles to Fire Centroid'] = [
142
+ distance(i) for i in gdf_cut[gdf_cut.columns[-4:]].values]
143
+ gdf_cut['Miles to Fire Centroid'] = gdf_cut['Miles to Fire Centroid'].round(2)
144
+ if miles_range is not None:
145
+ gdf_cut = gdf_cut.query(f"`Miles to Fire Centroid`<={miles_range}")
146
+
147
+ if size == 'Yes':
148
+ gdf_cut = gdf_cut.query("Size_acres>100")
149
+
150
+ gdf_cut = gdf_cut.sort_values('Miles to Fire Centroid').reset_index(drop=1)
151
+ gdf_cut.index = gdf_cut.index+1
152
+
153
+ #Map Data
154
+ m = map_perimeters(gdf_cut, address)
155
+
156
+ #Incident Edge
157
+ indicents = list(gdf_cut['Incident'].values)
158
+ incident_edge = st.sidebar.selectbox(
159
+ 'Find Distance to Closest Edge:', indicents)
160
+
161
+ vertices = extract_vertices(gdf_cut.query(f"Incident=='{incident_edge}'"))
162
+ vertices["Lat_address"] = lat
163
+ vertices["Lon_address"] = lon
164
+ vertices['Distance'] = [
165
+ distance(i) for i in vertices.values]
166
+ closest_edge = vertices[vertices['Distance']
167
+ == vertices['Distance'].min()].head(1)
168
+ lon_point, lat_point = closest_edge[['Lon', 'Lat']].values[0]
169
+ distance_edge = closest_edge['Distance'].round(2).values[0]
170
+ folium.PolyLine([[lat, lon],
171
+ [lat_point, lon_point]],
172
+ color='black',
173
+ tooltip=f'Distance: {distance_edge} Miles'
174
+ ).add_to(m)
175
+
176
+ #Display
177
+ col1, col2 = st.columns((2, 3))
178
+ with col1:
179
+ st.header('Fire Perimeters')
180
+ st_folium(m, height=600)
181
+ with col2:
182
+ st.header('Fires')
183
+ gdf_cut[['Incident', 'DiscoveryDate', 'Size_acres','Miles to Fire Centroid']]
184
+
185
+
186
+
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ folium==0.12.1.post1
2
+ geopandas==0.10.2
3
+ geopy==2.2.0
4
+ numpy==1.19.5
5
+ pandas==1.5.2
6
+ streamlit==1.20.0
7
+ streamlit_folium==0.6.15
8
+ vincenty==0.1.4
wildfire_perimeters.parquet ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6e1b2b8347d7116e8a10a31db26905f48a67e3100eda50ebf7c371bce952eb7d
3
+ size 145374232