Spaces:
Sleeping
Sleeping
File size: 6,361 Bytes
ff39e1a 6f1635e ff39e1a 6c7d496 ff39e1a 6c7d496 ff39e1a 7c640f7 6c7d496 7c640f7 ff39e1a 6c7d496 ff39e1a 029672d ff39e1a 6f1635e ff39e1a ad68f89 ff39e1a ad68f89 ff39e1a ad68f89 ff39e1a 223e856 6c7d496 223e856 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
import requests
import folium
import colorcet as cc
import plotly.express as px
import panel as pn
import pandas as pd
import geopandas as gpd
from time import sleep
from bokeh.models.widgets.tables import DateFormatter
from vrp import calcul_routes
from tableur import Tableur
from routingmat import fetch_matrices
pn.extension("tabulator", 'filedropper', 'plotly')
wgs84="EPSG:4326"
l93="EPSG:9794"
pal=cc.glasbey_dark
def mat_figs(dfadr, mat_dist, mat_dur):
labels=[ f'{row["oid"]}:{row["lieu"]}' for _, row in dfadr.iterrows()]
fig_dist = px.imshow(mat_dur, height=1500, x=labels, y=labels, title = "Distance (m) entre deux adresses")
fig_dur = px.imshow(mat_dist, height=1500, x=labels, y=labels, title = "Temps (minutes) entre deux adresses")
return fig_dist, fig_dur
duree_taxi=pn.widgets.IntInput(name='Durée max taxi', value=45, step=1, start=0, end=300)
duree_ecole=pn.widgets.IntInput(name='Durée max devant école', value=10, step=1, start=0, end=60)
capacité=pn.widgets.IntInput(name='Capacité taxi', value=3, step=1, start=0, end=10)
def mise_en_forme_dfinal(sol, dfadr):
dfsol=sol.routes
dfsol["num_vehicule"]=dfsol.groupby("vehicle_id").ngroup()
dfsol["durée (minutes)"]=dfsol["duration"]//60
dfsol["temps d'attente (minutes)"]=dfsol["waiting_time"]//60
dfsol["indice"]=dfsol.location_index.map(dfadr["oid"].to_dict())
dfsol["lieu"] = dfsol.location_index.map(dfadr["lieu"].to_dict())
dfsol["geometry"] = dfsol.location_index.map(dfadr["geometry"].to_dict())
dfsol["heure"]=dfsol.arrival.astype("datetime64[s]").dt.time
goodcols=['num_vehicule', 'type', 'distance', 'durée (minutes)',
"temps d'attente (minutes)", 'indice', 'lieu', 'geometry', 'heure']
dffinal=dfsol[goodcols].query("type in ['pickup', 'delivery']")
return dffinal
def fetch_itinéraires(dffinal):
dres={}
for igp, gp in dffinal.groupby("num_vehicule"):
coo=[f"{p.x},{p.y}" for p in gp.geometry.to_list()]
params=dict(resource= "bdtopo-osrm",
start=coo[0],
end=coo[-1],
intermediates="|".join(coo[1:-2]),
geometryFormat="geojson",
getSteps='false',
getBbox='true',
timeUnit="minute",
crs=wgs84)
r=requests.get(url="https://data.geopf.fr/navigation/itineraire",
params=params)
sleep(0.15)
if r.ok:
dres[igp]=r.json()
return dres
def carte(dffinal, dres, dfadr):
tiles='Stadia.AlidadeSmooth'
tiles='Cartodb Positron'
bbox=dfadr.total_bounds #[0.036343, 48.41117, 0.109909, 48.465001]
m = folium.Map(location=[(bbox[3]+bbox[1])/2, (bbox[2]+bbox[0])/2], tiles=tiles)#, zoom_start=10)
for igp, gp in dffinal.groupby("num_vehicule"):
dirs=dres[igp]
color=pal[igp]
folium.GeoJson(
name=f'Vehicle {igp}',
data={"type": "FeatureCollection",
"features": [{"type": "Feature",
"geometry": dirs['geometry'],
"properties": {"color": color} }]},
style_function=lambda x: {"color": x['properties']['color']}
).add_to(m)
for _, step in gp.iterrows():
icon='user' if step['type']=='pickup' else 'briefcase'
folium.Marker(
location=[step["geometry"].y, step["geometry"].x],
icon=folium.Icon(color="lightgray", icon_color=color, icon=icon),
popup=f'{step["lieu"]}\n{step["heure"]}'
).add_to(m)
return m
tabd=Tableur(idx_offset=1)
tabp=Tableur(idx_offset=1001, delivery_tab=tabd)
def tous_calculs(_):
dfp=tabp.df.dropna()
dest_col=tabp.dest_col.value
gdfadr=gpd.GeoDataFrame(pd.concat([
dfp[["suggestion", "geometry_p"]].rename(columns={"suggestion" : "lieu", "geometry_p": "geometry"}),
tabd.df[[dest_col, "geometry"]][tabd.df[dest_col].isin(tabp.df.dropna()[dest_col])].rename(columns={dest_col : "lieu"})],
keys=["p", "d"], names=['type', 'oid']).drop_duplicates().reset_index() )
ladr=gdfadr["lieu"].to_list()
mat_dist, mat_dur=fetch_matrices(gdfadr)
fig_dist, fig_dur=mat_figs(gdfadr, mat_dist, mat_dur)
tabs.append(('Matrice de distances', pn.pane.Plotly(fig_dist, width=1100, height=1000 )))
tabs.append(('Matrice de durées', pn.pane.Plotly(fig_dur, width=1100, height=1000 )))
sol=calcul_routes(dfp, ladr, mat_dist, mat_dur, duree_taxi.value, duree_ecole.value, capacité.value)
gpu=dfp.loc[list({u["id"] for u in sol.to_dict()["unassigned"]})][['suggestion', 'indice_destination', dest_col, 'arrivée_max']].copy()
gpu["Distance (km)"]=gpu.apply(lambda row: mat_dist[ladr.index(row["suggestion"])][ladr.index( row[dest_col])], axis=1)
gpu["Durée (min)"]=gpu.apply(lambda row: mat_dur[ladr.index( row["suggestion"])][ladr.index( row[dest_col])]//60, axis=1)
tabs.append(('Non assignés', pn.widgets.Tabulator(gpu, disabled=True, height=1000)))
dffinal=mise_en_forme_dfinal(sol, gdfadr)
tab_final=pn.widgets.Tabulator(dffinal.drop("geometry", axis=1).value_counts().reset_index().sort_values(by=["num_vehicule", "heure"]).reset_index(drop=True),
formatters={"heure" : DateFormatter(format="%H:%M")},
disabled=True,
height=1000)
tabs.append(('Tableau des résultats', tab_final.style.map(lambda v: f'background-color:{pal[v]};color:white', subset="num_vehicule")))
dres=fetch_itinéraires(dffinal)
m=carte(dffinal, dres, gdfadr)
tabs.append(('Carte des résultats', pn.pane.plot.Folium(m, height=1000) ))
return
bouton=pn.widgets.Button(name="Lancer les calculs", button_type="primary", on_click=tous_calculs)
tabs=pn.Tabs(
('Destinations', tabd.get_panel()),
('Usagers', tabp.get_panel()),
('Calculs des routes', pn.Column(duree_taxi, duree_ecole, capacité, bouton) ), )
template= pn.template.MaterialTemplate(title="Problème de tournée des véhicules avec capacités et fenêtre temporelle")
template.main.append(tabs)
template.header.append("v0.2.3")
template.servable() |