WRO2025 / src /streamlit_app.py
maddiaks's picture
Update src/streamlit_app.py
e2f184b verified
import streamlit as st
import json
import folium
from streamlit_folium import folium_static, st_folium
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import os
from constants import zone_colors, ALL_ZONES
# Set page title
st.set_page_config(layout="wide")
st.title("🌧️ Storm Water Drain Dashboard - Hyderabad")
fSWDDetails = {}
all_zones = []
# Load SWD details from JSON file
file_path = "SWD_Details_Working.json"
json_path = os.path.join(os.path.dirname(__file__), file_path)
if os.path.exists(json_path):
# st.success(f"Found file: {json_path}")
with open(json_path, "r") as file:
fSWDDetails = json.load(file)
# st.write("Loaded JSON:")
# st.json(fSWDDetails)
else:
st.error(f"File not found: {file_path}")
def get_all_zones():
"""Extract unique zones from SWD details."""
global all_zones
if len(all_zones) == 0:
# Step 1: Extract all zones
for item in fSWDDetails:
if item['Zone'] not in all_zones:
all_zones.append(item['Zone'])
all_zones.append("All Zones")
all_zones.sort()
return all_zones
get_all_zones()
selected_zone = st.sidebar.radio("Filter by Zone", options=all_zones)
# avg_lat, avg_lon = 17.3850, 78.4867 # Default to Hyderabad center
avg_lat, avg_lon = 17.4250, 78.5567 # Default to Hyderabad center
zoom_level = 11.5 # Default zoom level
# Step 3: Filter data
filtered_data = fSWDDetails
if selected_zone != ALL_ZONES:
filtered_data = [item for item in fSWDDetails if item['Zone'] == selected_zone]
zoom_level = 13 # Zoom in closer for specific zone
avg_lat = sum(item['Latitude'] for item in filtered_data) / len(filtered_data) + 0.005
avg_lon = sum(item['Longitude'] for item in filtered_data) / len(filtered_data) + 0.035
selected_pit_id = st.sidebar.selectbox("Select Pit ID to View Details", ["None"] + [item['Id'] for item in filtered_data])
# Set layout with columns
col1, col2 = st.columns([2, 1]) # Map on left (wider), details on right
selected_pit = next((item for item in filtered_data if item['Id'] == selected_pit_id), None)
if selected_pit:
st.sidebar.write(f"Selected Pit: {selected_pit['Id']}")
st.sidebar.write(f"Zone: {selected_pit['Zone']}")
info = selected_pit['Details']['info']
with col1:
st.header("Storm Water Pit Map")
if selected_pit:
zoom_level = 15
avg_lat = selected_pit['Latitude']
avg_lon = selected_pit['Longitude']
hydMap = folium.Map(location=[avg_lat, avg_lon], zoom_start=zoom_level)
# Marker + Circle Highlight
# Add SWD entries to the map
for _, item in enumerate(filtered_data):
color = zone_colors.get(item["Zone"], "gray") # default to gray if zone not found
popup_info = f"""
<b>{item['Id']}</b><br>
<b>{item['Address']['Area']}</b><br>
"""
folium.Marker(
[item['Latitude'], item['Longitude']],
popup=popup_info,
tooltip=popup_info,
icon=folium.Icon(color=color, icon='info-sign')
).add_to(hydMap)
if selected_pit:
zoom_level = 15
folium.CircleMarker(
location=[selected_pit["Latitude"], selected_pit["Longitude"]],
radius=25,
color='orange',
fill=True,
fill_color='yellow',
fill_opacity=0.7,
weight=3
).add_to(hydMap)
st_data = st_folium(hydMap, width=1500, height=600)
with col2:
if selected_pit is not None:
st.header(f"Pit - {selected_pit['Id']}")
address = selected_pit['Address']
address_str = address['Street'] + "\n" + address['Area'] + "\n" + address['Pin']
subcol1, subcol2 = st.columns(2)
with subcol1:
info = selected_pit["Details"]["info"]
st.text_input("Debris Level", info['DebrisPitLevel'], disabled=True)
st.text_input("Last Cleaned", info['LastCleaned'], disabled=True)
st.text_input("Next Cleaning", info['NextScheduledCleaning'], disabled=True)
st.text_input("Maintenance", info['MaintenanceStatus'], disabled=True)
st.text_area("Address", address_str, height=110, disabled=True)
with subcol2:
st.text_input("Compression Enabled", info['CompressionEnabled'], disabled=True)
latcol1, longcol2 = st.columns(2)
with latcol1:
st.text_input("Latitude", selected_pit['Latitude'], disabled=True)
with longcol2:
st.text_input("Longitude", selected_pit['Longitude'], disabled=True)
st.text_input("Size", info['Size'], disabled=True)
st.text_input("Phone", selected_pit['Phone'], disabled=True)
st.text_area("Notes", info['Notes'], height=110, disabled=True)
st.slider("Compression Distance", min_value=3, max_value=12, value=5, step=1)
btnCol1, btnCol2 = st.columns(2)
with btnCol1:
st.button("Change Level", disabled=False, help="Coming Soon!", type="primary")
with btnCol2:
st.button("Raise Request", disabled=False, help="Coming Soon!", type="primary")
# Sample data
# if st.button("Show Storm Water Pit Level Trend"):
if selected_pit and st.checkbox("Show Debris Level Chart"):
st.subheader("Storm Water Pit Level Trend")
debris_levels = selected_pit.get("Details", {}).get("DebrisLevels", [])
if not debris_levels:
st.warning("No debris level data available for this pit.")
st.stop()
# data = [
# {"Timestamp": "2025-10-01T10:00:00Z", "Level": 0.5, "Status": "Normal"},
# {"Timestamp": "2025-10-02T10:00:00Z", "Level": 0.6, "Status": "Normal"},
# {"Timestamp": "2025-10-03T10:00:00Z", "Level": 0.7, "Status": "High"},
# {"Timestamp": "2025-10-04T10:00:00Z", "Level": 0.8, "Status": "Critical"},
# {"Timestamp": "2025-10-05T10:00:00Z", "Level": 0.9, "Status": "Critical"},
# {"Timestamp": "2025-10-06T10:00:00Z", "Level": 0.95, "Status": "High"},
# {"Timestamp": "2025-10-07T10:00:00Z", "Level": 1.0, "Status": "Critical"},
# {"Timestamp": "2025-10-08T10:00:00Z", "Level": 1.0, "Status": "Critical"},
# {"Timestamp": "2025-10-09T10:00:00Z", "Level": 0.85, "Status": "High"},
# {"Timestamp": "2025-10-10T10:00:00Z", "Level": 0.2, "Status": "Normal"}
# ]
# Convert to DataFrame
df = pd.DataFrame(debris_levels)
df["Timestamp"] = pd.to_datetime(df["Timestamp"])
df["DateLabel"] = df["Timestamp"].dt.strftime("%b %d") # e.g., 'Oct 01'
# Optional: Define color map for status
status_color_map = {
"Normal": "green",
"High": "orange",
"Critical": "red"
}
df["Color"] = df["Status"].map(status_color_map)
# Calculate average level
avg_level = df["Level"].mean()
fig = go.Figure()
# Plotly Bar Chart
fig = go.Figure()
fig.add_trace(go.Bar(
x=df["DateLabel"],
y=df["Level"],
marker_color=df["Color"],
text=df["Status"],
textposition="outside"
))
# Add average line
fig.add_hline(
y=avg_level,
line_dash="dash",
line_color="blue",
annotation_text=f"Average: {avg_level:.2f}",
annotation_position="top left"
)
fig.update_layout(
title="Storm Water Pit Level Trend",
xaxis_title="Date",
yaxis_title="Level (m)",
yaxis_range=[0, 1.2],
xaxis_tickangle=-30,
height=500
)
# Display in Streamlit
st.plotly_chart(fig, use_container_width=True)