Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -6,320 +6,209 @@ import pandas as pd
|
|
6 |
import io
|
7 |
from PIL import Image
|
8 |
import numpy as np
|
9 |
-
|
10 |
-
|
11 |
|
12 |
def meters_to_degrees(meters, lat):
|
|
|
|
|
|
|
13 |
lat_deg = meters / 111320
|
14 |
lon_deg = meters / (111320 * np.cos(np.radians(lat)))
|
15 |
return lat_deg, lon_deg
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
# 中心点の設定
|
38 |
point = (lat, lon)
|
39 |
-
|
40 |
# 距離をもとに緯度経度の幅と高さを計算
|
41 |
lat_deg, lon_deg = meters_to_degrees(distance, lat)
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
# 描画設定
|
44 |
fig, ax = plt.subplots(figsize=(width, height))
|
45 |
-
|
46 |
# 背景色を設定
|
47 |
fig.patch.set_facecolor(bg_color)
|
48 |
ax.set_facecolor(bg_color)
|
49 |
-
|
50 |
-
# 進捗を更新
|
51 |
-
current_step += 1
|
52 |
-
elapsed_time = time.time() - start_time
|
53 |
-
estimated_total_time = (elapsed_time / current_step) * total_steps
|
54 |
-
remaining_time = estimated_total_time - elapsed_time
|
55 |
-
progress_percent = int((current_step / total_steps) * 100)
|
56 |
-
progress_bar.progress(progress_percent)
|
57 |
-
time_placeholder.text(f"残り時間: 約{int(remaining_time // 60)}分{int(remaining_time % 60)}秒")
|
58 |
|
59 |
# 緑地の描画
|
60 |
-
if
|
61 |
-
|
62 |
-
greenery_list = []
|
63 |
-
greenery_tags = [
|
64 |
-
{'leisure': 'park'},
|
65 |
-
{'leisure': 'garden'},
|
66 |
-
{'landuse': 'grass'},
|
67 |
-
{'landuse': 'forest'},
|
68 |
-
{'landuse': 'meadow'},
|
69 |
-
{'natural': 'wood'},
|
70 |
-
{'natural': 'scrub'},
|
71 |
-
{'natural': 'grassland'},
|
72 |
-
{'natural': 'heath'}
|
73 |
-
]
|
74 |
-
for tags in greenery_tags:
|
75 |
-
try:
|
76 |
-
greenery_part = ox.features_from_point(point, tags=tags, dist=distance)
|
77 |
-
if not greenery_part.empty:
|
78 |
-
greenery_list.append(greenery_part)
|
79 |
-
except (InsufficientResponseError, EmptyOverpassResponse):
|
80 |
-
continue
|
81 |
-
except Exception as e:
|
82 |
-
st.warning(f"緑地データ取得中にエラーが発生しました: {e}")
|
83 |
-
continue
|
84 |
-
if greenery_list:
|
85 |
-
greenery = pd.concat(greenery_list)
|
86 |
-
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none')
|
87 |
-
else:
|
88 |
-
st.warning("指定された範囲に緑地が見つかりませんでした。")
|
89 |
|
90 |
-
# 進捗を更新
|
91 |
-
current_step += 1
|
92 |
-
elapsed_time = time.time() - start_time
|
93 |
-
estimated_total_time = (elapsed_time / current_step) * total_steps
|
94 |
-
remaining_time = estimated_total_time - elapsed_time
|
95 |
-
progress_percent = int((current_step / total_steps) * 100)
|
96 |
-
progress_bar.progress(progress_percent)
|
97 |
-
time_placeholder.text(f"残り時間: 約{int(remaining_time // 60)}分{int(remaining_time % 60)}秒")
|
98 |
-
|
99 |
# 水域の描画
|
100 |
-
if
|
101 |
-
|
102 |
-
water_list = []
|
103 |
-
water_tags = [
|
104 |
-
{'natural': 'water'},
|
105 |
-
{'waterway': 'riverbank'},
|
106 |
-
{'landuse': 'reservoir'},
|
107 |
-
{'landuse': 'basin'},
|
108 |
-
{'natural': 'wetland'}
|
109 |
-
]
|
110 |
-
for tags in water_tags:
|
111 |
-
try:
|
112 |
-
water_part = ox.features_from_point(point, tags=tags, dist=distance)
|
113 |
-
if not water_part.empty:
|
114 |
-
water_list.append(water_part)
|
115 |
-
except (InsufficientResponseError, EmptyOverpassResponse):
|
116 |
-
continue
|
117 |
-
except Exception as e:
|
118 |
-
st.warning(f"水域データ取得中にエラーが発生しました: {e}")
|
119 |
-
continue
|
120 |
-
if water_list:
|
121 |
-
water = pd.concat(water_list)
|
122 |
-
water.plot(ax=ax, facecolor=water_color, edgecolor='none')
|
123 |
-
else:
|
124 |
-
st.warning("指定された範囲に水域が見つかりませんでした。")
|
125 |
|
126 |
-
# 進捗を更新
|
127 |
-
current_step += 1
|
128 |
-
elapsed_time = time.time() - start_time
|
129 |
-
estimated_total_time = (elapsed_time / current_step) * total_steps
|
130 |
-
remaining_time = estimated_total_time - elapsed_time
|
131 |
-
progress_percent = int((current_step / total_steps) * 100)
|
132 |
-
progress_bar.progress(progress_percent)
|
133 |
-
time_placeholder.text(f"残り時間: 約{int(remaining_time // 60)}分{int(remaining_time % 60)}秒")
|
134 |
-
|
135 |
# 建物の描画
|
136 |
-
if
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
building_types = buildings['building'].unique()
|
143 |
-
for i, building_type in enumerate(building_types):
|
144 |
-
building_subset = buildings[buildings['building'] == building_type]
|
145 |
-
building_color = building_colors[i % len(building_colors)]
|
146 |
-
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none')
|
147 |
-
else:
|
148 |
-
# 'building'カラムがない場合、すべて同じ色で表示
|
149 |
-
buildings.plot(ax=ax, facecolor=building_colors[0], edgecolor='none')
|
150 |
-
else:
|
151 |
-
st.warning("指定された範囲に建物が見つかりませんでした。")
|
152 |
-
except (InsufficientResponseError, EmptyOverpassResponse):
|
153 |
-
st.warning("指定された範囲に建物が見つかりませんでした。")
|
154 |
-
except Exception as e:
|
155 |
-
st.warning(f"建物データ取得中にエラーが発生しました: {e}")
|
156 |
|
157 |
-
# 進捗を更新
|
158 |
-
current_step += 1
|
159 |
-
elapsed_time = time.time() - start_time
|
160 |
-
estimated_total_time = (elapsed_time / current_step) * total_steps
|
161 |
-
remaining_time = estimated_total_time - elapsed_time
|
162 |
-
progress_percent = int((current_step / total_steps) * 100)
|
163 |
-
progress_bar.progress(progress_percent)
|
164 |
-
time_placeholder.text(f"残り時間: 約{int(remaining_time // 60)}分{int(remaining_time % 60)}秒")
|
165 |
-
|
166 |
# 道路の描画
|
167 |
-
if
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
if display_medium_roads:
|
183 |
-
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])]
|
184 |
-
if not medium_roads.empty:
|
185 |
-
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color)
|
186 |
-
else:
|
187 |
-
st.warning("指定された範囲に中程度の道路が見つかりませんでした。")
|
188 |
-
|
189 |
-
# 小規模な道路の描画
|
190 |
-
if display_minor_roads:
|
191 |
-
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])]
|
192 |
-
if not minor_roads.empty:
|
193 |
-
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color)
|
194 |
-
else:
|
195 |
-
st.warning("指定された範囲に小規模な道路が見つかりませんでした。")
|
196 |
-
else:
|
197 |
-
st.warning("指定された範囲に道路データが見つかりませんでした。")
|
198 |
-
except (InsufficientResponseError, EmptyOverpassResponse):
|
199 |
-
st.warning("指定された範囲に道路データが見つかりませんでした。")
|
200 |
-
except Exception as e:
|
201 |
-
st.warning(f"道路データ取得中にエラーが発生しました: {e}")
|
202 |
|
203 |
-
# 進捗を更新
|
204 |
-
current_step += 1
|
205 |
-
elapsed_time = time.time() - start_time
|
206 |
-
estimated_total_time = (elapsed_time / current_step) * total_steps
|
207 |
-
remaining_time = estimated_total_time - elapsed_time
|
208 |
-
progress_percent = int((current_step / total_steps) * 100)
|
209 |
-
progress_bar.progress(progress_percent)
|
210 |
-
time_placeholder.text(f"残り時間: 約{int(remaining_time // 60)}分{int(remaining_time % 60)}秒")
|
211 |
-
|
212 |
# 軸をオフに設定
|
213 |
ax.axis('off')
|
214 |
-
|
215 |
# 表示範囲を設定
|
216 |
ax.set_xlim([lon - lon_deg, lon + lon_deg])
|
217 |
ax.set_ylim([lat - lat_deg, lat + lat_deg])
|
218 |
|
219 |
-
#
|
220 |
-
current_step += 1
|
221 |
-
progress_percent = int((current_step / total_steps) * 100)
|
222 |
-
progress_bar.progress(progress_percent)
|
223 |
-
time_placeholder.text("最終処理中...")
|
224 |
-
|
225 |
-
# バッファに保存して、PIL画像として返す
|
226 |
buf = io.BytesIO()
|
227 |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi)
|
228 |
plt.close()
|
229 |
buf.seek(0)
|
230 |
-
|
231 |
-
# 進捗を100%に更新
|
232 |
-
progress_bar.progress(100)
|
233 |
-
time_placeholder.text("完了しました!")
|
234 |
-
|
235 |
return Image.open(buf)
|
236 |
|
237 |
# Streamlit UI
|
238 |
st.title("カラフルな地図が作成できます")
|
239 |
|
240 |
-
# デフォルト値を設定
|
241 |
-
default_lat = 35.533283
|
242 |
-
default_lon = 139.642000
|
243 |
-
default_distance = 1.0 # キロメートル
|
244 |
-
|
245 |
# ユーザー入力
|
246 |
-
|
247 |
-
lon = st.number_input("経度を入力してください", value=default_lon, format="%.6f")
|
248 |
-
distance = st.number_input("距離を選択(km)", value=default_distance, format="%.2f")
|
249 |
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
st.
|
263 |
-
display_greenery = st.checkbox("緑地を表示", value=True)
|
264 |
-
if display_greenery:
|
265 |
-
greenery_color = st.color_picker("緑地の色を選択", "#80C341")
|
266 |
-
else:
|
267 |
-
greenery_color = None
|
268 |
-
|
269 |
-
# 水域の設定
|
270 |
-
st.subheader("水域の設定")
|
271 |
-
display_water = st.checkbox("水域を表示", value=True)
|
272 |
-
if display_water:
|
273 |
-
water_color = st.color_picker("水域の色を選択", "#45A6FF")
|
274 |
-
else:
|
275 |
-
water_color = None
|
276 |
-
|
277 |
-
# 建物の設定
|
278 |
-
st.subheader("建物の設定")
|
279 |
-
display_buildings = st.checkbox("建物を表示", value=True)
|
280 |
-
if display_buildings:
|
281 |
-
default_building_colors = ['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080']
|
282 |
-
building_colors = [
|
283 |
-
st.color_picker(f"建物の色 {i+1}", default_color)
|
284 |
-
for i, default_color in enumerate(default_building_colors)
|
285 |
-
]
|
286 |
-
else:
|
287 |
-
building_colors = []
|
288 |
-
|
289 |
-
# 道路の設定
|
290 |
-
st.subheader("道路の設定")
|
291 |
-
# 主要道路
|
292 |
-
display_major_roads = st.checkbox("主要道路を表示", value=True)
|
293 |
-
if display_major_roads:
|
294 |
-
major_road_color = st.color_picker("主要道路の色を選択", "#FF6347")
|
295 |
else:
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
302 |
else:
|
303 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
|
305 |
-
#
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
minor_road_color = None
|
311 |
|
312 |
# マップ生成ボタン
|
313 |
if st.button("マップを生成"):
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
bg_color, greenery_color, water_color, building_colors,
|
320 |
-
major_road_color, medium_road_color, minor_road_color,
|
321 |
-
display_greenery, display_water, display_buildings,
|
322 |
-
display_major_roads, display_medium_roads, display_minor_roads,
|
323 |
-
progress_bar, time_placeholder
|
324 |
-
)
|
325 |
-
st.image(map_image, caption="生成されたアートマップ", use_column_width=True)
|
|
|
6 |
import io
|
7 |
from PIL import Image
|
8 |
import numpy as np
|
9 |
+
|
10 |
+
ox.settings.use_cache = True # OSMnxのキャッシュを有効化
|
11 |
|
12 |
def meters_to_degrees(meters, lat):
|
13 |
+
"""
|
14 |
+
距離(メートル)を緯度・経度の変化量(度)に変換する。
|
15 |
+
"""
|
16 |
lat_deg = meters / 111320
|
17 |
lon_deg = meters / (111320 * np.cos(np.radians(lat)))
|
18 |
return lat_deg, lon_deg
|
19 |
|
20 |
+
@st.cache_data
|
21 |
+
def fetch_osm_data(point, distance):
|
22 |
+
"""
|
23 |
+
指定した地点と距離に基づいて、OSMデータ(ノード、エッジ、フィーチャ)を取得する。
|
24 |
+
"""
|
25 |
+
tags = {
|
26 |
+
'building': True,
|
27 |
+
'natural': ['water', 'wood'],
|
28 |
+
'landuse': ['grass', 'forest'],
|
29 |
+
'leisure': 'park'
|
30 |
+
}
|
31 |
+
# グラフデータの取得
|
32 |
+
G = ox.graph_from_point(point, dist=distance, network_type='all')
|
33 |
+
nodes, edges = ox.graph_to_gdfs(G)
|
34 |
+
# フィーチャデータの取得
|
35 |
+
features = ox.geometries_from_point(point, tags, dist=distance)
|
36 |
+
return nodes, edges, features
|
37 |
+
|
38 |
+
def create_artistic_map(lat, lon, distance, dpi, width, height, colors):
|
39 |
+
"""
|
40 |
+
指定されたパラメータに基づいて、カスタマイズ可能なアートマップ画像を作成する。
|
41 |
+
"""
|
42 |
+
# カラー設定の取得
|
43 |
+
bg_color = colors['bg_color']
|
44 |
+
greenery_color = colors['greenery_color']
|
45 |
+
water_color = colors['water_color']
|
46 |
+
building_colors = colors['building_colors']
|
47 |
+
major_road_color = colors['major_road_color']
|
48 |
+
medium_road_color = colors['medium_road_color']
|
49 |
+
minor_road_color = colors['minor_road_color']
|
50 |
|
51 |
# 中心点の設定
|
52 |
point = (lat, lon)
|
53 |
+
|
54 |
# 距離をもとに緯度経度の幅と高さを計算
|
55 |
lat_deg, lon_deg = meters_to_degrees(distance, lat)
|
56 |
+
|
57 |
+
# OSMデータ取得
|
58 |
+
nodes, edges, features = fetch_osm_data(point, distance)
|
59 |
+
|
60 |
+
# 建物データ取得
|
61 |
+
buildings = features[features['building'].notnull()]
|
62 |
+
|
63 |
+
# 水域データ取得
|
64 |
+
water = features[features['natural'] == 'water']
|
65 |
+
|
66 |
+
# 緑地データ取得(公園、草地、森林など)
|
67 |
+
greenery = features[
|
68 |
+
(features['leisure'] == 'park') |
|
69 |
+
(features['landuse'].isin(['grass', 'forest'])) |
|
70 |
+
(features['natural'] == 'wood')
|
71 |
+
]
|
72 |
+
|
73 |
# 描画設定
|
74 |
fig, ax = plt.subplots(figsize=(width, height))
|
75 |
+
|
76 |
# 背景色を設定
|
77 |
fig.patch.set_facecolor(bg_color)
|
78 |
ax.set_facecolor(bg_color)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
# 緑地の描画
|
81 |
+
if not greenery.empty:
|
82 |
+
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
# 水域の描画
|
85 |
+
if not water.empty:
|
86 |
+
water.plot(ax=ax, facecolor=water_color, edgecolor='none')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
# 建物の描画
|
89 |
+
if not buildings.empty:
|
90 |
+
building_types = buildings['building'].unique()
|
91 |
+
for i, building_type in enumerate(building_types):
|
92 |
+
building_subset = buildings[buildings['building'] == building_type]
|
93 |
+
building_color = building_colors[i % len(building_colors)]
|
94 |
+
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
# 道路の描画
|
97 |
+
if not edges.empty and 'highway' in edges.columns:
|
98 |
+
# 主要道路の描画
|
99 |
+
major_roads = edges[edges['highway'].isin(['motorway', 'trunk', 'primary'])]
|
100 |
+
if not major_roads.empty:
|
101 |
+
major_roads.plot(ax=ax, linewidth=2, edgecolor=major_road_color)
|
102 |
+
|
103 |
+
# 中程度の道路の描画
|
104 |
+
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])]
|
105 |
+
if not medium_roads.empty:
|
106 |
+
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color)
|
107 |
+
|
108 |
+
# 小規模な道路の描画
|
109 |
+
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])]
|
110 |
+
if not minor_roads.empty:
|
111 |
+
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
# 軸をオフに設定
|
114 |
ax.axis('off')
|
115 |
+
|
116 |
# 表示範囲を設定
|
117 |
ax.set_xlim([lon - lon_deg, lon + lon_deg])
|
118 |
ax.set_ylim([lat - lat_deg, lat + lat_deg])
|
119 |
|
120 |
+
# 画像をバッファに保存
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
buf = io.BytesIO()
|
122 |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi)
|
123 |
plt.close()
|
124 |
buf.seek(0)
|
|
|
|
|
|
|
|
|
|
|
125 |
return Image.open(buf)
|
126 |
|
127 |
# Streamlit UI
|
128 |
st.title("カラフルな地図が作成できます")
|
129 |
|
|
|
|
|
|
|
|
|
|
|
130 |
# ユーザー入力
|
131 |
+
location = st.text_input("場所を入力してください(住所、都市名など)")
|
|
|
|
|
132 |
|
133 |
+
default_lat = 35.533283
|
134 |
+
default_lon = 139.642000
|
135 |
+
default_distance = 1000
|
136 |
+
|
137 |
+
if location:
|
138 |
+
try:
|
139 |
+
geocode_result = ox.geocode(location)
|
140 |
+
lat, lon = geocode_result[0], geocode_result[1]
|
141 |
+
st.write(f"緯度: {lat}, 経度: {lon}")
|
142 |
+
except Exception as e:
|
143 |
+
st.error("場所の取得に失敗しました。緯度と経度を直接入力してください。")
|
144 |
+
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f")
|
145 |
+
lon = st.number_input("経度を入力してください", value=default_lon, format="%.6f")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
else:
|
147 |
+
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f")
|
148 |
+
lon = st.number_input("経度を入力してください", value=default_lon, format="%.6f")
|
149 |
+
|
150 |
+
distance = st.slider("距離を選択(メートル)", 100, 5000, default_distance)
|
151 |
+
|
152 |
+
# カラーテーマの設定
|
153 |
+
color_themes = {
|
154 |
+
'テーマ1': {
|
155 |
+
'bg_color': '#FAF3E0',
|
156 |
+
'greenery_color': '#80C341',
|
157 |
+
'water_color': '#45A6FF',
|
158 |
+
'building_colors': ['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080'],
|
159 |
+
'major_road_color': '#FF6347',
|
160 |
+
'medium_road_color': '#FF4500',
|
161 |
+
'minor_road_color': '#D2691E'
|
162 |
+
},
|
163 |
+
'テーマ2': {
|
164 |
+
'bg_color': '#FFFFFF',
|
165 |
+
'greenery_color': '#00FF00',
|
166 |
+
'water_color': '#0000FF',
|
167 |
+
'building_colors': ['#A52A2A', '#8B0000', '#B22222', '#FF0000', '#FF6347'],
|
168 |
+
'major_road_color': '#000000',
|
169 |
+
'medium_road_color': '#2F4F4F',
|
170 |
+
'minor_road_color': '#696969'
|
171 |
+
},
|
172 |
+
'カスタム': None
|
173 |
+
}
|
174 |
+
|
175 |
+
theme_name = st.selectbox("カラーテーマを選択", list(color_themes.keys()))
|
176 |
+
|
177 |
+
if theme_name != 'カスタム':
|
178 |
+
colors = color_themes[theme_name]
|
179 |
else:
|
180 |
+
# 色設定
|
181 |
+
with st.expander("カスタムカラーパレット"):
|
182 |
+
bg_color = st.color_picker("背景色を選択", "#FAF3E0")
|
183 |
+
greenery_color = st.color_picker("緑地の色を選択", "#80C341")
|
184 |
+
water_color = st.color_picker("水域の色を選択", "#45A6FF")
|
185 |
+
building_colors = [
|
186 |
+
st.color_picker(f"建物の色 {i+1}", default_color)
|
187 |
+
for i, default_color in enumerate(['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080'])
|
188 |
+
]
|
189 |
+
major_road_color = st.color_picker("主要道路の色を選択", "#FF6347")
|
190 |
+
medium_road_color = st.color_picker("中程度の道路の色を選択", "#FF4500")
|
191 |
+
minor_road_color = st.color_picker("小規模な道路の色を選択", "#D2691E")
|
192 |
+
colors = {
|
193 |
+
'bg_color': bg_color,
|
194 |
+
'greenery_color': greenery_color,
|
195 |
+
'water_color': water_color,
|
196 |
+
'building_colors': building_colors,
|
197 |
+
'major_road_color': major_road_color,
|
198 |
+
'medium_road_color': medium_road_color,
|
199 |
+
'minor_road_color': minor_road_color
|
200 |
+
}
|
201 |
|
202 |
+
# 画像設定
|
203 |
+
with st.expander("画像設定(オプション)"):
|
204 |
+
dpi = st.slider("画像のDPI(解像度)を選択", 72, 600, 300)
|
205 |
+
width = st.slider("画像の幅(インチ)を選択", 5, 30, 20)
|
206 |
+
height = st.slider("画像の高さ(インチ)を選択", 5, 30, 20)
|
|
|
207 |
|
208 |
# マップ生成ボタン
|
209 |
if st.button("マップを生成"):
|
210 |
+
with st.spinner('マップを生成中...'):
|
211 |
+
map_image = create_artistic_map(
|
212 |
+
lat, lon, distance, dpi, width, height, colors
|
213 |
+
)
|
214 |
+
st.image(map_image, caption="生成されたアートマップ", use_column_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|