複数のシナリオを比較できる施設配置最適化のweb appを作ってください。
To upload files, please first save the app
import streamlit as st
import pandas as pd
import numpy as np
import folium
from streamlit_folium import folium_static
from pulp import *
import json
st.set_page_config(layout="wide")
st.title("施設配置最適化シミュレーター")
# セッション状態の初期化
if 'scenarios' not in st.session_state:
st.session_state.scenarios = {}
# サイドバーでシナリオ管理
with st.sidebar:
st.header("シナリオ管理")
scenario_name = st.text_input("シナリオ名", "新規シナリオ")
# 需要地点の設定
st.subheader("需要地点の設定")
n_demand = st.number_input("需要地点数", min_value=1, value=3)
demand_points = []
for i in range(n_demand):
col1, col2, col3 = st.columns(3)
with col1:
lat = st.number_input(f"需要地点{i+1} 緯度", value=35.0 + np.random.random()*0.1)
with col2:
lon = st.number_input(f"需要地点{i+1} 経度", value=135.0 + np.random.random()*0.1)
with col3:
demand = st.number_input(f"需要量{i+1}", value=100)
demand_points.append({"lat": lat, "lon": lon, "demand": demand})
# 候補地点の設定
st.subheader("施設候補地点の設定")
n_facility = st.number_input("候補地点数", min_value=1, value=5)
facility_points = []
for i in range(n_facility):
col1, col2, col3 = st.columns(3)
with col1:
lat = st.number_input(f"候補地点{i+1} 緯度", value=35.0 + np.random.random()*0.1)
with col2:
lon = st.number_input(f"候補地点{i+1} 経度", value=135.0 + np.random.random()*0.1)
with col3:
cost = st.number_input(f"建設コスト{i+1}", value=1000)
facility_points.append({"lat": lat, "lon": lon, "cost": cost})
# 制約条件
st.subheader("制約条件")
max_facilities = st.number_input("設置可能な施設数", min_value=1, value=3)
max_distance = st.number_input("最大サービス距離 (km)", min_value=0.1, value=10.0)
if st.button("シナリオを保存"):
st.session_state.scenarios[scenario_name] = {
"demand_points": demand_points,
"facility_points": facility_points,
"max_facilities": max_facilities,
"max_distance": max_distance
}
st.success(f"シナリオ '{scenario_name}' を保存しました!")
# メイン画面での表示と最適化
col1, col2 = st.columns([2, 1])
with col1:
# 地図表示
m = folium.Map(location=[35.0, 135.0], zoom_start=10)
# 現在のシナリオのポイントを表示
for dp in demand_points:
folium.CircleMarker(
location=[dp["lat"], dp["lon"]],
radius=10,
color="blue",
fill=True,
popup=f"需要量: {dp['demand']}"
).add_to(m)
for fp in facility_points:
folium.CircleMarker(
location=[fp["lat"], fp["lon"]],
radius=10,
color="red",
fill=True,
popup=f"コスト: {fp['cost']}"
).add_to(m)
folium_static(m)
with col2:
st.header("シナリオ比較")
# 保存されたシナリオの表示
st.subheader("保存されたシナリオ")
for name in st.session_state.scenarios.keys():
st.write(f"- {name}")
# シナリオの選択と最適化
selected_scenarios = st.multiselect(
"比較するシナリオを選択",
options=list(st.session_state.scenarios.keys())
)
if st.button("選択したシナリオを最適化"):
results = {}
for scenario_name in selected_scenarios:
scenario = st.session_state.scenarios[scenario_name]
# 最適化の実行
prob = LpProblem("Facility_Location", LpMinimize)
# 決定変数
x = {i: LpVariable(f"facility_{i}", 0, 1, LpBinary)
for i in range(len(scenario["facility_points"]))}
y = {(i,j): LpVariable(f"assign_{i}_{j}", 0, 1, LpBinary)
for i in range(len(scenario["facility_points"]))
for j in range(len(scenario["demand_points"]))}
# 目的関数(総コスト最小化)
prob += lpSum([scenario["facility_points"][i]["cost"] * x[i]
for i in range(len(scenario["facility_points"]))])
# 制約条件
# 施設数制限
prob += lpSum([x[i] for i in range(len(scenario["facility_points"]))]) <= scenario["max_facilities"]
# 需要点の割り当て制約
for j in range(len(scenario["demand_points"])):
prob += lpSum([y[i,j] for i in range(len(scenario["facility_points"]))]) == 1
# 施設が開設されている場合のみ割り当て可能
for i in range(len(scenario["facility_points"])):
for j in range(len(scenario["demand_points"])):
prob += y[i,j] <= x[i]
# 問題を解く
prob.solve()
# 結果を保存
results[scenario_name] = {
"status": LpStatus[prob.status],
"total_cost": value(prob.objective),
"selected_facilities": [i for i in range(len(scenario["facility_points"])) if value(x[i]) > 0.5],
"assignments": {j: [i for i in range(len(scenario["facility_points"])) if value(y[i,j]) > 0.5][0]
for j in range(len(scenario["demand_points"]))}
}
# 結果の表示
st.subheader("最適化結果")
for name, result in results.items():
st.write(f"\nシナリオ: {name}")
st.write(f"ステータス: {result['status']}")
st.write(f"総コスト: {result['total_cost']:,.0f}")
st.write(f"選択された施設: {result['selected_facilities']}")
st.write("需要地点の割り当て:", result['assignments'])
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?