Initial commit: Shelly Manager with Textual CLI, Streamlit UI, and comprehensive .gitignore
Shelly device management app with mDNS/subnet discovery, inventory, configuration, and mass operations for Gen1/Gen2+ devices. Includes .gitignore excluding runtime data (device DB, user config), AI conversation history, build artifacts, and common Python/OS patterns.
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "dashboard-seattle-weather"
|
||||
version = "1.0.0"
|
||||
description = "An example dashboard exploring the Seattle Weather dataset"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"altair>=5.5.0",
|
||||
"pandas>=2.2.3",
|
||||
"snowflake-connector-python>=3.3.0",
|
||||
"streamlit[snowflake]>=1.54.0",
|
||||
"vega-datasets>=0.9.0",
|
||||
]
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
import streamlit as st
|
||||
import altair as alt
|
||||
import vega_datasets
|
||||
|
||||
|
||||
full_df = vega_datasets.data("seattle_weather")
|
||||
|
||||
st.set_page_config(
|
||||
# Title and icon for the browser's tab bar:
|
||||
page_title="Seattle Weather",
|
||||
page_icon=":mostly_sunny:",
|
||||
# Make the content take up the width of the page:
|
||||
layout="wide",
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
# Seattle Weather
|
||||
|
||||
Let's explore the [classic Seattle Weather
|
||||
dataset](https://altair-viz.github.io/case_studies/exploring-weather.html)!
|
||||
"""
|
||||
|
||||
"" # Add a little vertical space. Same as st.write("").
|
||||
""
|
||||
|
||||
"""
|
||||
## 2015 Summary
|
||||
"""
|
||||
|
||||
""
|
||||
|
||||
df_2015 = full_df[full_df["date"].dt.year == 2015]
|
||||
df_2014 = full_df[full_df["date"].dt.year == 2014]
|
||||
|
||||
max_temp_2015 = df_2015["temp_max"].max()
|
||||
max_temp_2014 = df_2014["temp_max"].max()
|
||||
|
||||
min_temp_2015 = df_2015["temp_min"].min()
|
||||
min_temp_2014 = df_2014["temp_min"].min()
|
||||
|
||||
max_wind_2015 = df_2015["wind"].max()
|
||||
max_wind_2014 = df_2014["wind"].max()
|
||||
|
||||
min_wind_2015 = df_2015["wind"].min()
|
||||
min_wind_2014 = df_2014["wind"].min()
|
||||
|
||||
max_prec_2015 = df_2015["precipitation"].max()
|
||||
max_prec_2014 = df_2014["precipitation"].max()
|
||||
|
||||
min_prec_2015 = df_2015["precipitation"].min()
|
||||
min_prec_2014 = df_2014["precipitation"].min()
|
||||
|
||||
|
||||
with st.container(horizontal=True, gap="medium"):
|
||||
cols = st.columns(2, gap="medium", width=300)
|
||||
|
||||
with cols[0]:
|
||||
st.metric(
|
||||
"Max temperature",
|
||||
f"{max_temp_2015:0.1f}C",
|
||||
delta=f"{max_temp_2015 - max_temp_2014:0.1f}C",
|
||||
width="content",
|
||||
)
|
||||
|
||||
with cols[1]:
|
||||
st.metric(
|
||||
"Min temperature",
|
||||
f"{min_temp_2015:0.1f}C",
|
||||
delta=f"{min_temp_2015 - min_temp_2014:0.1f}C",
|
||||
width="content",
|
||||
)
|
||||
|
||||
cols = st.columns(2, gap="medium", width=300)
|
||||
|
||||
with cols[0]:
|
||||
st.metric(
|
||||
"Max precipitation",
|
||||
f"{max_prec_2015:0.1f}mm",
|
||||
delta=f"{max_prec_2015 - max_prec_2014:0.1f}mm",
|
||||
width="content",
|
||||
)
|
||||
|
||||
with cols[1]:
|
||||
st.metric(
|
||||
"Min precipitation",
|
||||
f"{min_prec_2015:0.1f}mm",
|
||||
delta=f"{min_prec_2015 - min_prec_2014:0.1f}mm",
|
||||
width="content",
|
||||
)
|
||||
|
||||
cols = st.columns(2, gap="medium", width=300)
|
||||
|
||||
with cols[0]:
|
||||
st.metric(
|
||||
"Max wind",
|
||||
f"{max_wind_2015:0.1f}m/s",
|
||||
delta=f"{max_wind_2015 - max_wind_2014:0.1f}m/s",
|
||||
width="content",
|
||||
)
|
||||
|
||||
with cols[1]:
|
||||
st.metric(
|
||||
"Min wind",
|
||||
f"{min_wind_2015:0.1f}m/s",
|
||||
delta=f"{min_wind_2015 - min_wind_2014:0.1f}m/s",
|
||||
width="content",
|
||||
)
|
||||
|
||||
weather_icons = {
|
||||
"sun": "sunny",
|
||||
"snow": "weather_snowy",
|
||||
"rain": "rainy",
|
||||
"fog": "foggy",
|
||||
"drizzle": "rainy",
|
||||
}
|
||||
|
||||
cols = st.columns(2, gap="large")
|
||||
|
||||
with cols[0]:
|
||||
weather_name = (
|
||||
full_df["weather"].value_counts().head(1).reset_index()["weather"][0]
|
||||
)
|
||||
st.metric(
|
||||
"Most common weather",
|
||||
f":material/{weather_icons[weather_name]}: {weather_name.upper()}",
|
||||
)
|
||||
|
||||
with cols[1]:
|
||||
weather_name = (
|
||||
full_df["weather"].value_counts().tail(1).reset_index()["weather"][0]
|
||||
)
|
||||
st.metric(
|
||||
"Least common weather",
|
||||
f":material/{weather_icons[weather_name]}: {weather_name.upper()}",
|
||||
)
|
||||
|
||||
""
|
||||
""
|
||||
|
||||
"""
|
||||
## Compare different years
|
||||
"""
|
||||
|
||||
YEARS = full_df["date"].dt.year.unique()
|
||||
selected_years = st.pills(
|
||||
"Years to compare", YEARS, default=YEARS, selection_mode="multi"
|
||||
)
|
||||
|
||||
if not selected_years:
|
||||
st.warning("You must select at least 1 year.", icon=":material/warning:")
|
||||
|
||||
df = full_df[full_df["date"].dt.year.isin(selected_years)]
|
||||
|
||||
cols = st.columns([3, 1])
|
||||
|
||||
with cols[0].container(border=True, height="stretch"):
|
||||
"### 🌡️ Temperature"
|
||||
|
||||
st.altair_chart(
|
||||
alt.Chart(df)
|
||||
.mark_bar(width=1)
|
||||
.encode(
|
||||
alt.X("monthdate(date):T").title("date"),
|
||||
alt.Y("temp_max:Q").title("temperature range (C)"),
|
||||
alt.Y2("temp_min:Q"),
|
||||
alt.Color("year(date):N").title("year"),
|
||||
alt.XOffset("year(date):N"),
|
||||
tooltip=[
|
||||
alt.Tooltip("monthdate(date):T", title="Date"),
|
||||
alt.Tooltip("temp_max:Q", title="Max Temp (C)"),
|
||||
alt.Tooltip("temp_min:Q", title="Min Temp (C)"),
|
||||
alt.Tooltip("year(date):N", title="Year"),
|
||||
],
|
||||
)
|
||||
.configure_legend(orient="bottom")
|
||||
)
|
||||
|
||||
with cols[1].container(border=True, height="stretch"):
|
||||
"### Weather distribution"
|
||||
|
||||
st.altair_chart(
|
||||
alt.Chart(df)
|
||||
.mark_arc()
|
||||
.encode(
|
||||
alt.Theta("count()"),
|
||||
alt.Color("weather:N"),
|
||||
)
|
||||
.configure_legend(orient="bottom")
|
||||
)
|
||||
|
||||
|
||||
cols = st.columns(2)
|
||||
|
||||
with cols[0].container(border=True, height="stretch"):
|
||||
"### 💨 Wind"
|
||||
|
||||
# Prepare data for st.line_chart - pivot by year
|
||||
wind_df = df.copy()
|
||||
wind_df["month_day"] = wind_df["date"].dt.strftime("%m-%d")
|
||||
wind_df["year"] = wind_df["date"].dt.year
|
||||
|
||||
# Calculate 14-day rolling average per year
|
||||
wind_pivot = wind_df.pivot_table(
|
||||
index="month_day",
|
||||
columns="year",
|
||||
values="wind",
|
||||
aggfunc="mean"
|
||||
).sort_index()
|
||||
|
||||
st.line_chart(wind_pivot, height=300)
|
||||
|
||||
with cols[1].container(border=True, height="stretch"):
|
||||
"### 🌧️ Precipitation"
|
||||
|
||||
st.altair_chart(
|
||||
alt.Chart(df)
|
||||
.mark_bar()
|
||||
.encode(
|
||||
alt.X("month(date):O").title("month"),
|
||||
alt.Y("sum(precipitation):Q").title("precipitation (mm)"),
|
||||
alt.Color("year(date):N").title("year"),
|
||||
tooltip=[
|
||||
alt.Tooltip("month(date):O", title="Month"),
|
||||
alt.Tooltip("sum(precipitation):Q", title="Precipitation (mm)"),
|
||||
alt.Tooltip("year(date):N", title="Year"),
|
||||
],
|
||||
)
|
||||
.configure_legend(orient="bottom")
|
||||
)
|
||||
|
||||
cols = st.columns(2)
|
||||
|
||||
with cols[0].container(border=True, height="stretch"):
|
||||
"### Monthly weather breakdown"
|
||||
""
|
||||
|
||||
st.altair_chart(
|
||||
alt.Chart(df)
|
||||
.mark_bar()
|
||||
.encode(
|
||||
alt.X("month(date):O", title="month"),
|
||||
alt.Y("count():Q", title="days").stack("normalize"),
|
||||
alt.Color("weather:N"),
|
||||
)
|
||||
.configure_legend(orient="bottom")
|
||||
)
|
||||
|
||||
with cols[1].container(border=True, height="stretch"):
|
||||
"### Raw data"
|
||||
|
||||
st.dataframe(df)
|
||||
Reference in New Issue
Block a user