Spaces:
Runtime error
Runtime error
import streamlit as st | |
import pandas as pd | |
import plotly.express as px | |
import plotly.graph_objects as go | |
import folium | |
from folium import LinearColormap | |
import requests | |
from datetime import datetime, timedelta | |
from streamlit_folium import st_folium | |
# Set page layout to wide | |
st.set_page_config(layout="wide", page_title="Real-Time Relative Humidity Data Dashboard") | |
# Function to load data | |
# Cache data to avoid reloading every time | |
def load_data(): | |
with st.spinner("Loading data..."): | |
response = requests.get("https://csdi.vercel.app/weather/rhum") | |
data = response.json() | |
features = data['features'] | |
df = pd.json_normalize(features) | |
df.rename(columns={ | |
'properties.Relative Humidity(percent)': 'Relative Humidity (%)', | |
'properties.Automatic Weather Station': 'Station Name', | |
'geometry.coordinates': 'Coordinates' | |
}, inplace=True) | |
return df | |
# Check if the data has been loaded before | |
if 'last_run' not in st.session_state or (datetime.now() - st.session_state.last_run) > timedelta(minutes=5): | |
st.session_state.df = load_data() | |
st.session_state.last_run = datetime.now() | |
# Data | |
df = st.session_state.df | |
# Compute statistics | |
humidity_data = df['Relative Humidity (%)'] | |
avg_humidity = humidity_data.mean() | |
max_humidity = humidity_data.max() | |
min_humidity = humidity_data.min() | |
std_humidity = humidity_data.std() | |
# Create three columns | |
col1, col2, col3 = st.columns([1.65, 2, 1.15]) | |
# Column 1: Histogram and statistics | |
with col1: | |
# Define colors for gradient | |
color_scale = ['#58a0db', '#0033cc'] | |
# Create histogram | |
fig = px.histogram(df, x='Relative Humidity (%)', nbins=20, | |
labels={'Relative Humidity (%)': 'Relative Humidity (%)'}, | |
title='Relative Humidity Histogram', | |
color_discrete_sequence=color_scale) | |
# Add average line | |
fig.add_shape( | |
go.layout.Shape( | |
type="line", | |
x0=avg_humidity, | |
y0=0, | |
x1=avg_humidity, | |
y1=df['Relative Humidity (%)'].value_counts().max(), | |
line=dict(color="red", width=2, dash="dash"), | |
) | |
) | |
# Update layout | |
fig.update_layout( | |
xaxis_title='Relative Humidity (%)', | |
yaxis_title='Count', | |
title='Relative Humidity Distribution', | |
bargap=0.2, | |
title_font_size=20, | |
xaxis_title_font_size=14, | |
yaxis_title_font_size=14, | |
height=350, | |
shapes=[{ | |
'type': 'rect', | |
'x0': min_humidity, | |
'x1': max_humidity, | |
'y0': 0, | |
'y1': df['Relative Humidity (%)'].value_counts().max(), | |
'fillcolor': 'rgba(0, 100, 255, 0.2)', | |
'line': { | |
'color': 'rgba(0, 100, 255, 0.2)', | |
'width': 0 | |
}, | |
'opacity': 0.1 | |
}] | |
) | |
# Add annotations | |
fig.add_annotation( | |
x=avg_humidity, | |
y=df['Relative Humidity (%)'].value_counts().max() * 0.9, | |
text=f"Average: {avg_humidity:.2f}%", | |
showarrow=True, | |
arrowhead=1 | |
) | |
st.plotly_chart(fig, use_container_width=True) | |
# Display statistics | |
col_1, col_2 = st.columns([1, 1]) | |
with col_1: | |
st.metric(label="Average R.Humidity (%)", value=f"{avg_humidity:.2f}") | |
st.metric(label="Minimum R.Humidity (%)", value=f"{min_humidity:.2f}") | |
with col_2: | |
st.metric(label="Maximum R.Humidity (%)", value=f"{max_humidity:.2f}") | |
st.metric(label="Std. Dev (%)", value=f"{std_humidity:.2f}") | |
# Function to convert humidity to color based on gradient | |
def humidity_to_color(humidity, min_humidity, max_humidity): | |
norm_humidity = (humidity - min_humidity) / (max_humidity - min_humidity) | |
if norm_humidity < 0.5: | |
r = int(173 + (0 - 173) * (2 * norm_humidity)) | |
g = int(216 + (0 - 216) * (2 * norm_humidity)) | |
b = int(230 + (255 - 230) * (2 * norm_humidity)) | |
else: | |
r = int(0 + (0 - 0) * (2 * (norm_humidity - 0.5))) | |
g = int(0 + (0 - 0) * (2 * (norm_humidity - 0.5))) | |
b = int(255 + (0 - 255) * (2 * (norm_humidity - 0.5))) | |
return f'rgb({r}, {g}, {b})' | |
# Column 2: Map | |
with col2: | |
with st.spinner("Loading map..."): | |
m = folium.Map(location=[22.3547, 114.1483], zoom_start=11, tiles='CartoDB positron') | |
min_humidity = df['Relative Humidity (%)'].min() | |
max_humidity = df['Relative Humidity (%)'].max() | |
colormap = LinearColormap( | |
colors=['#58a0db', 'blue'], | |
index=[min_humidity, max_humidity], | |
vmin=min_humidity, | |
vmax=max_humidity, | |
caption='Relative Humidity (%)' | |
) | |
colormap.add_to(m) | |
for _, row in df.iterrows(): | |
humidity = row['Relative Humidity (%)'] | |
color = humidity_to_color(humidity, min_humidity, max_humidity) | |
folium.Marker( | |
location=[row['Coordinates'][1], row['Coordinates'][0]], | |
popup=f"<p style='font-size: 12px; background-color: white; padding: 5px; border-radius: 5px;'>{row['Station Name']}: {humidity:.1f}%</p>", | |
icon=folium.DivIcon( | |
html=f'<div style="font-size: 10pt; color: {color}; padding: 2px; border-radius: 5px;">' | |
f'<strong>{humidity:.1f}%</strong></div>' | |
) | |
).add_to(m) | |
st_folium(m, width=500, height=600) | |
# Column 3: Data Table | |
with col3: | |
st.markdown( | |
""" | |
<style> | |
.dataframe-container { | |
height: 600px; | |
overflow-y: auto; | |
} | |
.dataframe th, .dataframe td { | |
text-align: left; | |
padding: 8px; | |
} | |
</style> | |
""", | |
unsafe_allow_html=True | |
) | |
# Rename column for display | |
df_display = df[['Station Name', 'Relative Humidity (%)']].rename(columns={'Relative Humidity (%)': 'R.Humidity'}) | |
st.dataframe(df_display, height=600) | |
# Refresh Button | |
if st.button("Refresh Data"): | |
with st.spinner("Refreshing data..."): | |
st.session_state.df = load_data() | |
st.session_state.last_run = datetime.now() | |
st.experimental_rerun() | |