Spaces:
Running
Running
# -*- coding: utf-8 -*- | |
""" | |
Created on Fri Oct 14 10:35:25 2022 | |
@author: mritchey | |
""" | |
# streamlit run "C:\Users\mritchey\.spyder-py3\Python Scripts\streamlit projects\ERA\ERA2.py" | |
import datetime | |
import glob | |
import os | |
import branca.colormap as cm | |
import folium | |
import numpy as np | |
import pandas as pd | |
import plotly.express as px | |
import streamlit as st | |
from geopy.extra.rate_limiter import RateLimiter | |
from geopy.geocoders import Nominatim | |
from matplotlib import colors as colors | |
from streamlit_folium import st_folium | |
import rioxarray | |
import xarray as xr | |
import cdsapi | |
import os | |
def mapvalue2color(value, cmap): | |
if np.isnan(value): | |
return (1, 0, 0, 0) | |
else: | |
return colors.to_rgba(cmap(value), 0.7) | |
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 graph_within_date_range(d, number_days_range): | |
year, month, day = d[:4], d[4:6], d[6:8] | |
date = pd.Timestamp(d) | |
start_date, end_date = date - \ | |
pd.Timedelta(days=number_days_range), date + \ | |
pd.Timedelta(days=number_days_range+1) | |
start_date = start_date.strftime("%Y-%m-%d") | |
end_date = end_date.strftime("%Y-%m-%d") | |
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,wind_gusts_10m&models=best_match&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch' | |
df = pd.read_json(url).reset_index() | |
data = pd.DataFrame({c['index']: c['hourly'] for r, c in df.iterrows()}) | |
data['time'] = pd.to_datetime(data['time']) | |
data['date'] = pd.to_datetime(data['time'].dt.date) | |
data = data.query("temperature_2m==temperature_2m") | |
data_agg = data.groupby(['date']).agg({'temperature_2m': ['min', 'mean', 'max'], | |
'precipitation': ['sum'], | |
'windspeed_10m': ['min', 'mean', 'max'], | |
'wind_gusts_10m': ['min', 'mean', 'max'] | |
}) | |
data_agg.columns = data_agg.columns.to_series().str.join('_') | |
data_agg = data_agg.query("temperature_2m_min==temperature_2m_min") | |
return data.drop(columns=['date']), data_agg | |
def get_era5_data(year, month, day): | |
c = cdsapi.Client(key=os.environ['key'], | |
url="https://cds.climate.copernicus.eu/api/v2") | |
c.retrieve( | |
'reanalysis-era5-single-levels', | |
{ | |
'product_type': 'reanalysis', | |
'variable': ['10m_u_component_of_wind', '10m_v_component_of_wind', | |
'instantaneous_10m_wind_gust', | |
'2m_temperature', 'total_precipitation'], | |
'year': year, | |
'month': [month], | |
'day': [day], | |
'time': ['00:00', '06:00', '12:00', '18:00'], | |
'area': [49.5, -125, 24.5, -66.5, ], | |
'format': 'netcdf', | |
}, | |
'data.nc') | |
def convert_df(df): | |
return df.to_csv(index=0).encode('utf-8') | |
try: | |
for i in glob.glob('*.grib2'): | |
os.remove(i) | |
except: | |
pass | |
st.set_page_config(layout="wide") | |
col1, col2 = st.columns((2)) | |
address = st.sidebar.text_input( | |
"Address", "1000 Main St, Cincinnati, OH 45202") | |
date = st.sidebar.date_input( | |
"Date", pd.Timestamp(2022, 9, 28)) | |
d = date.strftime('%Y%m%d') | |
date = date.strftime('%Y-%m-%d') | |
time = st.sidebar.selectbox('Time (UTC):', ('12 AM', '6 AM', '12 PM', '6 PM',)) | |
type_var = st.sidebar.selectbox( | |
'Type:', ('Gust', 'Wind', 'Temp', 'Precipitation')) | |
number_days_range = st.sidebar.selectbox( | |
'Within Day Range:', (5, 10, 30, 90, 180)) | |
hourly_daily = st.sidebar.radio('Aggregate Data', ('Hourly', 'Daily')) | |
# Keys | |
var_key = {'Gust': 'i10fg', 'Wind': 'wind10', | |
'Temp': 't2m', 'Precipitation': 'tp'} | |
variable = var_key[type_var] | |
unit_key = {'Gust': 'MPH', 'Wind': 'MPH', | |
'Temp': 'F', 'Precipitation': 'In.'} | |
unit = unit_key[type_var] | |
cols_key = {'Gust': ['wind_gusts_10m'], 'Wind': ['windspeed_10m'], 'Temp': ['temperature_2m'], | |
'Precipitation': ['precipitation']} | |
cols_key_agg = {'Gust': ['windgusts_10m_min', 'windgusts_10m_mean', | |
'windgusts_10m_max'], | |
'Wind': ['windspeed_10m_min', 'windspeed_10m_mean', | |
'windspeed_10m_max'], | |
'Temp': ['temperature_2m_min', 'temperature_2m_mean', 'temperature_2m_max'], | |
'Precipitation': ['precipitation_sum']} | |
if hourly_daily == 'Hourly': | |
cols = cols_key[type_var] | |
else: | |
cols = cols_key_agg[type_var] | |
if time[-2:] == 'PM' and int(time[:2].strip()) < 12: | |
t = datetime.time(int(time[:2].strip())+12, 00).strftime('%H')+'00' | |
elif time[-2:] == 'AM' and int(time[:2].strip()) == 12: | |
t = '00:00' | |
else: | |
t = datetime.time(int(time[:2].strip()), 00).strftime('%H')+'00' | |
year, month, day = d[:4], d[4:6], d[6:8] | |
get_era5_data(year, month, day) | |
ds = xr.open_dataset('data.nc') | |
ds = ds.sel(time=f'{date}T{t}').drop('time') | |
#Convert Units | |
ds = ds.assign(t2m=(ds.t2m - 273.15) * 9/5 + 32) | |
ds = ds.assign(i10fg=(ds.i10fg*2.237)) | |
ds = ds.assign(tp=(ds.tp/24.5)) | |
ds = ds.assign(wind10=((ds.v10**2+ds.u10**2)**.5)*2.237) | |
lat, lon = geocode(address) | |
var_value = ds[variable].sel( | |
longitude=lon, latitude=lat, method="nearest").values.item() | |
var_value = round(var_value, 1) | |
img = ds[variable].values | |
boundary = ds.rio.bounds() | |
left, bottom, right, top = boundary | |
img[img < 0.0] = np.nan | |
clat = (bottom + top)/2 | |
clon = (left + right)/2 | |
vmin = np.floor(np.nanmin(img)) | |
vmax = np.ceil(np.nanmax(img)) | |
colormap = cm.LinearColormap( | |
colors=['blue', 'lightblue', 'red'], vmin=vmin, vmax=vmax) | |
m = folium.Map(location=[lat, lon], zoom_start=5, height=500) | |
folium.Marker( | |
location=[lat, lon], | |
popup=f"{var_value} {unit}" | |
).add_to(m) | |
folium.raster_layers.ImageOverlay( | |
image=img, | |
name='Wind Speed Map', | |
opacity=.8, | |
bounds=[[bottom, left], [top, right]], | |
colormap=lambda value: mapvalue2color(value, colormap) | |
).add_to(m) | |
folium.LayerControl().add_to(m) | |
colormap.caption = 'Wind Speed: MPH' | |
m.add_child(colormap) | |
with col1: | |
st.title('ERA5 Model') | |
# st.write( | |
# f"{type_wind.title()} Speed: {wind_mph[0].round(2)} MPH at {time} UTC") | |
st_folium(m, height=500) | |
df_all, df_all_agg = graph_within_date_range(d, number_days_range) | |
if hourly_daily == 'Hourly': | |
fig = px.line(df_all, x="time", y=cols) | |
df_downloald = df_all | |
else: | |
fig = px.line(df_all_agg.reset_index(), x="date", y=cols) | |
df_downloald = df_all_agg.reset_index() | |
with col2: | |
st.title('Analysis') | |
st.plotly_chart(fig) | |
csv = convert_df(df_downloald) | |
st.download_button( | |
label="Download data as CSV", | |
data=csv, | |
file_name=f'{d}.csv', | |
mime='text/csv') | |
st.markdown(""" <style> | |
#MainMenu {visibility: hidden;} | |
footer {visibility: hidden;} | |
</style> """, unsafe_allow_html=True) | |