Spaces:
Build error
Build error
| 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("注)各拠点にヘリが停まれるかどうかは無視") |