# -*- 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 @st.cache(allow_output_mutation=True) 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') @st.cache 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(""" """, unsafe_allow_html=True)