mattritchey commited on
Commit
12e1f6d
·
1 Parent(s): ac5fe72

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +239 -0
app.py ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Oct 14 10:35:25 2022
4
+
5
+ @author: mritchey
6
+ """
7
+ # streamlit run "C:\Users\mritchey\.spyder-py3\Python Scripts\streamlit projects\ERA\ERA2.py"
8
+ import datetime
9
+ import glob
10
+ import os
11
+ import branca.colormap as cm
12
+ import folium
13
+ import numpy as np
14
+ import pandas as pd
15
+ import plotly.express as px
16
+ import streamlit as st
17
+ from geopy.extra.rate_limiter import RateLimiter
18
+ from geopy.geocoders import Nominatim
19
+ from matplotlib import colors as colors
20
+ from streamlit_folium import st_folium
21
+ import xarray as xr
22
+ import cdsapi
23
+ import os
24
+
25
+
26
+
27
+ def mapvalue2color(value, cmap):
28
+ if np.isnan(value):
29
+ return (1, 0, 0, 0)
30
+ else:
31
+ return colors.to_rgba(cmap(value), 0.7)
32
+
33
+
34
+ def geocode(address):
35
+ try:
36
+ address2 = address.replace(' ', '+').replace(',', '%2C')
37
+ df = pd.read_json(
38
+ f'https://geocoding.geo.census.gov/geocoder/locations/onelineaddress?address={address2}&benchmark=2020&format=json')
39
+ results = df.iloc[:1, 0][0][0]['coordinates']
40
+ lat, lon = results['y'], results['x']
41
+ except:
42
+ geolocator = Nominatim(user_agent="GTA Lookup")
43
+ geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)
44
+ location = geolocator.geocode(address)
45
+ lat, lon = location.latitude, location.longitude
46
+ return lat, lon
47
+
48
+
49
+ def graph_within_date_range(d, number_days_range):
50
+ year, month, day = d[:4], d[4:6], d[6:8]
51
+ date = pd.Timestamp(d)
52
+ start_date, end_date = date - \
53
+ pd.Timedelta(days=number_days_range), date + \
54
+ pd.Timedelta(days=number_days_range+1)
55
+ start_date = start_date.strftime("%Y-%m-%d")
56
+ end_date = end_date.strftime("%Y-%m-%d")
57
+ url = f'https://archive-api.open-meteo.com/v1/archive?latitude={lat}&longitude={lon}&start_date={start_date}&end_date={end_date}&hourly=temperature_2m,precipitation,windspeed_10m,windgusts_10m&models=best_match&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch'
58
+ df = pd.read_json(url).reset_index()
59
+ data = pd.DataFrame({c['index']: c['hourly'] for r, c in df.iterrows()})
60
+ data['time'] = pd.to_datetime(data['time'])
61
+ data['date'] = pd.to_datetime(data['time'].dt.date)
62
+ data = data.query("temperature_2m==temperature_2m")
63
+
64
+ data_agg = data.groupby(['date']).agg({'temperature_2m': ['min', 'mean', 'max'],
65
+ 'precipitation': ['sum'],
66
+ 'windspeed_10m': ['min', 'mean', 'max'],
67
+ 'windgusts_10m': ['min', 'mean', 'max']
68
+ })
69
+ data_agg.columns = data_agg.columns.to_series().str.join('_')
70
+ data_agg = data_agg.query("temperature_2m_min==temperature_2m_min")
71
+ return data.drop(columns=['date']), data_agg
72
+
73
+
74
+ @st.cache(allow_output_mutation=True)
75
+ def get_era5_data(year, month, day):
76
+ c = cdsapi.Client(key=os.environ['key'],
77
+ url="https://cds.climate.copernicus.eu/api/v2")
78
+
79
+ c.retrieve(
80
+ 'reanalysis-era5-single-levels',
81
+ {
82
+ 'product_type': 'reanalysis',
83
+ 'variable': ['10m_u_component_of_wind', '10m_v_component_of_wind',
84
+ 'instantaneous_10m_wind_gust',
85
+ '2m_temperature', 'total_precipitation'],
86
+ 'year': year,
87
+ 'month': [month],
88
+ 'day': [day],
89
+ 'time': ['00:00', '06:00', '12:00', '18:00'],
90
+ 'area': [49.5, -125, 24.5, -66.5, ],
91
+ 'format': 'netcdf',
92
+ },
93
+ 'data.nc')
94
+
95
+
96
+ @st.cache
97
+ def convert_df(df):
98
+ return df.to_csv(index=0).encode('utf-8')
99
+
100
+
101
+ try:
102
+ for i in glob.glob('*.grib2'):
103
+ os.remove(i)
104
+ except:
105
+ pass
106
+
107
+ st.set_page_config(layout="wide")
108
+ col1, col2 = st.columns((2))
109
+
110
+ address = st.sidebar.text_input(
111
+ "Address", "123 Main Street, Columbus, OH 43215")
112
+ date = st.sidebar.date_input(
113
+ "Date", pd.Timestamp(2022, 9, 28))
114
+ d = date.strftime('%Y%m%d')
115
+ date = date.strftime('%Y-%m-%d')
116
+ time = st.sidebar.selectbox('Time (UTC):', ('12 AM', '6 AM', '12 PM', '6 PM',))
117
+ type_var = st.sidebar.selectbox(
118
+ 'Type:', ('Gust', 'Wind', 'Temp', 'Precipitation'))
119
+ number_days_range = st.sidebar.selectbox(
120
+ 'Within Day Range:', (5, 10, 30, 90, 180))
121
+ hourly_daily = st.sidebar.radio('Aggregate Data', ('Hourly', 'Daily'))
122
+
123
+ # Keys
124
+ var_key = {'Gust': 'i10fg', 'Wind': 'wind10',
125
+ 'Temp': 't2m', 'Precipitation': 'tp'}
126
+
127
+ variable = var_key[type_var]
128
+
129
+ unit_key = {'Gust': 'MPH', 'Wind': 'MPH',
130
+ 'Temp': 'F', 'Precipitation': 'In.'}
131
+ unit = unit_key[type_var]
132
+
133
+ cols_key = {'Gust': ['windgusts_10m'], 'Wind': ['windspeed_10m'], 'Temp': ['temperature_2m'],
134
+ 'Precipitation': ['precipitation']}
135
+
136
+ cols_key_agg = {'Gust': ['windgusts_10m_min', 'windgusts_10m_mean',
137
+ 'windgusts_10m_max'],
138
+ 'Wind': ['windspeed_10m_min', 'windspeed_10m_mean',
139
+ 'windspeed_10m_max'],
140
+ 'Temp': ['temperature_2m_min', 'temperature_2m_mean', 'temperature_2m_max'],
141
+ 'Precipitation': ['precipitation_sum']}
142
+
143
+ if hourly_daily == 'Hourly':
144
+ cols = cols_key[type_var]
145
+ else:
146
+ cols = cols_key_agg[type_var]
147
+
148
+
149
+ if time[-2:] == 'PM' and int(time[:2].strip()) < 12:
150
+ t = datetime.time(int(time[:2].strip())+12, 00).strftime('%H')+'00'
151
+ elif time[-2:] == 'AM' and int(time[:2].strip()) == 12:
152
+ t = '00:00'
153
+ else:
154
+ t = datetime.time(int(time[:2].strip()), 00).strftime('%H')+'00'
155
+
156
+ year, month, day = d[:4], d[4:6], d[6:8]
157
+
158
+ get_era5_data(year, month, day)
159
+ ds = xr.open_dataset('data.nc')
160
+ ds = ds.sel(time=f'{date}T{t}').drop('time')
161
+
162
+ #Convert Units
163
+ ds = ds.assign(t2m=(ds.t2m - 273.15) * 9/5 + 32)
164
+ ds = ds.assign(i10fg=(ds.i10fg*2.237))
165
+ ds = ds.assign(tp=(ds.tp/24.5))
166
+ ds = ds.assign(wind10=((ds.v10**2+ds.u10**2)**.5)*2.237)
167
+
168
+ lat, lon = geocode(address)
169
+
170
+ var_value = ds[variable].sel(
171
+ longitude=lon, latitude=lat, method="nearest").values.item()
172
+ var_value = round(var_value, 1)
173
+
174
+ img = ds[variable].values
175
+ boundary = ds.rio.bounds()
176
+ left, bottom, right, top = boundary
177
+
178
+ img[img < 0.0] = np.nan
179
+
180
+ clat = (bottom + top)/2
181
+ clon = (left + right)/2
182
+
183
+ vmin = np.floor(np.nanmin(img))
184
+ vmax = np.ceil(np.nanmax(img))
185
+
186
+ colormap = cm.LinearColormap(
187
+ colors=['blue', 'lightblue', 'red'], vmin=vmin, vmax=vmax)
188
+
189
+ m = folium.Map(location=[lat, lon], zoom_start=5, height=500)
190
+
191
+ folium.Marker(
192
+ location=[lat, lon],
193
+ popup=f"{var_value} {unit}"
194
+ ).add_to(m)
195
+
196
+ folium.raster_layers.ImageOverlay(
197
+ image=img,
198
+ name='Wind Speed Map',
199
+ opacity=.8,
200
+ bounds=[[bottom, left], [top, right]],
201
+ colormap=lambda value: mapvalue2color(value, colormap)
202
+ ).add_to(m)
203
+
204
+
205
+ folium.LayerControl().add_to(m)
206
+ colormap.caption = 'Wind Speed: MPH'
207
+ m.add_child(colormap)
208
+
209
+ with col1:
210
+ st.title('ERA5 Model')
211
+ # st.write(
212
+ # f"{type_wind.title()} Speed: {wind_mph[0].round(2)} MPH at {time} UTC")
213
+ st_folium(m, height=500)
214
+ df_all, df_all_agg = graph_within_date_range(d, number_days_range)
215
+
216
+ if hourly_daily == 'Hourly':
217
+ fig = px.line(df_all, x="time", y=cols)
218
+ df_downloald = df_all
219
+ else:
220
+ fig = px.line(df_all_agg.reset_index(), x="date", y=cols)
221
+ df_downloald = df_all_agg.reset_index()
222
+
223
+ with col2:
224
+ st.title('Analysis')
225
+ st.plotly_chart(fig)
226
+
227
+ csv = convert_df(df_downloald)
228
+
229
+ st.download_button(
230
+ label="Download data as CSV",
231
+ data=csv,
232
+ file_name=f'{d}.csv',
233
+ mime='text/csv')
234
+
235
+
236
+ st.markdown(""" <style>
237
+ #MainMenu {visibility: hidden;}
238
+ footer {visibility: hidden;}
239
+ </style> """, unsafe_allow_html=True)