Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -5,6 +5,27 @@ import geopandas as gpd
|
|
5 |
import pandas as pd
|
6 |
import io
|
7 |
from PIL import Image
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greenery_color, water_color, building_colors, major_road_color, medium_road_color, minor_road_color):
|
10 |
"""
|
@@ -28,25 +49,23 @@ def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greene
|
|
28 |
Returns:
|
29 |
- PIL.Image.Image: Generated map image
|
30 |
"""
|
31 |
-
#
|
32 |
point = (lat, lon)
|
33 |
|
34 |
-
#
|
35 |
-
|
36 |
|
37 |
-
#
|
38 |
-
G = ox.graph_from_point(point, dist=
|
39 |
-
|
40 |
-
# Get road data
|
41 |
nodes, edges = ox.graph_to_gdfs(G)
|
42 |
|
43 |
-
#
|
44 |
-
buildings = ox.features_from_point(point, tags={'building': True}, dist=
|
45 |
|
46 |
-
#
|
47 |
-
water = ox.features_from_point(point, tags={'natural': 'water'}, dist=
|
48 |
|
49 |
-
#
|
50 |
greenery_list = []
|
51 |
greenery_tags = [
|
52 |
{'leisure': 'park'},
|
@@ -64,22 +83,22 @@ def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greene
|
|
64 |
else:
|
65 |
greenery = gpd.GeoDataFrame()
|
66 |
|
67 |
-
#
|
68 |
fig, ax = plt.subplots(figsize=(width, height))
|
69 |
|
70 |
-
#
|
71 |
fig.patch.set_facecolor(bg_color)
|
72 |
ax.set_facecolor(bg_color)
|
73 |
|
74 |
-
#
|
75 |
if not greenery.empty:
|
76 |
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none')
|
77 |
|
78 |
-
#
|
79 |
if not water.empty:
|
80 |
water.plot(ax=ax, facecolor=water_color, edgecolor='none')
|
81 |
|
82 |
-
#
|
83 |
if not buildings.empty:
|
84 |
building_types = buildings['building'].unique()
|
85 |
for i, building_type in enumerate(building_types):
|
@@ -87,27 +106,31 @@ def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greene
|
|
87 |
building_color = building_colors[i % len(building_colors)]
|
88 |
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none')
|
89 |
|
90 |
-
#
|
91 |
if not edges.empty and 'highway' in edges.columns:
|
92 |
-
#
|
93 |
major_roads = edges[edges['highway'].isin(['motorway', 'trunk', 'primary'])]
|
94 |
if not major_roads.empty:
|
95 |
major_roads.plot(ax=ax, linewidth=2, edgecolor=major_road_color)
|
96 |
|
97 |
-
#
|
98 |
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])]
|
99 |
if not medium_roads.empty:
|
100 |
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color)
|
101 |
|
102 |
-
#
|
103 |
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])]
|
104 |
if not minor_roads.empty:
|
105 |
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color)
|
106 |
|
107 |
-
#
|
108 |
ax.axis('off')
|
109 |
|
110 |
-
#
|
|
|
|
|
|
|
|
|
111 |
buf = io.BytesIO()
|
112 |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi)
|
113 |
plt.close()
|
@@ -115,41 +138,41 @@ def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greene
|
|
115 |
return Image.open(buf)
|
116 |
|
117 |
# Streamlit UI
|
118 |
-
st.title("
|
119 |
|
120 |
-
#
|
121 |
default_lat = 35.533283
|
122 |
default_lon = 139.642000
|
123 |
-
default_distance =
|
124 |
-
|
125 |
-
#
|
126 |
-
lat = st.number_input("
|
127 |
-
lon = st.number_input("
|
128 |
-
distance = st.slider("
|
129 |
-
|
130 |
-
#
|
131 |
-
dpi = st.slider("
|
132 |
-
width = st.slider("
|
133 |
-
height = st.slider("
|
134 |
-
|
135 |
-
#
|
136 |
-
bg_color = st.color_picker("
|
137 |
-
greenery_color = st.color_picker("
|
138 |
-
water_color = st.color_picker("
|
139 |
building_colors = [
|
140 |
-
st.color_picker(f"
|
141 |
for i, default_color in enumerate(['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080'])
|
142 |
]
|
143 |
-
major_road_color = st.color_picker("
|
144 |
-
medium_road_color = st.color_picker("
|
145 |
-
minor_road_color = st.color_picker("
|
146 |
|
147 |
-
#
|
148 |
-
if st.button("
|
149 |
-
with st.spinner('
|
150 |
map_image = create_artistic_map(
|
151 |
lat, lon, distance, dpi, width, height,
|
152 |
bg_color, greenery_color, water_color, building_colors,
|
153 |
major_road_color, medium_road_color, minor_road_color
|
154 |
)
|
155 |
-
st.image(map_image, caption="
|
|
|
5 |
import pandas as pd
|
6 |
import io
|
7 |
from PIL import Image
|
8 |
+
import numpy as np
|
9 |
+
|
10 |
+
def meters_to_degrees(meters, lat):
|
11 |
+
"""
|
12 |
+
Convert meters to degrees for latitude and longitude.
|
13 |
+
|
14 |
+
Parameters:
|
15 |
+
- meters (float): Distance in meters
|
16 |
+
- lat (float): Latitude at which the conversion is done (as the conversion depends on latitude)
|
17 |
+
|
18 |
+
Returns:
|
19 |
+
- lat_deg (float): Change in degrees of latitude
|
20 |
+
- lon_deg (float): Change in degrees of longitude
|
21 |
+
"""
|
22 |
+
# 緯度1度あたりの距離は常に約111.32km
|
23 |
+
lat_deg = meters / 111320
|
24 |
+
|
25 |
+
# 経度1度あたりの距離は緯度によって変わる(赤道では約111.32kmだが、極に近づくと小さくなる)
|
26 |
+
lon_deg = meters / (111320 * np.cos(np.radians(lat)))
|
27 |
+
|
28 |
+
return lat_deg, lon_deg
|
29 |
|
30 |
def create_artistic_map(lat, lon, distance, dpi, width, height, bg_color, greenery_color, water_color, building_colors, major_road_color, medium_road_color, minor_road_color):
|
31 |
"""
|
|
|
49 |
Returns:
|
50 |
- PIL.Image.Image: Generated map image
|
51 |
"""
|
52 |
+
# 中心点の設定
|
53 |
point = (lat, lon)
|
54 |
|
55 |
+
# 距離をもとに緯度経度の幅と高さを計算
|
56 |
+
lat_deg, lon_deg = meters_to_degrees(distance, lat)
|
57 |
|
58 |
+
# OSMデータ取得
|
59 |
+
G = ox.graph_from_point(point, dist=distance, network_type='all')
|
|
|
|
|
60 |
nodes, edges = ox.graph_to_gdfs(G)
|
61 |
|
62 |
+
# 建物データ取得
|
63 |
+
buildings = ox.features_from_point(point, tags={'building': True}, dist=distance)
|
64 |
|
65 |
+
# 水域データ取得
|
66 |
+
water = ox.features_from_point(point, tags={'natural': 'water'}, dist=distance)
|
67 |
|
68 |
+
# 緑地データ取得(公園、草地、森林など)
|
69 |
greenery_list = []
|
70 |
greenery_tags = [
|
71 |
{'leisure': 'park'},
|
|
|
83 |
else:
|
84 |
greenery = gpd.GeoDataFrame()
|
85 |
|
86 |
+
# 描画設定
|
87 |
fig, ax = plt.subplots(figsize=(width, height))
|
88 |
|
89 |
+
# 背景色を設定
|
90 |
fig.patch.set_facecolor(bg_color)
|
91 |
ax.set_facecolor(bg_color)
|
92 |
|
93 |
+
# 緑地の描画
|
94 |
if not greenery.empty:
|
95 |
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none')
|
96 |
|
97 |
+
# 水域の描画
|
98 |
if not water.empty:
|
99 |
water.plot(ax=ax, facecolor=water_color, edgecolor='none')
|
100 |
|
101 |
+
# 建物の描画
|
102 |
if not buildings.empty:
|
103 |
building_types = buildings['building'].unique()
|
104 |
for i, building_type in enumerate(building_types):
|
|
|
106 |
building_color = building_colors[i % len(building_colors)]
|
107 |
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none')
|
108 |
|
109 |
+
# 道路の描画
|
110 |
if not edges.empty and 'highway' in edges.columns:
|
111 |
+
# 主要道路の描画
|
112 |
major_roads = edges[edges['highway'].isin(['motorway', 'trunk', 'primary'])]
|
113 |
if not major_roads.empty:
|
114 |
major_roads.plot(ax=ax, linewidth=2, edgecolor=major_road_color)
|
115 |
|
116 |
+
# 中程度の道路の描画
|
117 |
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])]
|
118 |
if not medium_roads.empty:
|
119 |
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color)
|
120 |
|
121 |
+
# 小規模な道路の描画
|
122 |
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])]
|
123 |
if not minor_roads.empty:
|
124 |
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color)
|
125 |
|
126 |
+
# 軸をオフに設定
|
127 |
ax.axis('off')
|
128 |
|
129 |
+
# 入力された距離をもとに表示範囲を正方形に設定
|
130 |
+
ax.set_xlim([lon - lon_deg, lon + lon_deg])
|
131 |
+
ax.set_ylim([lat - lat_deg, lat + lat_deg])
|
132 |
+
|
133 |
+
# バッファに保存して、PIL画像として返す
|
134 |
buf = io.BytesIO()
|
135 |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi)
|
136 |
plt.close()
|
|
|
138 |
return Image.open(buf)
|
139 |
|
140 |
# Streamlit UI
|
141 |
+
st.title("カスタマイズ可能なアートマップジェネレーター")
|
142 |
|
143 |
+
# デフォルト値を設定
|
144 |
default_lat = 35.533283
|
145 |
default_lon = 139.642000
|
146 |
+
default_distance = 1000
|
147 |
+
|
148 |
+
# ユーザー入力
|
149 |
+
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f")
|
150 |
+
lon = st.number_input("経度を入力してください", value=default_lon, format="%.6f")
|
151 |
+
distance = st.slider("距離を選択(メートル)", 100, 5000, default_distance)
|
152 |
+
|
153 |
+
# 画像設定
|
154 |
+
dpi = st.slider("画像のDPI(解像度)を選択", 72, 600, 300)
|
155 |
+
width = st.slider("画像の幅(インチ)を選択", 5, 30, 20)
|
156 |
+
height = st.slider("画像の高さ(インチ)を選択", 5, 30, 20)
|
157 |
+
|
158 |
+
# 色設定
|
159 |
+
bg_color = st.color_picker("背景色を選択", "#FAF3E0")
|
160 |
+
greenery_color = st.color_picker("緑地の色を選択", "#80C341")
|
161 |
+
water_color = st.color_picker("水域の色を選択", "#45A6FF")
|
162 |
building_colors = [
|
163 |
+
st.color_picker(f"建物の色 {i+1}", default_color)
|
164 |
for i, default_color in enumerate(['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080'])
|
165 |
]
|
166 |
+
major_road_color = st.color_picker("主要道路の色を選択", "#FF6347")
|
167 |
+
medium_road_color = st.color_picker("中程度の道路の色を選択", "#FF4500")
|
168 |
+
minor_road_color = st.color_picker("小規模な道路の色を選択", "#D2691E")
|
169 |
|
170 |
+
# マップ生成ボタン
|
171 |
+
if st.button("マップを生成"):
|
172 |
+
with st.spinner('マップを生成中...'):
|
173 |
map_image = create_artistic_map(
|
174 |
lat, lon, distance, dpi, width, height,
|
175 |
bg_color, greenery_color, water_color, building_colors,
|
176 |
major_road_color, medium_road_color, minor_road_color
|
177 |
)
|
178 |
+
st.image(map_image, caption="生成されたアートマップ", use_column_width=True)
|