| | 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 |
| |
|
| | |
| | st.set_page_config(layout="wide") |
| | st.title("🌧️ Storm Water Drain Dashboard - Hyderabad") |
| |
|
| |
|
| | fSWDDetails = {} |
| | all_zones = [] |
| |
|
| | |
| | file_path = "SWD_Details_Working.json" |
| | json_path = os.path.join(os.path.dirname(__file__), file_path) |
| |
|
| |
|
| | if os.path.exists(json_path): |
| | |
| | with open(json_path, "r") as file: |
| | fSWDDetails = json.load(file) |
| | |
| | |
| | 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: |
| | |
| | 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.4250, 78.5567 |
| |
|
| | zoom_level = 11.5 |
| |
|
| | |
| | filtered_data = fSWDDetails |
| |
|
| | if selected_zone != ALL_ZONES: |
| | filtered_data = [item for item in fSWDDetails if item['Zone'] == selected_zone] |
| | zoom_level = 13 |
| |
|
| | 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]) |
| |
|
| | |
| | col1, col2 = st.columns([2, 1]) |
| |
|
| | 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) |
| |
|
| | |
| | |
| | for _, item in enumerate(filtered_data): |
| |
|
| | color = zone_colors.get(item["Zone"], "gray") |
| | 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") |
| |
|
| | |
| |
|
| | |
| | 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() |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | df = pd.DataFrame(debris_levels) |
| | df["Timestamp"] = pd.to_datetime(df["Timestamp"]) |
| | df["DateLabel"] = df["Timestamp"].dt.strftime("%b %d") |
| |
|
| |
|
| | |
| | status_color_map = { |
| | "Normal": "green", |
| | "High": "orange", |
| | "Critical": "red" |
| | } |
| | df["Color"] = df["Status"].map(status_color_map) |
| |
|
| | |
| | avg_level = df["Level"].mean() |
| |
|
| | fig = go.Figure() |
| |
|
| | |
| | fig = go.Figure() |
| | fig.add_trace(go.Bar( |
| | x=df["DateLabel"], |
| | y=df["Level"], |
| | marker_color=df["Color"], |
| | text=df["Status"], |
| | textposition="outside" |
| | )) |
| |
|
| | |
| | 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 |
| | ) |
| |
|
| | |
| | st.plotly_chart(fig, use_container_width=True) |
| |
|
| |
|
| |
|