| import os |
| import sys |
| from pathlib import Path |
| import pandas as pd |
| import folium |
| import streamlit as st |
|
|
| def load_data(): |
| """ |
| Load delivery and vehicle data from CSV files |
| |
| Returns: |
| tuple: (delivery_data, vehicle_data) |
| """ |
| |
| root_dir = Path(__file__).resolve().parent.parent.parent |
| |
| |
| delivery_data_path = os.path.join(root_dir, 'data', 'delivery-data', 'delivery_data.csv') |
| vehicle_data_path = os.path.join(root_dir, 'data', 'vehicle-data', 'vehicle_data.csv') |
| |
| |
| try: |
| delivery_data = pd.read_csv(delivery_data_path) |
| vehicle_data = pd.read_csv(vehicle_data_path) |
| return delivery_data, vehicle_data |
| except FileNotFoundError as e: |
| st.error(f"Could not load data: {e}") |
| st.info("Please generate the data first by running: python src/utils/generate_all_data.py") |
| return None, None |
|
|
| def create_delivery_map(delivery_data=None, vehicle_data=None, show_deliveries=True, show_depots=True, |
| date_filter=None, status_filter=None, priority_filter=None): |
| """ |
| Create a Folium map with markers for deliveries and vehicle depots |
| |
| Parameters: |
| delivery_data (pd.DataFrame): Delivery data |
| vehicle_data (pd.DataFrame): Vehicle data |
| show_deliveries (bool): Whether to show delivery markers |
| show_depots (bool): Whether to show depot markers |
| date_filter (str): Filter deliveries by date |
| status_filter (str): Filter deliveries by status |
| priority_filter (str): Filter deliveries by priority |
| |
| Returns: |
| folium.Map: Folium map with markers |
| """ |
| |
| if delivery_data is None or vehicle_data is None: |
| delivery_data, vehicle_data = load_data() |
| if delivery_data is None or vehicle_data is None: |
| return None |
| |
| |
| if date_filter is not None: |
| delivery_data = delivery_data[delivery_data['delivery_date'] == date_filter] |
| |
| if status_filter is not None: |
| delivery_data = delivery_data[delivery_data['status'] == status_filter] |
| |
| if priority_filter is not None: |
| delivery_data = delivery_data[delivery_data['priority'] == priority_filter] |
| |
| |
| singapore_coords = [1.3521, 103.8198] |
| m = folium.Map(location=singapore_coords, zoom_start=12) |
| |
| |
| if show_deliveries and not delivery_data.empty: |
| for _, row in delivery_data.iterrows(): |
| |
| popup_content = f""" |
| <b>Delivery ID:</b> {row['delivery_id']}<br> |
| <b>Customer:</b> {row['customer_name']}<br> |
| <b>Address:</b> {row['address']}<br> |
| <b>Time Window:</b> {row['time_window']}<br> |
| <b>Status:</b> {row['status']}<br> |
| <b>Priority:</b> {row['priority']}<br> |
| <b>Weight:</b> {row['weight_kg']} kg<br> |
| <b>Volume:</b> {row['volume_m3']} m³ |
| """ |
| |
| |
| color_map = {'High': 'red', 'Medium': 'orange', 'Low': 'blue'} |
| color = color_map.get(row['priority'], 'blue') |
| |
| |
| folium.Marker( |
| location=[row['latitude'], row['longitude']], |
| popup=folium.Popup(popup_content, max_width=300), |
| tooltip=f"Delivery {row['delivery_id']}: {row['customer_name']}", |
| icon=folium.Icon(color=color, icon="package", prefix="fa") |
| ).add_to(m) |
| |
| |
| if show_depots and not vehicle_data.empty: |
| for _, row in vehicle_data.iterrows(): |
| |
| popup_content = f""" |
| <b>Vehicle ID:</b> {row['vehicle_id']}<br> |
| <b>Type:</b> {row['vehicle_type']}<br> |
| <b>Driver:</b> {row['driver_name']}<br> |
| <b>Status:</b> {row['status']}<br> |
| <b>Capacity:</b> {row['max_weight_kg']} kg / {row['max_volume_m3']} m³<br> |
| <b>Working Hours:</b> {row['start_time']} - {row['end_time']} |
| """ |
| |
| |
| folium.Marker( |
| location=[row['depot_latitude'], row['depot_longitude']], |
| popup=folium.Popup(popup_content, max_width=300), |
| tooltip=f"Depot: {row['vehicle_id']}", |
| icon=folium.Icon(color="green", icon="truck", prefix="fa") |
| ).add_to(m) |
| |
| return m |
|
|
| def display_map_component(): |
| """ |
| Display the map visualization component in Streamlit |
| """ |
| st.subheader("Delivery and Depot Locations") |
| |
| |
| delivery_data, vehicle_data = load_data() |
| if delivery_data is None or vehicle_data is None: |
| return |
| |
| |
| with st.sidebar: |
| st.subheader("Map Filters") |
| |
| |
| show_deliveries = st.checkbox("Show Deliveries", value=True) |
| show_depots = st.checkbox("Show Depots", value=True) |
| |
| |
| dates = sorted(delivery_data['delivery_date'].unique()) |
| selected_date = st.selectbox( |
| "Filter by Date", |
| options=["All"] + list(dates), |
| index=0 |
| ) |
| date_filter = None if selected_date == "All" else selected_date |
| |
| |
| statuses = sorted(delivery_data['status'].unique()) |
| selected_status = st.selectbox( |
| "Filter by Status", |
| options=["All"] + list(statuses), |
| index=0 |
| ) |
| status_filter = None if selected_status == "All" else selected_status |
| |
| |
| priorities = sorted(delivery_data['priority'].unique()) |
| selected_priority = st.selectbox( |
| "Filter by Priority", |
| options=["All"] + list(priorities), |
| index=0 |
| ) |
| priority_filter = None if selected_priority == "All" else selected_priority |
| |
| |
| col1, col2, col3 = st.columns(3) |
| |
| |
| filtered_delivery_data = delivery_data |
| if date_filter: |
| filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['delivery_date'] == date_filter] |
| if status_filter: |
| filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['status'] == status_filter] |
| if priority_filter: |
| filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['priority'] == priority_filter] |
| |
| with col1: |
| st.metric("Total Deliveries", filtered_delivery_data.shape[0]) |
| |
| with col2: |
| st.metric("Total Weight", f"{filtered_delivery_data['weight_kg'].sum():.2f} kg") |
| |
| with col3: |
| st.metric("Available Vehicles", vehicle_data[vehicle_data['status'] == 'Available'].shape[0]) |
| |
| |
| delivery_map = create_delivery_map( |
| delivery_data=delivery_data, |
| vehicle_data=vehicle_data, |
| show_deliveries=show_deliveries, |
| show_depots=show_depots, |
| date_filter=date_filter, |
| status_filter=status_filter, |
| priority_filter=priority_filter |
| ) |
| |
| if delivery_map: |
| folium_static(delivery_map, width=800, height=600) |
| else: |
| st.error("Could not create map. Please check that data is available.") |
|
|
| if __name__ == "__main__": |
| |
| display_map_component() |