klydekushy commited on
Commit
4dbcdf0
·
verified ·
1 Parent(s): 8f066dd

Update src/modules/map_dashboard.py

Browse files
Files changed (1) hide show
  1. src/modules/map_dashboard.py +148 -112
src/modules/map_dashboard.py CHANGED
@@ -120,117 +120,153 @@ def show_map_dashboard(client, sheet_name):
120
  st.caption(f"Rev: {row['Revenus']} XOF")
121
 
122
  with col_map:
123
- # Préparation des données pour Pydeck
124
- clients_layer_data = df_map[['lon', 'lat', 'ID', 'Adresse']].copy()
125
-
126
- # Données HQ
127
- hq_data = pd.DataFrame({
128
- 'lon': [2.396667],
129
- 'lat': [48.913418],
130
- 'name': ['HQ - VORTEX'],
131
- 'elevation': [500]
132
- })
133
-
134
- # Configuration de la vue 3D
135
- view_state = pdk.ViewState(
136
- latitude=48.913418,
137
- longitude=2.396667,
138
- zoom=13,
139
- pitch=60, # Inclinaison 3D
140
- bearing=0
141
- )
142
-
143
- layers = []
144
-
145
- # Layer 1: Colonnes 3D pour les clients (losanges bleus)
146
- layers.append(
147
- pdk.Layer(
148
- 'ColumnLayer',
149
- data=clients_layer_data,
150
- get_position='[lon, lat]',
151
- get_elevation=200,
152
- elevation_scale=1,
153
- radius=30,
154
- get_fill_color=[37, 193, 247, 200],
155
- pickable=True,
156
- auto_highlight=True,
157
- )
158
- )
159
-
160
- # Layer 2: HQ Pyramide Rouge (style Palantir)
161
- layers.append(
162
- pdk.Layer(
163
- 'ColumnLayer',
164
- data=hq_data,
165
- get_position='[lon, lat]',
166
- get_elevation='elevation',
167
- elevation_scale=1,
168
- radius=50,
169
- get_fill_color=[255, 50, 50, 255],
170
- pickable=True,
171
- )
172
- )
173
-
174
- # Layer 3: Lignes de connexion (si activées)
175
- if show_dist:
176
- arc_data = []
177
- for _, row in df_map.iterrows():
178
- arc_data.append({
179
- 'source_lon': 2.396667,
180
- 'source_lat': 48.913418,
181
- 'target_lon': row['lon'],
182
- 'target_lat': row['lat']
183
- })
184
-
185
- arc_df = pd.DataFrame(arc_data)
186
-
187
- layers.append(
188
- pdk.Layer(
189
- 'ArcLayer',
190
- data=arc_df,
191
- get_source_position='[source_lon, source_lat]',
192
- get_target_position='[target_lon, target_lat]',
193
- get_source_color=[255, 215, 0, 180],
194
- get_target_color=[37, 193, 247, 150],
195
- get_width=2,
196
- pickable=True,
197
- )
198
- )
199
-
200
- # Layer 4: Zone de densité (si activée)
201
- if show_cluster:
202
- avg_lat = df_map['lat'].mean()
203
- avg_lon = df_map['lon'].mean()
204
-
205
- circle_data = pd.DataFrame({
206
- 'lon': [avg_lon],
207
- 'lat': [avg_lat],
208
- 'radius': [2000]
209
  })
210
-
211
- layers.append(
212
- pdk.Layer(
213
- 'ScatterplotLayer',
214
- data=circle_data,
215
- get_position='[lon, lat]',
216
- get_radius='radius',
217
- get_fill_color=[84, 189, 75, 80],
218
- pickable=False,
219
- )
220
- )
221
 
222
- # Rendu final sans attribution
223
- st.pydeck_chart(pdk.Deck(
224
- map_style='mapbox://styles/mapbox/dark-v10',
225
- initial_view_state=view_state,
226
- layers=layers,
227
- tooltip={
228
- 'html': '<b>{ID}</b><br>{Adresse}',
229
- 'style': {
230
- 'backgroundColor': '#1a1a1a',
231
- 'color': '#25C1F7',
232
- 'fontFamily': 'Space Grotesk'
233
- }
234
- }
235
- ))
236
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  st.caption(f"Rev: {row['Revenus']} XOF")
121
 
122
  with col_map:
123
+ # Préparer les données des clients
124
+ clients_markers = []
125
+ for _, row in df_map.iterrows():
126
+ clients_markers.append({
127
+ 'lon': row['lon'],
128
+ 'lat': row['lat'],
129
+ 'id': row['ID'],
130
+ 'adresse': row['Adresse']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  })
 
 
 
 
 
 
 
 
 
 
 
132
 
133
+ # Créer le HTML avec Mapbox GL
134
+ mapbox_html = f"""
135
+ <!DOCTYPE html>
136
+ <html>
137
+ <head>
138
+ <meta charset="utf-8">
139
+ <script src='https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js'></script>
140
+ <link href='https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css' rel='stylesheet' />
141
+ <style>
142
+ body {{ margin: 0; padding: 0; }}
143
+ #map {{ position: absolute; top: 0; bottom: 0; width: 100%; }}
144
+ </style>
145
+ </head>
146
+ <body>
147
+ <div id="map"></div>
148
+ <script>
149
+ mapboxgl.accessToken = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw'; // Token public Mapbox
150
+
151
+ const map = new mapboxgl.Map({{
152
+ container: 'map',
153
+ style: 'mapbox://styles/mapbox/satellite-streets-v12', // Vue satellite
154
+ center: [2.396667, 48.913418],
155
+ zoom: 15,
156
+ pitch: 60, // Vue 3D inclinée
157
+ bearing: 0,
158
+ antialias: true
159
+ }});
160
+
161
+ map.on('load', () => {{
162
+ // Activer les bâtiments 3D
163
+ map.addLayer({{
164
+ 'id': '3d-buildings',
165
+ 'source': 'composite',
166
+ 'source-layer': 'building',
167
+ 'filter': ['==', 'extrude', 'true'],
168
+ 'type': 'fill-extrusion',
169
+ 'minzoom': 14,
170
+ 'paint': {{
171
+ 'fill-extrusion-color': '#aaa',
172
+ 'fill-extrusion-height': ['get', 'height'],
173
+ 'fill-extrusion-base': ['get', 'min_height'],
174
+ 'fill-extrusion-opacity': 0.8
175
+ }}
176
+ }});
177
+
178
+ // Marqueur HQ (Pyramide Rouge)
179
+ const hqEl = document.createElement('div');
180
+ hqEl.style.width = '30px';
181
+ hqEl.style.height = '30px';
182
+ hqEl.style.backgroundImage = 'linear-gradient(135deg, #ff3232 0%, #aa0000 100%)';
183
+ hqEl.style.transform = 'rotate(45deg)';
184
+ hqEl.style.border = '2px solid #fff';
185
+ hqEl.style.boxShadow = '0 0 20px rgba(255, 50, 50, 0.8)';
186
+
187
+ new mapboxgl.Marker({{element: hqEl}})
188
+ .setLngLat([2.396667, 48.913418])
189
+ .setPopup(new mapboxgl.Popup().setHTML('<strong>HQ - VORTEX</strong>'))
190
+ .addTo(map);
191
+
192
+ // Marqueurs Clients (Losanges Bleus)
193
+ const clients = {clients_markers};
194
+ clients.forEach(client => {{
195
+ const el = document.createElement('div');
196
+ el.style.width = '20px';
197
+ el.style.height = '20px';
198
+ el.style.background = 'linear-gradient(135deg, #25C1F7 0%, #0080ff 100%)';
199
+ el.style.transform = 'rotate(45deg)';
200
+ el.style.border = '1px solid #fff';
201
+ el.style.boxShadow = '0 0 15px rgba(37, 193, 247, 0.6)';
202
+ el.style.cursor = 'pointer';
203
+
204
+ new mapboxgl.Marker({{element: el}})
205
+ .setLngLat([client.lon, client.lat])
206
+ .setPopup(new mapboxgl.Popup().setHTML(`<strong>${{client.id}}</strong><br>${{client.adresse}}`))
207
+ .addTo(map);
208
+
209
+ // Lignes de connexion (si activé)
210
+ {'if (true) {' if show_dist else 'if (false) {'}
211
+ map.addLayer({{
212
+ 'id': 'line-' + client.id,
213
+ 'type': 'line',
214
+ 'source': {{
215
+ 'type': 'geojson',
216
+ 'data': {{
217
+ 'type': 'Feature',
218
+ 'geometry': {{
219
+ 'type': 'LineString',
220
+ 'coordinates': [
221
+ [2.396667, 48.913418],
222
+ [client.lon, client.lat]
223
+ ]
224
+ }}
225
+ }}
226
+ }},
227
+ 'paint': {{
228
+ 'line-color': '#FFD700',
229
+ 'line-width': 2,
230
+ 'line-opacity': 0.6
231
+ }}
232
+ }});
233
+ }}
234
+ }});
235
+
236
+ // Zone de cluster (si activé)
237
+ {'if (true) {' if show_cluster else 'if (false) {'}
238
+ map.addLayer({{
239
+ 'id': 'cluster-zone',
240
+ 'type': 'circle',
241
+ 'source': {{
242
+ 'type': 'geojson',
243
+ 'data': {{
244
+ 'type': 'Feature',
245
+ 'geometry': {{
246
+ 'type': 'Point',
247
+ 'coordinates': [{df_map['lon'].mean()}, {df_map['lat'].mean()}]
248
+ }}
249
+ }}
250
+ }},
251
+ 'paint': {{
252
+ 'circle-radius': {{
253
+ 'stops': [[0, 0], [20, 300]]
254
+ }},
255
+ 'circle-color': '#54BD4B',
256
+ 'circle-opacity': 0.3,
257
+ 'circle-stroke-width': 2,
258
+ 'circle-stroke-color': '#54BD4B'
259
+ }}
260
+ }});
261
+ }}
262
+ }});
263
+
264
+ // Contrôles de navigation
265
+ map.addControl(new mapboxgl.NavigationControl());
266
+ </script>
267
+ </body>
268
+ </html>
269
+ """
270
+
271
+ # Afficher la carte
272
+ st.components.v1.html(mapbox_html, height=600)