Skip to content
This repository was archived by the owner on Sep 29, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pems_data/src/pems_data/services/stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def get_district_metadata(self, district_number: str) -> pd.DataFrame:
cache_opts = {"key": self._build_cache_key("metadata", "district", district_number), "ttl": 3600} # 1 hour
columns = [
"STATION_ID",
"CONTROLLER_ID",
"NAME",
"PHYSICAL_LANES",
"STATE_POSTMILE",
Expand Down
44 changes: 25 additions & 19 deletions pems_streamlit/src/pems_streamlit/apps/districts/app_stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

from pems_data import ServiceFactory

from pems_streamlit.components.map_station_summary import map_station_summary
from pems_streamlit.components.map_summary import map_district_summary, map_station_summary
from pems_streamlit.components.plot_5_min_traffic_data import plot_5_min_traffic_data

FACTORY = ServiceFactory()
STATIONS = FACTORY.stations_service()
S3 = FACTORY.s3_source

st.set_page_config(layout="wide")


@st.cache_data(ttl=3600) # Cache for 1 hour
def load_station_metadata(district_number: str) -> pd.DataFrame:
Expand Down Expand Up @@ -51,34 +53,38 @@ def main():

df_station_metadata = load_station_metadata(district_number)

map_placeholder = st.empty()

station = st.selectbox(
"Station",
df_station_metadata["STATION_ID"],
)
col1, col2 = st.columns([0.25, 0.75])

quantity = st.multiselect("Quantity", ["VOLUME_SUM", "OCCUPANCY_AVG", "SPEED_FIVE_MINS"])
with col1:
station = st.selectbox("Station", df_station_metadata["STATION_ID"], index=None)
lane = None
if station:
num_lanes = int(df_station_metadata[df_station_metadata["STATION_ID"] == station]["PHYSICAL_LANES"].iloc[0])
lane = st.multiselect(
"Lane",
list(range(1, num_lanes + 1)),
)
quantity = st.multiselect("Quantity", ["VOLUME_SUM", "OCCUPANCY_AVG", "SPEED_FIVE_MINS"])
days = st.multiselect("Days", get_available_days())
station_data_button = st.button("Load Station Data", type="primary")

num_lanes = int(df_station_metadata[df_station_metadata["STATION_ID"] == station]["PHYSICAL_LANES"].iloc[0])
lane = st.multiselect(
"Lane",
list(range(1, num_lanes + 1)),
)
with col2:
map_placeholder = st.empty()

with map_placeholder:
df_selected_station = df_station_metadata.query("STATION_ID == @station")
map_station_summary(df_selected_station)

days = st.multiselect("Days", get_available_days())

station_data_button = st.button("Load Station Data", type="primary")
if station:
df_selected_station = df_station_metadata.query("STATION_ID == @station")
map_station_summary(df_selected_station)
else:
map_district_summary(df_station_metadata)

error_placeholder = st.empty()
plot_placeholder = st.empty()

if station_data_button:
error_messages = []
if not station:
error_messages.append("- Please select a station to proceed.")
if len(quantity) == 0 or len(quantity) > 2:
error_messages.append("- Please select one or two quantities to proceed.")
if not lane:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@
import streamlit as st


def map_district_summary(df_station_metadata: pd.DataFrame):

map_col, info_col = st.columns([0.6, 0.4])

with map_col:
map_df = df_station_metadata.rename(columns={"LATITUDE": "latitude", "LONGITUDE": "longitude"})
map_df_cleaned = map_df.dropna(subset=["latitude", "longitude"])
st.map(map_df_cleaned[["latitude", "longitude"]], height=265)

with info_col:
with st.container(border=True):
st.markdown(f"**Directional Distance** {df_station_metadata['LENGTH'].sum().round(1)} miles")
st.markdown(f"**Freeways** {df_station_metadata['FREEWAY'].nunique()}")
st.markdown(f"**Stations** {df_station_metadata['STATION_ID'].nunique()}")
st.markdown(f"**Controllers** {df_station_metadata['CONTROLLER_ID'].nunique()}")


def map_station_summary(df_station_metadata: pd.DataFrame):

map_col, info_col = st.columns([0.6, 0.4])
Expand Down
16 changes: 8 additions & 8 deletions pems_web/src/pems_web/core/templates/core/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<header role="banner" id="header" class="global-header fixed">
<!-- Utility header structural component -->
<div class="utility-header">
<div class="container">
<div class="container-fluid">
<div class="flex-row">
<div class="social-media-links">
<div class="header-cagov-logo">
Expand All @@ -54,7 +54,7 @@
</div>
<!-- header branding with light gray background -->
<div class="section-default">
<div class="branding">
<div class="branding container-fluid">
<div class="header-organization-banner">
<a href="{% url 'core:index' %}">
<div class="logo-assets">
Expand Down Expand Up @@ -84,7 +84,7 @@
</div>
</div>
<!-- Top Level Navigation Only -->
<div class="navigation-search full-width-nav container">
<div class="navigation-search full-width-nav container-fluid">
<div id="head-search" class="search-container featured-search">
<div class="d-block d-lg-none">
<a href="{% url 'core:index' %}" class="drawer-logo-link first-level-link">
Expand All @@ -94,7 +94,7 @@
</a>
</div>
</div>
<nav id="navigation" class="main-navigation singlelevel" aria-label="Main navigation">
<nav id="navigation" class="main-navigation container-fluid singlelevel" aria-label="Main navigation">
<ul id="nav_list" class="top-level-nav">
<li class="nav-item">
<a href="{% url 'core:index' %}" class="first-level-link">Home</a>
Expand All @@ -113,9 +113,9 @@
</div>
</header>
<div id="main-content" class="main-content">
<div class="container">
<div class="container-fluid">
<main class="main-primary">
<h1>
<h1 class="m-y-md">
{% block headline %}
{% endblock headline %}
</h1>
Expand All @@ -126,7 +126,7 @@ <h1>
</div>
<!-- Global Footer -->
<footer id="footer" class="global-footer">
<div class="container">
<div class="container-fluid">
<div class="d-flex">
<a href="https://www.ca.gov" class="cagov-logo">
<span class="sr-only">CA.gov</span>
Expand All @@ -152,7 +152,7 @@ <h1>
</div>
<!-- Copyright Statement -->
<div class="copyright">
<div class="container text-right">
<div class="container-fluid text-right">
<span aria-hidden="true">©</span>
<span id="thisyear">
<script>document.getElementById('thisyear').appendChild(document.createTextNode(new Date().getFullYear()))</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% endblock headline %}

{% block districts-content %}
<div class="row" style="min-height: 450px;">
<div class="row min-vh-100">
<div class="col-lg-12">
<iframe title="District {{ current_district.number }} visualization"
class="w-100 h-100"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% endblock headline %}

{% block inner-content %}
<div class="container p-t-lg">
<div class="container-fluid p-t-xs">
<div class="row">
<div class="col-lg-2 pb-lg-5" role="complementary">
{% block sidebar %}
Expand All @@ -15,7 +15,7 @@
<div class="col-lg-10 pb-lg-5">
{% block districts-content %}
<div class="row" style="min-height: 450px;">
<div class="col-lg-12">
<div class="col-lg-12 min-vh-100">
<iframe title="District visualizations" class="w-100 h-100" src="{{ streamlit.url }}/districts--stations?embed=true">
</iframe>
</div>
Expand Down
5 changes: 5 additions & 0 deletions pems_web/src/pems_web/static/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ header {
}
}
}

.main-navigation.container-fluid,
.branding.container-fluid {
max-width: 100% !important;
}
1 change: 1 addition & 0 deletions tests/pytest/pems_data/services/test_stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def test_get_district_metadata(self, service: StationsService, data_source: IDat
assert data_source.read.call_args.args[0] == service.metadata_file
assert data_source.read.call_args.kwargs["columns"] == [
"STATION_ID",
"CONTROLLER_ID",
"NAME",
"PHYSICAL_LANES",
"STATE_POSTMILE",
Expand Down
Loading