Weather_app / streamlit_app.py
MatthewMec
app
1decd71
import openmeteo_requests
import requests_cache
import polars as pl
from retry_requests import retry
import streamlit as st
from datetime import datetime, timedelta
import pytz
from lets_plot import *
from streamlit_letsplot import st_letsplot
import numpy as np
#API Fetch
openmeteo = openmeteo_requests.Client()
#Empty Frames
locations = [
{"name": "Rexburg, Idaho", "latitude": 43.8251, "longitude": -111.7924},
{"name": "Provo, Utah", "latitude": 40.2338, "longitude": -111.6585},
{"name": "Laie, Hawaii", "latitude": 21.6210, "longitude": -157.9753}
]
location_names = [location["name"] for location in locations]
filtered_forecasts = {}
filtered_histories = {}
historical_data = []
forecast_data = []
timezones = pytz.all_timezones
def find_max(df):
daily_highs = df.group_by(by = 'Date').agg(pl.max("Temperature").alias('max'))
return daily_highs, df
# Date Variables
today = datetime.today()
default = today - timedelta(days=14)
# Streamlit Variables
start_date = st.sidebar.date_input(
'Select start date:',
value = default,
max_value= default
)
selected_timezone = st.sidebar.selectbox(
'Choose a timezone:',
timezones
)
end_date = start_date + timedelta(days=14)
temperature_option = st.sidebar.selectbox(
'Select Temperature Type',
('Highest', 'Lowest')
)
city_option = st.sidebar.selectbox(
'Select City',
('Rexburg, Idaho', 'Provo, Utah', 'Laie, Hawaii')
)
# Display the selected date range
st.sidebar.write(f"Date Range: {start_date} to {end_date}")
# Get Forecast Data
for location in locations:
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": location["latitude"],
"longitude": location["longitude"],
"start_date": start_date.strftime('%Y-%m-%d'),
"end_date": end_date.strftime('%Y-%m-%d'),
"hourly": "temperature_2m"
}
# Fetch weather data
responses = openmeteo.weather_api(url, params=params)
response = responses[0]
hourly = response.Hourly()
hourly_temperature_2m = hourly.Variables(0).ValuesAsNumpy()
# Convert timestamp to datetime
start = datetime.fromtimestamp(hourly.Time())
end = datetime.fromtimestamp(hourly.TimeEnd())
freq = timedelta(seconds=hourly.Interval())
# Create Polars DataFrame
hourly_data = pl.select(
date = pl.datetime_range(start, end, freq, closed = "left"),
temperature_2m = hourly_temperature_2m,
location = [location["name"]])
hourly_dataframe = pl.DataFrame(data = hourly_data)
historical_data.append(hourly_dataframe)
# Concatenate all DataFrames
combined_historical = pl.DataFrame(pl.concat(historical_data)).explode('location')
# Get True Historical Data
for location in locations:
url = "https://archive-api.open-meteo.com/v1/archive"
params = {
"latitude": location["latitude"],
"longitude": location["longitude"],
"start_date": start_date.strftime('%Y-%m-%d'),
"end_date": end_date.strftime('%Y-%m-%d'),
"hourly": "temperature_2m"
}
# Fetch weather data
responses = openmeteo.weather_api(url, params=params)
response = responses[0]
hourly = response.Hourly()
hourly_temperature_2m = hourly.Variables(0).ValuesAsNumpy()
# Convert timestamp to datetime
start = datetime.fromtimestamp(hourly.Time())
end = datetime.fromtimestamp(hourly.TimeEnd())
freq = timedelta(seconds=hourly.Interval())
# Create Polars DataFrame
hourly_data = pl.select(
date = pl.datetime_range(start, end, freq, closed = "left"),
temperature_2m = hourly_temperature_2m,
location = [location["name"]])
hourly_dataframe = pl.DataFrame(data = hourly_data)
forecast_data.append(hourly_dataframe)
combined_forecast = pl.DataFrame(pl.concat(forecast_data)).explode('location')
for name in location_names:
filtered_forecasts[name] = (combined_forecast.filter(pl.col("location") == name).drop('location').rename({'date': 'Date'}).rename({'temperature_2m': 'Temperature'}).with_columns(pl.col('Temperature') * 9/5 + 32))
filtered_histories[name] = (combined_historical.filter(pl.col("location") == name).drop('location').rename({'date': 'Date'}).rename({'temperature_2m': 'Temperature'}).with_columns(pl.col('Temperature') * 9/5 + 32))
tab1, tab2, tab3 = st.tabs(["Data", "Visualisations", "KPIs"])
with tab1:
st.title("Forecasted Weather vs Actual Weather by City")
st.header('Forecasts')
st.markdown("<h2 style='text-align: center; color: white;'>Rexburg</h2>", unsafe_allow_html=True)
# Create two columns for Rexburg content
rexburg_col1, rexburg_col2 = st.columns(2)
# Rexburg content
with rexburg_col1:
st.write("Forecasts")
st.dataframe(filtered_forecasts["Rexburg, Idaho"], use_container_width=True, hide_index=True)
with rexburg_col2:
st.write("Historical Data")
st.dataframe(filtered_histories["Rexburg, Idaho"], use_container_width=True, hide_index=True)
# Provo Header
st.markdown("<h2 style='text-align: center; color: white;'>Provo</h2>", unsafe_allow_html=True)
# Create two columns for Provo content
provo_col1, provo_col2 = st.columns(2)
# Provo content
with provo_col1:
st.write("Forecasts")
st.dataframe(filtered_forecasts["Provo, Utah"], use_container_width=True, hide_index=True)
with provo_col2:
st.write("Historical Data")
st.dataframe(filtered_histories["Provo, Utah"], use_container_width=True, hide_index=True)
# Laie Header
st.markdown("<h2 style='text-align: center; color: white;'>Laie</h2>", unsafe_allow_html=True)
# Create two columns for Laie content
laie_col1, laie_col2 = st.columns(2)
# Laie content
with laie_col1:
st.write("Forecasts")
st.dataframe(filtered_forecasts["Laie, Hawaii"], use_container_width=True, hide_index=True)
with laie_col2:
st.write("Historical Data")
st.dataframe(filtered_histories["Laie, Hawaii"], use_container_width=True, hide_index=True)
with tab2:
st.header('Visualisations by City')
st.subheader("Forecasted Data vs. Historical Data")
combined_forecast = combined_forecast.rename({'date': 'Date'}).rename({'temperature_2m': 'Temperature'}).with_columns(pl.col('Temperature') * 9/5 + 32).with_columns(pl.col('Date').cast(datetime))
combined_historical = combined_historical.rename({'date': 'Date'}).rename({'temperature_2m': 'Temperature'}).with_columns(pl.col('Temperature') * 9/5 + 32).with_columns(pl.col('Date').cast(datetime))
reg_forecasted = ggplot(combined_forecast, aes(x='Date', y='Temperature', color = 'location')) \
+ geom_line() \
+ facet_wrap('location', ncol = 1) \
+ labs(title = f'Hourly Temperatures',
x = 'Date', y = 'Temperature (°F)', color = 'City Name') + \
guides(color="none") + \
scale_x_datetime(format = '%m/%d')
reg_historical = ggplot(combined_historical, aes(x='Date', y='Temperature', color = 'location')) \
+ geom_line() \
+ facet_wrap('location', ncol = 1) \
+ labs(title = f'Hourly Temperatures',
x = 'Date', y = 'Temperature (°F)', color = 'City Name') + \
guides(color="none") + \
scale_x_datetime(format = '%m/%d')
st.subheader('Forecasted')
st_letsplot(reg_forecasted)
st.subheader('Historical')
st_letsplot(reg_historical)
st.subheader('Boxplot of Average Hourly Temperature')
box_plot = ggplot(combined_forecast, aes(x='location', y='Temperature', color = 'location')) + \
geom_jitter(alpha = .65) + \
geom_boxplot(alpha = .9) + \
labs(title=f'Hourly Temperature Readings',
x='City', y='Temperature (°F)') + \
guides(color = "none")
st_letsplot(box_plot)
maxes = combined_historical.group_by('location').agg((pl.col('Temperature').max()))
max_plot = ggplot(maxes, aes(x = 'location', y = 'Temperature', color = 'location')) + \
geom_bar(stat='identity') + \
labs(x = 'City Name', y = 'Max Temperature in Month (°F)')
st.subheader('Maximum Temperature for Period')
st_letsplot(max_plot)
with tab3:
if temperature_option == 'Highest':
highest_temp = combined_historical.filter(pl.col('location') == city_option).select(pl.max('Temperature')).item()
st.metric(label=f"Highest Temperature in {city_option}", value=f"{round(highest_temp,2)} °F")
else:
# Get the lowest temperature and its corresponding date
lowest_temp = combined_historical.filter(pl.col('location') == city_option).select(pl.min('Temperature')).item()
st.metric(label=f"Highest Temperature in {city_option}", value=f"{round(lowest_temp,2)} °F")