from collections import namedtuple import altair as alt import math import pandas as pd import streamlit as st import polars as pl import openmeteo_requests from datetime import * st.set_page_config( page_title="Weather Data", page_icon="🌤️", layout='wide' ) st.markdown("# Historic Weather Data for 3 BYU Campuses") st.markdown("__Explore weather data gathered at all 3 BYU locations from any chosen date range. Observe visuals explaining the temperature, pressure, wind speed, and far more from all locations.__") columns = st.columns(3, gap='medium') openmeteo = openmeteo_requests.Client() st.sidebar.markdown("_Note: Data is only present up to 4 days ago_") length = st.sidebar.slider("Length of Time Period for Data (Days)", min_value=5, max_value=30, value=15) campus = ['provo', 'hawaii', 'idaho'] locations = [(40.2518, 111.6493), (21.6419, 157.9267), (43.8145, 111.7833)] start_day = st.sidebar.date_input("Start of Period for Data", value=(datetime.today() - timedelta(days=35)), min_value=date(2020, 1, 1), max_value=(datetime.today() - timedelta(days=(length+4)))) end = (start_day + timedelta(days=length)).strftime('%Y-%m-%d') start = start_day.strftime('%Y-%m-%d') zone_select = st.sidebar.selectbox("Choose Timezone", options=['Mountain Time', 'Hawaiian Time']) zone = 'HST' if zone_select == 'Hawaiian Time' else 'MST' variables = ['Temperature (F)', 'Apparent Temp (F)', 'Humidity (%)', 'Pressure (hPa)', 'Precipitation (in)', 'Rain (in)', 'Snowfall (in)', 'Cloud Cover (%)', 'Wind Speed (mph)', 'Snow Depth (m)'] variable_select = st.sidebar.selectbox("Choose variable of interest", options=variables) variable_dict = { 'Temperature (F)': 'temperature_2m', 'Apparent Temp (F)': 'apparent_temperature', 'Humidity (%)': 'relative_humidity_2m', 'Pressure (hPa)': 'surface_pressure', 'Precipitation (in)': 'precipitation', 'Rain (in)': 'rain', 'Snowfall (in)': 'snowfall', 'Cloud Cover (%)': 'cloud_cover', 'Wind Speed (mph)': 'wind_speed_10m', 'Snow Depth (m)': 'snow_depth' } var = variable_dict[variable_select] hi_lo = st.sidebar.selectbox("Daily Extremes", options=['Max', 'Min']) daily_var = 'temperature_2m_max' if hi_lo == 'Max' else 'temperature_2m_min' def request(url, lat, long, start, end, variable, time_unit, timezone): params = { "latitude": lat, "longitude": long, "start_date": start, "end_date": end, time_unit: variable, "temperature_unit": "fahrenheit", 'timezone': timezone, 'precipitation_unit': 'inch', 'wind_speed_unit': 'mph' } return openmeteo.weather_api(url, params=params)[0] i = 0 temp_box = pl.DataFrame() for location in locations: actual = request("https://archive-api.open-meteo.com/v1/archive", location[0], location[1], start, end, var, 'hourly', zone) forecasted = request("https://historical-forecast-api.open-meteo.com/v1/forecast", location[0], location[1], start, end, var, 'hourly', zone) hourly_actual= actual.Hourly() hourly_var_actual = hourly_actual.Variables(0).ValuesAsNumpy() hourly_forecasted = forecasted.Hourly() hourly_var_forecasted = hourly_forecasted.Variables(0).ValuesAsNumpy() hourly_data = {"date-time": pd.date_range( start = pd.to_datetime(hourly_actual.Time(), unit = "s", utc = True), end = pd.to_datetime(hourly_actual.TimeEnd(), unit = "s", utc = True), freq = pd.Timedelta(seconds = hourly_actual.Interval()), inclusive = "left" )} hourly_data[var] = hourly_var_actual hourly_data[f"forecast_{var}"] = hourly_var_forecasted hourly_dataframe = pl.DataFrame(hourly_data) hourly_dataframe = hourly_dataframe.with_columns(pl.col('date-time').dt.strftime('%Y-%m-%d').alias('date')) hourly_dataframe = hourly_dataframe.with_columns(pl.col('date-time').dt.strftime("%H:%M:%S").alias('time')) with columns[i]: st.markdown(f"### {campus[i].title()}") st.dataframe(hourly_dataframe.drop('date-time')) st.dataframe(hourly_dataframe.select([var, f'forecast_{var}']).describe()[2:9]) current_campus = hourly_dataframe.with_columns(pl.lit(campus[i]).alias('campus')) end_month = (datetime.today() - timedelta(days=4)).strftime('%Y-%m-%d') start_month = (datetime.today() - timedelta(days=35)).strftime('%Y-%m-%d') daily = request("https://archive-api.open-meteo.com/v1/archive", location[0], location[1], start_month, end_month, daily_var, 'daily', zone).Daily() daily_data = {"date-time": pd.date_range( start = pd.to_datetime(daily.Time(), unit = "s", utc = True), end = pd.to_datetime(daily.TimeEnd(), unit = "s", utc = True), freq = pd.Timedelta(seconds = daily.Interval()), inclusive = "left" )} daily_data['temperature'] = daily.Variables(0).ValuesAsNumpy() daily_df = pl.DataFrame(daily_data) daily_df = daily_df.with_columns(pl.lit(campus[i]).alias('campus')) if len(temp_box) == 0: temp_box = pl.DataFrame(current_campus) temp_line = daily_df else: temp_box = temp_box.vstack(current_campus) temp_line = temp_line.vstack(daily_df) i+=1 daily = alt.Chart(temp_line).mark_line().encode( alt.X("date-time"), alt.Y('temperature'), color='campus' ).properties( title='Daily Temp Extremes Over Last Month', width=300, height=300 ) hourly_box = alt.Chart(temp_box).mark_boxplot().encode( alt.X(var).scale(zero=False), alt.Y("campus") ).properties( title='Hourly Readings', width=400, height=300 ) grouped = temp_box.select(['time', var, 'campus']).group_by(['time', 'campus']).mean() hourly_average = alt.Chart(grouped).mark_line().encode( x="time", y=var, color="campus" ).properties( title='Average Reading Given Time of Day', width=400, height=300 ) kpi_max = temp_box.select([var, 'campus']).group_by('campus').max() pr_hi = kpi_max.filter(pl.col('campus') == 'provo')[var][0] id_hi = kpi_max.filter(pl.col('campus') == 'idaho')[var][0] hi_hi = kpi_max.filter(pl.col('campus') == 'hawaii')[var][0] kpi_low = temp_box.select([var, 'campus']).group_by('campus').min() pr_lo = kpi_low.filter(pl.col('campus') == 'provo')[var][0] id_lo = kpi_low.filter(pl.col('campus') == 'idaho')[var][0] hi_lo = kpi_low.filter(pl.col('campus') == 'hawaii')[var][0] st.sidebar.altair_chart(daily) columns[1].altair_chart(hourly_box) columns[0].altair_chart(hourly_average) with columns [2]: sub_cols = st.columns(2) with sub_cols[0]: st.markdown(f"Provo Max: {round(pr_hi, 1)}") st.markdown(f"Hawaii Max: {round(hi_hi, 1)}") st.markdown(f"Idaho Max: {round(id_hi, 1)}") with sub_cols[1]: st.markdown(f"Provo Min: {round(pr_lo, 1)}") st.markdown(f"Hawaii Min: {round(hi_lo, 1)}") st.markdown(f"Idaho Min: {round(id_lo, 1)}")