add utils src
Browse files- src/components/__init__.py +1 -0
- src/components/map_visualization.py +197 -0
- src/streamlit_app.py +0 -40
src/components/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
# This file is intentionally left blank.
|
src/components/map_visualization.py
ADDED
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def load_data():
|
2 |
+
"""
|
3 |
+
Load delivery and vehicle data from CSV files
|
4 |
+
|
5 |
+
Returns:
|
6 |
+
tuple: (delivery_data, vehicle_data)
|
7 |
+
"""
|
8 |
+
# Get the project root directory
|
9 |
+
root_dir = Path(__file__).resolve().parent.parent.parent
|
10 |
+
|
11 |
+
# Define data paths
|
12 |
+
delivery_data_path = os.path.join(root_dir, 'data', 'delivery-data', 'delivery_data.csv')
|
13 |
+
vehicle_data_path = os.path.join(root_dir, 'data', 'vehicle-data', 'vehicle_data.csv')
|
14 |
+
|
15 |
+
# Load data
|
16 |
+
try:
|
17 |
+
delivery_data = pd.read_csv(delivery_data_path)
|
18 |
+
vehicle_data = pd.read_csv(vehicle_data_path)
|
19 |
+
return delivery_data, vehicle_data
|
20 |
+
except FileNotFoundError as e:
|
21 |
+
st.error(f"Could not load data: {e}")
|
22 |
+
st.info("Please generate the data first by running: python src/utils/generate_all_data.py")
|
23 |
+
return None, None
|
24 |
+
|
25 |
+
def create_delivery_map(delivery_data=None, vehicle_data=None, show_deliveries=True, show_depots=True,
|
26 |
+
date_filter=None, status_filter=None, priority_filter=None):
|
27 |
+
"""
|
28 |
+
Create a Folium map with markers for deliveries and vehicle depots
|
29 |
+
|
30 |
+
Parameters:
|
31 |
+
delivery_data (pd.DataFrame): Delivery data
|
32 |
+
vehicle_data (pd.DataFrame): Vehicle data
|
33 |
+
show_deliveries (bool): Whether to show delivery markers
|
34 |
+
show_depots (bool): Whether to show depot markers
|
35 |
+
date_filter (str): Filter deliveries by date
|
36 |
+
status_filter (str): Filter deliveries by status
|
37 |
+
priority_filter (str): Filter deliveries by priority
|
38 |
+
|
39 |
+
Returns:
|
40 |
+
folium.Map: Folium map with markers
|
41 |
+
"""
|
42 |
+
# If data not provided, load it
|
43 |
+
if delivery_data is None or vehicle_data is None:
|
44 |
+
delivery_data, vehicle_data = load_data()
|
45 |
+
if delivery_data is None or vehicle_data is None:
|
46 |
+
return None
|
47 |
+
|
48 |
+
# Apply filters to delivery data
|
49 |
+
if date_filter is not None:
|
50 |
+
delivery_data = delivery_data[delivery_data['delivery_date'] == date_filter]
|
51 |
+
|
52 |
+
if status_filter is not None:
|
53 |
+
delivery_data = delivery_data[delivery_data['status'] == status_filter]
|
54 |
+
|
55 |
+
if priority_filter is not None:
|
56 |
+
delivery_data = delivery_data[delivery_data['priority'] == priority_filter]
|
57 |
+
|
58 |
+
# Create map centered around Singapore
|
59 |
+
singapore_coords = [1.3521, 103.8198] # Center of Singapore
|
60 |
+
m = folium.Map(location=singapore_coords, zoom_start=12)
|
61 |
+
|
62 |
+
# Add delivery markers
|
63 |
+
if show_deliveries and not delivery_data.empty:
|
64 |
+
for _, row in delivery_data.iterrows():
|
65 |
+
# Create popup content with delivery information
|
66 |
+
popup_content = f"""
|
67 |
+
<b>Delivery ID:</b> {row['delivery_id']}<br>
|
68 |
+
<b>Customer:</b> {row['customer_name']}<br>
|
69 |
+
<b>Address:</b> {row['address']}<br>
|
70 |
+
<b>Time Window:</b> {row['time_window']}<br>
|
71 |
+
<b>Status:</b> {row['status']}<br>
|
72 |
+
<b>Priority:</b> {row['priority']}<br>
|
73 |
+
<b>Weight:</b> {row['weight_kg']} kg<br>
|
74 |
+
<b>Volume:</b> {row['volume_m3']} m³
|
75 |
+
"""
|
76 |
+
|
77 |
+
# Set marker color based on priority
|
78 |
+
color_map = {'High': 'red', 'Medium': 'orange', 'Low': 'blue'}
|
79 |
+
color = color_map.get(row['priority'], 'blue')
|
80 |
+
|
81 |
+
# Add marker to map
|
82 |
+
folium.Marker(
|
83 |
+
location=[row['latitude'], row['longitude']],
|
84 |
+
popup=folium.Popup(popup_content, max_width=300),
|
85 |
+
tooltip=f"Delivery {row['delivery_id']}: {row['customer_name']}",
|
86 |
+
icon=folium.Icon(color=color, icon="package", prefix="fa")
|
87 |
+
).add_to(m)
|
88 |
+
|
89 |
+
# Add depot markers
|
90 |
+
if show_depots and not vehicle_data.empty:
|
91 |
+
for _, row in vehicle_data.iterrows():
|
92 |
+
# Create popup content with vehicle information
|
93 |
+
popup_content = f"""
|
94 |
+
<b>Vehicle ID:</b> {row['vehicle_id']}<br>
|
95 |
+
<b>Type:</b> {row['vehicle_type']}<br>
|
96 |
+
<b>Driver:</b> {row['driver_name']}<br>
|
97 |
+
<b>Status:</b> {row['status']}<br>
|
98 |
+
<b>Capacity:</b> {row['max_weight_kg']} kg / {row['max_volume_m3']} m³<br>
|
99 |
+
<b>Working Hours:</b> {row['start_time']} - {row['end_time']}
|
100 |
+
"""
|
101 |
+
|
102 |
+
# Add marker to map
|
103 |
+
folium.Marker(
|
104 |
+
location=[row['depot_latitude'], row['depot_longitude']],
|
105 |
+
popup=folium.Popup(popup_content, max_width=300),
|
106 |
+
tooltip=f"Depot: {row['vehicle_id']}",
|
107 |
+
icon=folium.Icon(color="green", icon="truck", prefix="fa")
|
108 |
+
).add_to(m)
|
109 |
+
|
110 |
+
return m
|
111 |
+
|
112 |
+
def display_map_component():
|
113 |
+
"""
|
114 |
+
Display the map visualization component in Streamlit
|
115 |
+
"""
|
116 |
+
st.subheader("Delivery and Depot Locations")
|
117 |
+
|
118 |
+
# Load data
|
119 |
+
delivery_data, vehicle_data = load_data()
|
120 |
+
if delivery_data is None or vehicle_data is None:
|
121 |
+
return
|
122 |
+
|
123 |
+
# Create sidebar filters
|
124 |
+
with st.sidebar:
|
125 |
+
st.subheader("Map Filters")
|
126 |
+
|
127 |
+
# Show/hide options
|
128 |
+
show_deliveries = st.checkbox("Show Deliveries", value=True)
|
129 |
+
show_depots = st.checkbox("Show Depots", value=True)
|
130 |
+
|
131 |
+
# Delivery date filter
|
132 |
+
dates = sorted(delivery_data['delivery_date'].unique())
|
133 |
+
selected_date = st.selectbox(
|
134 |
+
"Filter by Date",
|
135 |
+
options=["All"] + list(dates),
|
136 |
+
index=0
|
137 |
+
)
|
138 |
+
date_filter = None if selected_date == "All" else selected_date
|
139 |
+
|
140 |
+
# Delivery status filter
|
141 |
+
statuses = sorted(delivery_data['status'].unique())
|
142 |
+
selected_status = st.selectbox(
|
143 |
+
"Filter by Status",
|
144 |
+
options=["All"] + list(statuses),
|
145 |
+
index=0
|
146 |
+
)
|
147 |
+
status_filter = None if selected_status == "All" else selected_status
|
148 |
+
|
149 |
+
# Delivery priority filter
|
150 |
+
priorities = sorted(delivery_data['priority'].unique())
|
151 |
+
selected_priority = st.selectbox(
|
152 |
+
"Filter by Priority",
|
153 |
+
options=["All"] + list(priorities),
|
154 |
+
index=0
|
155 |
+
)
|
156 |
+
priority_filter = None if selected_priority == "All" else selected_priority
|
157 |
+
|
158 |
+
# Display statistics
|
159 |
+
col1, col2, col3 = st.columns(3)
|
160 |
+
|
161 |
+
# Apply filters for stats calculation
|
162 |
+
filtered_delivery_data = delivery_data
|
163 |
+
if date_filter:
|
164 |
+
filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['delivery_date'] == date_filter]
|
165 |
+
if status_filter:
|
166 |
+
filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['status'] == status_filter]
|
167 |
+
if priority_filter:
|
168 |
+
filtered_delivery_data = filtered_delivery_data[filtered_delivery_data['priority'] == priority_filter]
|
169 |
+
|
170 |
+
with col1:
|
171 |
+
st.metric("Total Deliveries", filtered_delivery_data.shape[0])
|
172 |
+
|
173 |
+
with col2:
|
174 |
+
st.metric("Total Weight", f"{filtered_delivery_data['weight_kg'].sum():.2f} kg")
|
175 |
+
|
176 |
+
with col3:
|
177 |
+
st.metric("Available Vehicles", vehicle_data[vehicle_data['status'] == 'Available'].shape[0])
|
178 |
+
|
179 |
+
# Create and display the map
|
180 |
+
delivery_map = create_delivery_map(
|
181 |
+
delivery_data=delivery_data,
|
182 |
+
vehicle_data=vehicle_data,
|
183 |
+
show_deliveries=show_deliveries,
|
184 |
+
show_depots=show_depots,
|
185 |
+
date_filter=date_filter,
|
186 |
+
status_filter=status_filter,
|
187 |
+
priority_filter=priority_filter
|
188 |
+
)
|
189 |
+
|
190 |
+
if delivery_map:
|
191 |
+
folium_static(delivery_map, width=800, height=600)
|
192 |
+
else:
|
193 |
+
st.error("Could not create map. Please check that data is available.")
|
194 |
+
|
195 |
+
if __name__ == "__main__":
|
196 |
+
# Run the map visualization component
|
197 |
+
display_map_component()
|
src/streamlit_app.py
DELETED
@@ -1,40 +0,0 @@
|
|
1 |
-
import altair as alt
|
2 |
-
import numpy as np
|
3 |
-
import pandas as pd
|
4 |
-
import streamlit as st
|
5 |
-
|
6 |
-
"""
|
7 |
-
# Welcome to Streamlit!
|
8 |
-
|
9 |
-
Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
|
10 |
-
If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
|
11 |
-
forums](https://discuss.streamlit.io).
|
12 |
-
|
13 |
-
In the meantime, below is an example of what you can do with just a few lines of code:
|
14 |
-
"""
|
15 |
-
|
16 |
-
num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
|
17 |
-
num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
|
18 |
-
|
19 |
-
indices = np.linspace(0, 1, num_points)
|
20 |
-
theta = 2 * np.pi * num_turns * indices
|
21 |
-
radius = indices
|
22 |
-
|
23 |
-
x = radius * np.cos(theta)
|
24 |
-
y = radius * np.sin(theta)
|
25 |
-
|
26 |
-
df = pd.DataFrame({
|
27 |
-
"x": x,
|
28 |
-
"y": y,
|
29 |
-
"idx": indices,
|
30 |
-
"rand": np.random.randn(num_points),
|
31 |
-
})
|
32 |
-
|
33 |
-
st.altair_chart(alt.Chart(df, height=700, width=700)
|
34 |
-
.mark_point(filled=True)
|
35 |
-
.encode(
|
36 |
-
x=alt.X("x", axis=None),
|
37 |
-
y=alt.Y("y", axis=None),
|
38 |
-
color=alt.Color("idx", legend=None, scale=alt.Scale()),
|
39 |
-
size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
|
40 |
-
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|