Spaces:
Sleeping
Sleeping
File size: 5,720 Bytes
efe5623 |
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
import numpy as np
import pandas as pd
from scipy.spatial import distance_matrix
import streamlit as st
from streamlit_folium import folium_static
import folium
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
# マップ及びマップの初期座標、初期ズームの指定
m = folium.Map(location=[35.4122, 137.4130], zoom_start=6)
# 緯度、経度のDataFrameを作成
data = pd.DataFrame(
[
["東京", 35.4122, 139.4130],
["千葉", 35.6047, 140.1233],
["山梨", 35.6638, 138.5683],
["宮城", 38.2688, 140.8719],
["新潟", 37.9022, 139.0236],
["長野", 36.6513, 138.1811],
["福島", 37.7500, 140.4677],
["栃木", 36.5658, 139.8836],
["石川", 36.5944, 136.6255],
["福井", 36.0652, 136.2219],
["静岡", 34.9769, 138.3830],
["岐阜", 35.3911, 136.7222],
["三重", 34.7302, 136.5086],
["愛知", 35.1802, 136.9066],
["京都", 35.0213, 135.7555],
["和歌山", 34.2261,135.1675],
["鳥取", 35.5036, 134.2383],
["島根", 35.4722, 133.0505],
["隠岐の島", 36.1200, 133.1000],
#["", , ],
["広島", 34.3963, 132.4594],
["高知", 33.5597, 133.5311],
["福岡", 33.6063, 130.4180],
["大島", 34.7570, 139.3574],
["八丈島", 33.1024, 139.7990],
["鹿児島", 31.5602, 130.5580],
]
)
data.columns = ["place", "latitude", "longitude"]
### サイドバー
# ヘリの台数
vehicle_num = st.sidebar.selectbox('ヘリの台数',(1, 2, 3, 4))
# 県を選択するマルチラベル(出発点の東京除く)
prefecture = st.sidebar.multiselect('出発点の東京除くマーカーを表示する県を選択してください',list(data[data.place!="東京"].place) ,
list(data[data.place!="東京"].place)
) #例
# 東京を追加
prefecture = pd.concat(
[
data[data.place=="東京"].place,
data.place[data.place.isin(prefecture)]
]
)
data = data[data["place"].isin(prefecture)]
### タイトル
st.title(f"出発点東京 {len(data)}拠点 ヘリ{vehicle_num}機のルート最適化")
# 距離行列
data_matrix = pd.DataFrame(
distance_matrix(data[["latitude", "longitude"]].values,
data[["latitude", "longitude"]].values),
index=data["place"],
columns=data["place"]
)
### 以下、数理最適化
manager = pywrapcp.RoutingIndexManager(
len(data),
vehicle_num, # 車両台数
0 # 出発点のindex
)
routing = pywrapcp.RoutingModel(manager)
def distance_callback(from_index, to_index):
"""Returns the distance between the two nodes."""
# Convert from routing variable Index to distance matrix NodeIndex.
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data_matrix.values.tolist()[from_node][to_node]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
dimension_name = 'Distance'
routing.AddDimension(
transit_callback_index,
0, # no slack
3000, # vehicle maximum travel distance
True, # start cumul to zero
dimension_name)
distance_dimension = routing.GetDimensionOrDie(dimension_name)
distance_dimension.SetGlobalSpanCostCoefficient(100)
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
solution = routing.SolveWithParameters(search_parameters)
def get_routes(solution, routing, manager):
"""Get vehicle routes from a solution and store them in an array."""
# Get vehicle routes and store them in a two dimensional array whose
# i,j entry is the jth location visited by vehicle i along its route.
routes = []
for route_nbr in range(routing.vehicles()):
index = routing.Start(route_nbr)
route = [manager.IndexToNode(index)]
while not routing.IsEnd(index):
index = solution.Value(routing.NextVar(index))
route.append(manager.IndexToNode(index))
routes.append(route)
return routes
routes = get_routes(solution, routing, manager)
### 以上、数理最適化
# 線で結ぶ
sq = [] # 座標を格納するリスト
color_list = [] # 色指定用のリスト
# sq、color_list の入力
for i in range(len(routes)):
sq = sq + data.iloc[routes[i], 1:3].values.tolist()
color_list = color_list + [i] * len(routes[i])
# order 経路順の作成
place_index = [0]
order_num = [0]
for i in range(len(routes)):
for j in range(1, len(routes[i]) -1):
place_index = place_index + [routes[i][j]]
order_num = order_num + [j]
order = pd.DataFrame(
[
order_num,
place_index
]
).T
order.columns = ["order_num", "place_index"]
order = order.sort_values("place_index").reset_index()["order_num"]
# 経路の作成
folium.ColorLine( # 色付きの線をマップに表示
positions=sq, # 座標
colors= color_list, # 色
weight=3 # 線の太さ
).add_to(m)
# マーカーの表示
for i in range(len(data)):
popup = folium.Popup(
html= f"{order[i]}",
max_width=1000,
show=False
)
folium.Circle(
location = data[["latitude", "longitude"]].values.tolist()[i],
popup=popup,
parse_html=True,
color = "red",
radius = 10000.0,
fill = True
).add_to(m)
# 地図をブラウザに表示
folium_static(m)
st.write("注)各拠点にヘリが停まれるかどうかは無視") |