junlongcheng commited on
Commit
94a2717
1 Parent(s): ee6f22b

Upload 3 files

Browse files
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ permanently_cleaned_geolocation_data.csv filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dash
2
+ from dash import dcc, html, Input, Output, exceptions
3
+ import pandas as pd
4
+ from sklearn.cluster import KMeans
5
+ import plotly.express as px
6
+ import dash_bootstrap_components as dbc
7
+
8
+ # 1. Data Preparation (Assuming you've read your data into a DataFrame named 'df')
9
+ df = pd.read_csv('permanently_cleaned_geolocation_data.csv')
10
+
11
+ df = df.rename(columns = {'id_left': 'id',
12
+ 'geolocation_state': 'state',
13
+ 'geolocation_lat': 'latitude',
14
+ 'geolocation_lng': 'longitude'})
15
+
16
+ df['object'] = df['object'].astype(str).str.capitalize()
17
+
18
+ # 2. Dash App Setup
19
+ app = dash.Dash(__name__, external_stylesheets=['https://codepen.io/chriddyp/pen/bWLwgP.css'])
20
+
21
+ # State Filter Options with "Select All"
22
+ state_options = [{'label': 'Select All', 'value': 'all'}] + [
23
+ {'label': i, 'value': i} for i in df['state'].unique()
24
+ ]
25
+
26
+ app.layout = html.Div([
27
+ html.H1("Olist Warehouse Location Optimization Tool", style={'textAlign': 'center'}),
28
+
29
+ # Outer container for slicers
30
+ html.Div(id='outer_div', children=[
31
+ html.Div([ # Slicer 1 (Object)
32
+ html.Label("Select Object:"),
33
+ dcc.Dropdown(id='object-filter', options=[{'label': i, 'value': i} for i in df['object'].unique()], multi=True)
34
+ ], style={'width': '250px', 'margin': '10px'}), # Adjust width as needed
35
+
36
+ html.Div([ # Slicer 2 (State)
37
+ html.Label("Select State:"),
38
+ dcc.Dropdown(id='state-filter', options=state_options, value='all', multi=True)
39
+ ], style={'width': '250px', 'margin': '10px'}),
40
+
41
+ html.Div([ # Slicer 3 (Number of Clusters)
42
+ html.Label("Number of Warehouses:"),
43
+ dcc.Input(id='cluster-input', type='number', min=1, value=3)
44
+ ], style={'width': '250px', 'margin': '10px'}),
45
+ ], style={
46
+ 'display': 'flex',
47
+ 'flex-direction': 'row',
48
+ 'justify-content': 'center',
49
+ 'align-items': 'center',
50
+ 'flex-wrap': 'wrap'
51
+ }),
52
+
53
+ html.Div( # Map container
54
+ dcc.Graph(id='cluster-plot', style={'height': '600px', 'width': '800px'}),
55
+ style={
56
+ 'display': 'flex',
57
+ 'justify-content': 'center',
58
+ 'align-items': 'center'
59
+ }
60
+ )
61
+ ])
62
+
63
+ # 5. Callback for Interactivity
64
+ @app.callback(
65
+ Output('cluster-plot', 'figure'),
66
+ [Input('object-filter', 'value'),
67
+ Input('state-filter', 'value'),
68
+ Input('cluster-input', 'value')]
69
+ )
70
+ def update_plot(selected_objects, selected_states, num_clusters):
71
+ # Handle "Select All" for States
72
+ if 'all' in selected_states:
73
+ selected_states = df['state'].unique()
74
+
75
+ if selected_objects is None or num_clusters is None:
76
+ return px.scatter() # Empty plot if filters are not selected
77
+
78
+ filtered_df = df[df['object'].isin(selected_objects) & df['state'].isin(selected_states)]
79
+
80
+ if filtered_df.empty:
81
+ return px.scatter()
82
+
83
+ # Clustering
84
+ kmeans = KMeans(n_clusters=num_clusters).fit(filtered_df[['longitude', 'latitude']])
85
+ filtered_df['cluster'] = kmeans.labels_
86
+
87
+ # Calculate Cluster Centers
88
+ cluster_centers = filtered_df.groupby('cluster')[['longitude', 'latitude']].mean().reset_index()
89
+
90
+ # Create Plot (NO hovertemplate here)
91
+ fig = px.scatter_mapbox(filtered_df, lat="latitude", lon="longitude", color="cluster",
92
+ hover_name=None,
93
+ custom_data=['cluster'],
94
+ mapbox_style="carto-positron")
95
+
96
+ # Add Cluster Centers to Plot (WITH hover data)
97
+ fig.add_scattermapbox(
98
+ lat=cluster_centers["latitude"],
99
+ lon=cluster_centers["longitude"],
100
+ mode="markers",
101
+ marker=dict(size=20, color="red"),
102
+ name="Warehouses",
103
+ hoverinfo="text", # Enable hover for cluster centers
104
+ text=[
105
+ f"Warehouse {i + 1}<br>Lat: {lat:.4f}<br>Lon: {lon:.4f}"
106
+ for i, lat, lon in zip(
107
+ cluster_centers.index, cluster_centers["latitude"], cluster_centers["longitude"]
108
+ )
109
+ ],
110
+ showlegend=False,
111
+ )
112
+
113
+ return fig
114
+
115
+ if __name__ == '__main__':
116
+ app.run_server(debug=True, port=8068)
permanently_cleaned_geolocation_data.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:601485a3bab25314c4eb6d77f8203ac110f3d11c6803c7939929b221a8c3df43
3
+ size 16261986
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ dash==2.14.2
2
+ dash_bootstrap_components==1.6.0
3
+ pandas==2.2.2
4
+ plotly==5.9.0
5
+ scikit_learn==1.2.2