|
import altair as alt |
|
import pandas as pd |
|
import plotly.graph_objects as go |
|
import streamlit as st |
|
|
|
from src.helper_functions import custom_metric_box, pollution_box |
|
from src.predict import get_data_and_predictions |
|
|
|
st.set_page_config( |
|
page_title="Utrecht Pollution Dashboard ", |
|
page_icon="🌱", |
|
layout="wide", |
|
initial_sidebar_state="expanded", |
|
) |
|
|
|
alt.themes.enable("dark") |
|
|
|
week_data, predictions_O3, predictions_NO2 = get_data_and_predictions() |
|
|
|
today = week_data.iloc[-1] |
|
previous_day = week_data.iloc[-2] |
|
|
|
dates_past = pd.date_range(end=pd.Timestamp.today(), periods=8).to_list() |
|
dates_future = pd.date_range( |
|
start=pd.Timestamp.today() + pd.Timedelta(days=1), periods=3 |
|
).to_list() |
|
|
|
|
|
o3_past_values = week_data["O3"] |
|
no2_past_values = week_data["NO2"] |
|
o3_future_values = pd.Series(predictions_O3[0].flatten()) |
|
no2_future_values = pd.Series(predictions_NO2[0].flatten()) |
|
o3_values = pd.concat([o3_past_values, o3_future_values], ignore_index=True) |
|
no2_values = pd.concat([no2_past_values, no2_future_values], ignore_index=True) |
|
|
|
dates = dates_past + dates_future |
|
df = pd.DataFrame({"Date": dates, "O3": o3_values, "NO2": no2_values}) |
|
|
|
|
|
st.title("Utrecht Pollution Dashboard 🌱") |
|
|
|
col1, col2 = st.columns((1, 3)) |
|
|
|
with col1: |
|
st.subheader("Current Weather") |
|
|
|
|
|
custom_metric_box( |
|
label="Temperature", |
|
value=f"{round(today['mean_temp'] * 0.1)} °C", |
|
) |
|
custom_metric_box( |
|
label="Humidity", |
|
value=f"{round(today['humidity'])} %", |
|
) |
|
custom_metric_box( |
|
label="Pressure", |
|
value=f"{round(today['pressure'] * 0.1)} hPa", |
|
) |
|
|
|
custom_metric_box( |
|
label="Precipitation", |
|
value=f"{round(today['percipitation'] * 0.1)} mm", |
|
) |
|
custom_metric_box( |
|
label="Solar Radiation", |
|
value=f"{round(today['global_radiation'])} J/m²", |
|
) |
|
custom_metric_box( |
|
label="Wind Speed", |
|
value=f"{round(today['wind_speed'] * 0.1, 1)} m/s", |
|
) |
|
|
|
with col2: |
|
st.subheader("Current Pollution Levels") |
|
sub1, sub2 = st.columns((1, 1)) |
|
|
|
|
|
with sub1: |
|
pollution_box( |
|
label="O<sub>3</sub>", |
|
value=f"{round(today['O3'])} µg/m³", |
|
delta=f"{round(int(today['O3']) - int(previous_day['O3']))} µg/m³", |
|
threshold=120 |
|
) |
|
with st.expander("Learn more about O3", expanded=False): |
|
st.markdown( |
|
""" |
|
*Ozone (O<sub>3</sub>)*: A harmful gas at ground level that can irritate the respiratory system and aggravate asthma.<br> |
|
**Good/Bad**: "Good" means safe levels for most people, while "Bad" suggests harmful levels, especially for sensitive groups. |
|
""", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
with sub2: |
|
pollution_box( |
|
label="NO<sub>2</sub>", |
|
value=f"{round(today['NO2'])} µg/m³", |
|
delta=f"{round(int(today['NO2']) - int(previous_day['NO2']))} µg/m³", |
|
threshold=40 |
|
) |
|
with st.expander("Learn more about NO2", expanded=False): |
|
st.markdown( |
|
""" |
|
*Nitrogen Dioxide (NO<sub>2</sub>)*: A toxic gas that contributes to lung irritation and worsens asthma and other respiratory issues.<br> |
|
**Good/Bad**: "Good" means safe air quality, while "Bad" indicates levels that could cause respiratory problems, especially for vulnerable individuals. |
|
""", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
|
|
st.subheader("O3 Forecast") |
|
|
|
|
|
def get_simple_color_scale(values, threshold): |
|
"""Returns green for values below the threshold, orange for values between the threshold and 2x the threshold, and red for values above 2x the threshold.""" |
|
return [ |
|
"#77C124" if v < threshold else |
|
"#E68B0A" if v < 2 * threshold else |
|
"#E63946" for v in values |
|
] |
|
|
|
|
|
o3_colors = get_simple_color_scale(o3_values, 40) |
|
|
|
fig_o3 = go.Figure() |
|
fig_o3.add_trace( |
|
go.Bar( |
|
x=df["Date"], |
|
y=df["O3"], |
|
name="O3", |
|
marker=dict(color=o3_colors), |
|
hovertemplate="%{x|%d-%b-%Y}<br>%{y} µg/m³<extra></extra>", |
|
) |
|
) |
|
fig_o3.add_shape( |
|
dict( |
|
type="line", |
|
x0=pd.Timestamp.today(), |
|
x1=pd.Timestamp.today(), |
|
y0=min(o3_values), |
|
y1=max(o3_values), |
|
line=dict(color="White", width=3, dash="dash"), |
|
) |
|
) |
|
fig_o3.update_layout( |
|
plot_bgcolor="rgba(0, 0, 0, 0)", |
|
paper_bgcolor="rgba(0, 0, 0, 0)", |
|
yaxis_title="O3 Concentration (µg/m³)", |
|
font=dict(size=14), |
|
hovermode="x", |
|
xaxis=dict( |
|
title="Date", |
|
type="date", |
|
tickmode="array", |
|
tickvals=df["Date"], |
|
tickformat="%d-%b", |
|
tickangle=-45, |
|
tickcolor="gray", |
|
), |
|
) |
|
st.plotly_chart(fig_o3, key="fig_o3") |
|
|
|
|
|
no2_colors = get_simple_color_scale(no2_values, 120) |
|
st.subheader("NO2 Forecast") |
|
fig_no2 = go.Figure() |
|
fig_no2.add_trace( |
|
go.Bar( |
|
x=df["Date"], |
|
y=df["NO2"], |
|
name="NO2", |
|
marker=dict(color=no2_colors), |
|
hovertemplate="%{x|%d-%b-%Y}<br>%{y} µg/m³<extra></extra>", |
|
) |
|
) |
|
fig_no2.add_shape( |
|
dict( |
|
type="line", |
|
x0=pd.Timestamp.today(), |
|
x1=pd.Timestamp.today(), |
|
y0=min(no2_values), |
|
y1=max(no2_values), |
|
line=dict(color="White", width=3, dash="dash"), |
|
) |
|
) |
|
fig_no2.update_layout( |
|
plot_bgcolor="rgba(0, 0, 0, 0)", |
|
paper_bgcolor="rgba(0, 0, 0, 0)", |
|
yaxis_title="NO<sub>2</sub> Concentration (µg/m³)", |
|
font=dict(size=14), |
|
hovermode="x", |
|
xaxis=dict( |
|
title="Date", |
|
type="date", |
|
tickmode="array", |
|
tickvals=df["Date"], |
|
tickformat="%d-%b", |
|
tickangle=-45, |
|
tickcolor="gray", |
|
), |
|
) |
|
st.plotly_chart(fig_no2, key="fig_no2") |
|
|
|
import matplotlib.pyplot as plt |
|
import numpy as np |
|
|
|
fig, ax = plt.subplots() |
|
|
|
bar = ax.bar([1,2,3,4,5,6],[4,5,6,3,7,5]) |
|
|
|
def gradientbars(bars): |
|
grad = np.atleast_2d(np.linspace(0,1,256)).T |
|
ax = bars[0].axes |
|
lim = ax.get_xlim()+ax.get_ylim() |
|
for bar in bars: |
|
bar.set_zorder(1) |
|
bar.set_facecolor("none") |
|
x,y = bar.get_xy() |
|
w, h = bar.get_width(), bar.get_height() |
|
ax.imshow(grad, extent=[x,x+w,y,y+h], aspect="auto", zorder=0) |
|
ax.axis(lim) |
|
|
|
gradientbars(bar) |
|
|
|
plt.show() |
|
|