Skip to content

Commit

Permalink
feat: add time span filters to historical and aggregated data
Browse files Browse the repository at this point in the history
  • Loading branch information
unmonoqueteclea committed Oct 12, 2024
1 parent d884a3d commit f64ebdf
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 31 deletions.
2 changes: 1 addition & 1 deletion ui/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "valencianow"
version = "0.1.0"
version = "0.2.0"
requires-python = ">=3.12"
dependencies = [
"streamlit>=1.32.2,<2",
Expand Down
35 changes: 22 additions & 13 deletions ui/src/valencianow/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,35 @@

def aggregated_sensor_data(data_now: pd.DataFrame, label: str) -> None:
info = data.PIPES[label]
st.markdown("## ➕ individual sensor data")
st.markdown("## ➕ Individual sensor data")
with st.form(f"aggregated-sensor-{label}"):
sensor = st.selectbox(
"🔢 Select a sensor to show its data (sensor numbers in map tooltips)",
"🔢 Select a sensor to show its data (sensor ids in map tooltips)",
sorted(data_now.sensor.values),
)
timespan = st.radio(
"Select a time span: ",
["Today", "Last Week", "Last Month", "Last Year"],
index=2,
horizontal=True,
)

if st.form_submit_button("🔎 Find sensor data", use_container_width=True):
components.historical_graph(
info["hist_pipe"], sensor, info["hist_meas"], info["hist_y"]
info["hist_pipe"], timespan, sensor, info["hist_meas"], info["hist_y"]
)
st.markdown("#### aggregated data")
sensor_col_1, sensor_col_2 = st.columns(2)
with sensor_col_1:
components.per_day_graph(
info["per_day_pipe"], sensor, info["per_day_y"]
)
with sensor_col_2:
components.per_day_of_week_graph(
info["per_dow_pipe"], sensor, info["per_dow_y"]
)
if timespan != "Today":
st.markdown(f"#### Aggregated data ({timespan})")
sensor_col_1, sensor_col_2 = st.columns(2)
with sensor_col_1:
components.per_day_graph(
info["per_day_pipe"], sensor, timespan, info["per_day_y"]
)
if timespan != "Last Week":
with sensor_col_2:
components.per_day_of_week_graph(
info["per_dow_pipe"], sensor, timespan, info["per_dow_y"]
)


def render_tab_car(tab) -> None:
Expand Down
42 changes: 32 additions & 10 deletions ui/src/valencianow/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,46 @@ def reset_date_filter(date: str | None, reset) -> str | None:
return date


def historical_graph(pipe: str, sensor: str, measurement: str, y_axis: str) -> None:
data_sensor = data.load_data(pipe, None, sensor)
def historical_graph(
pipe: str, timespan: str, sensor: str, measurement: str, y_axis: str
) -> None:
data_sensor = data.load_data(pipe, None, sensor, filter_timespan=timespan)
if data_sensor is not None:
st.markdown(f"#### historical data: {measurement}")
st.markdown(f"#### Historical data: {measurement} ({timespan})")
data_sensor = data_sensor.sort_values(by="datetime")
fig = px.line(data_sensor, x="datetime", y=y_axis, markers=True)
fig = px.line(
data_sensor, x="datetime", y=y_axis, markers=True, line_shape="spline"
)
st.plotly_chart(fig, theme="streamlit", use_container_width=True)


def per_day_graph(pipe: str, sensor: str, y_axis):
st.markdown("**📅 data by day**")
data_agg_sensor = data.load_data(pipe, None, sensor)
fig = px.bar(data_agg_sensor, x="day", y=y_axis)
def per_day_graph(pipe: str, sensor: str, timespan: str, y_axis):
st.markdown("**📅 Data by day**")
data_agg_sensor = data.load_data(pipe, None, sensor, filter_timespan=timespan)
fig = px.bar(
data_agg_sensor,
x="day",
y=y_axis,
hover_data={"day": "|%A - %B %d, %Y"},
)
fig.update_xaxes(tickformat="%a - %b %d")
st.plotly_chart(fig, theme="streamlit", use_container_width=True)


def per_day_of_week_graph(pipe: str, sensor: str, y_axis):
st.markdown("**📅 data by day of week (1 is Monday)**")
def per_day_of_week_graph(pipe: str, sensor: str, timespan: str, y_axis):
st.markdown("**📅 Data by day of week**")
data_agg_week_sensor = data.load_data(pipe, None, sensor)
day_name_map = {
1: "Monday",
2: "Tuesday",
3: "Wednesday",
4: "Thursday",
5: "Friday",
6: "Saturday",
7: "Sunday",
}
data_agg_week_sensor["day_of_week"] = data_agg_week_sensor["day_of_week"].map(
day_name_map
)
fig = px.bar(data_agg_week_sensor, x="day_of_week", y=y_axis)
st.plotly_chart(fig, theme="streamlit", use_container_width=True)
2 changes: 1 addition & 1 deletion ui/src/valencianow/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
LOGGER.addHandler(logger_handler)


APP_NAME = "valencia-now"
APP_NAME = "Valencia-Now"

TINYBIRD_API = "https://api.tinybird.co/v0/pipes/"
TINYBIRD_TOKEN = os.environ["TINYBIRD_TOKEN_VLC"]
Expand Down
22 changes: 21 additions & 1 deletion ui/src/valencianow/data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import urllib.parse
from datetime import datetime
from datetime import datetime, timedelta, timezone

# Streamlit Cloud won't install the package, so we can't do:
# from valencianow import config
Expand Down Expand Up @@ -70,12 +70,26 @@ def _date_to_utc(date: str) -> str:
return utc_datetime.strftime("%Y-%m-%d %H:%M:%S")


def _min_date(current_date: datetime, timespan: str) -> str:
output = current_date
if timespan == "Today":
output -= timedelta(days=1)
elif timespan == "Last Week":
output -= timedelta(days=7)
elif timespan == "Last Month":
output -= timedelta(days=31)
elif timespan == "Last Year":
output -= timedelta(days=365)
return output.strftime("%Y-%m-%d %H:%M:%S")


# caching data for some time to reduce the number of Tinybird API hits
@st.cache_data(ttl=config.DATA_CACHE_SECONDS)
def load_data(
pipe_name: str, # the name of the Tinybird PIPE
filter_max_date: str | None,
filter_sensor: int | None = None,
filter_timespan: str | None = None,
local_time: bool = False,
) -> pd.DataFrame | None:
"""Load data from the given Tinybird pipe name.
Expand All @@ -88,6 +102,12 @@ def load_data(
if not local_time:
filter_max_date = _date_to_utc(filter_max_date)
params["date"] = filter_max_date
if filter_timespan:
if filter_max_date:
max_date = datetime.strptime(filter_max_date, "%Y-%m-%d %H:%M:%S")
else:
max_date = datetime.now(timezone.utc)
params["min_date"] = _min_date(max_date, filter_timespan)
if filter_sensor:
params["sensor"] = filter_sensor
logger.info(f"Retrieving {pipe_name} data from Tinybird: {params}")
Expand Down
9 changes: 4 additions & 5 deletions ui/src/valencianow/maps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""functions to build all the maps shown in the application
"""functions to build all the maps shown in the application"""

"""
import pandas as pd
import pydeck as pdk
import streamlit as st
Expand Down Expand Up @@ -46,8 +45,8 @@ def traffic_now_elevation(data: pd.DataFrame, is_bike=False) -> None:
max_ih = MAX_IH_BIKE if is_bike else MAX_IH_CAR
label = LABEL_BIKE if is_bike else LABEL_CAR
scale = 5 if is_bike else 0.5
tooltip = "🔢 sensor id: {sensor} \n⏱" + label + "s/hour: {ih}"
tooltip += "\n📅 updated: {date}"
tooltip = "🔢 Sensor id: {sensor} \n " + label.capitalize() + "s/hour: {ih}"
tooltip += "\n📅 Updated: {date}"
return pdk.Deck(
# map_style=None, # type: ignore
map_style=pdk.map_styles.SATELLITE,
Expand Down Expand Up @@ -94,7 +93,7 @@ def air_now_scatterplot(data: pd.DataFrame):
1: [162, 91, 164],
} # type: ignore
)
tooltip = "🔢 sensor: {sensor} \n 🍃 ICA: {ica} \n 📅 updated: {date}"
tooltip = "🔢 Sensor: {sensor} \n 🍃 ICA: {ica} \n 📅 Updated: {date}"
return pdk.Deck(
map_style=pdk.map_styles.SATELLITE,
map_provider="mapbox",
Expand Down

0 comments on commit f64ebdf

Please sign in to comment.