Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -8,128 +8,117 @@ 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
|
26 |
lon_deg = meters / (111320 * np.cos(np.radians(lat)))
|
27 |
|
28 |
return lat_deg, lon_deg
|
29 |
|
30 |
-
def create_artistic_map(
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
- lon (float): Longitude of the center point
|
37 |
-
- distance (float): Radius of the map in meters
|
38 |
-
- dpi (int): Resolution of the output image in DPI
|
39 |
-
- width (int): Width of the output image in inches
|
40 |
-
- height (int): Height of the output image in inches
|
41 |
-
- bg_color (str): Background color in hex code
|
42 |
-
- greenery_color (str): Color for greenery in hex code
|
43 |
-
- water_color (str): Color for water bodies in hex code
|
44 |
-
- building_colors (list): List of colors for buildings in hex codes
|
45 |
-
- major_road_color (str): Color for major roads in hex code
|
46 |
-
- medium_road_color (str): Color for medium roads in hex code
|
47 |
-
- minor_road_color (str): Color for minor roads in hex code
|
48 |
-
|
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'},
|
72 |
-
{'landuse': 'grass'},
|
73 |
-
{'landuse': 'forest'},
|
74 |
-
{'natural': 'wood'}
|
75 |
-
]
|
76 |
-
for tags in greenery_tags:
|
77 |
-
greenery_part = ox.features_from_point(point, tags=tags, dist=distance)
|
78 |
-
if not greenery_part.empty:
|
79 |
-
greenery_list.append(greenery_part)
|
80 |
-
|
81 |
-
if greenery_list:
|
82 |
-
greenery = pd.concat(greenery_list)
|
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
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
# 水域の描画
|
98 |
-
if
|
99 |
-
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
# 建物の描画
|
102 |
-
if
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
|
|
|
|
|
|
109 |
# 道路の描画
|
110 |
-
if
|
111 |
-
#
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
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)
|
@@ -143,7 +132,7 @@ st.title("カラフルな地図が作成できます")
|
|
143 |
# デフォルト値を設定
|
144 |
default_lat = 35.533283
|
145 |
default_lon = 139.642000
|
146 |
-
default_distance =
|
147 |
|
148 |
# ユーザー入力
|
149 |
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f")
|
@@ -151,25 +140,66 @@ lon = st.number_input("経度を入力してください", value=default_lon, fo
|
|
151 |
distance = st.number_input("距離を選択(km)", value=default_distance, format="%.2f")
|
152 |
|
153 |
# 画像設定
|
154 |
-
dpi = st.number_input(
|
155 |
-
label="画像のDPI(解像度)を選択", # Input label
|
156 |
-
value=72, # Default value
|
157 |
-
format="%d" # Format for integers
|
158 |
-
)
|
159 |
width = st.slider("画像の幅(インチ)を選択", 5, 30, 20)
|
160 |
height = st.slider("画像の高さ(インチ)を選択", 5, 30, 20)
|
161 |
|
162 |
-
#
|
|
|
|
|
|
|
163 |
bg_color = st.color_picker("背景色を選択", "#FAF3E0")
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
|
174 |
# マップ生成ボタン
|
175 |
if st.button("マップを生成"):
|
@@ -177,6 +207,8 @@ if st.button("マップを生成"):
|
|
177 |
map_image = create_artistic_map(
|
178 |
lat, lon, distance*1000, dpi, width, height,
|
179 |
bg_color, greenery_color, water_color, building_colors,
|
180 |
-
major_road_color, medium_road_color, minor_road_color
|
|
|
|
|
181 |
)
|
182 |
st.image(map_image, caption="生成されたアートマップ", use_column_width=True)
|
|
|
8 |
import numpy as np
|
9 |
|
10 |
def meters_to_degrees(meters, lat):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
# 緯度1度あたりの距離は常に約111.32km
|
12 |
lat_deg = meters / 111320
|
13 |
|
14 |
+
# 経度1度あたりの距離は緯度によって変わる
|
15 |
lon_deg = meters / (111320 * np.cos(np.radians(lat)))
|
16 |
|
17 |
return lat_deg, lon_deg
|
18 |
|
19 |
+
def create_artistic_map(
|
20 |
+
lat, lon, distance, dpi, width, height, bg_color, greenery_color, water_color,
|
21 |
+
building_colors, major_road_color, medium_road_color, minor_road_color,
|
22 |
+
display_greenery, display_water, display_buildings,
|
23 |
+
display_major_roads, display_medium_roads, display_minor_roads
|
24 |
+
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
# 中心点の設定
|
26 |
point = (lat, lon)
|
27 |
+
|
28 |
# 距離をもとに緯度経度の幅と高さを計算
|
29 |
lat_deg, lon_deg = meters_to_degrees(distance, lat)
|
30 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
# 描画設定
|
32 |
fig, ax = plt.subplots(figsize=(width, height))
|
33 |
+
|
34 |
# 背景色を設定
|
35 |
fig.patch.set_facecolor(bg_color)
|
36 |
ax.set_facecolor(bg_color)
|
37 |
+
|
38 |
# 緑地の描画
|
39 |
+
if display_greenery:
|
40 |
+
# 緑地データ取得
|
41 |
+
greenery_list = []
|
42 |
+
greenery_tags = [
|
43 |
+
{'leisure': 'park'},
|
44 |
+
{'leisure': 'garden'},
|
45 |
+
{'landuse': 'grass'},
|
46 |
+
{'landuse': 'forest'},
|
47 |
+
{'landuse': 'meadow'},
|
48 |
+
{'natural': 'wood'},
|
49 |
+
{'natural': 'scrub'},
|
50 |
+
{'natural': 'grassland'},
|
51 |
+
{'natural': 'heath'}
|
52 |
+
]
|
53 |
+
for tags in greenery_tags:
|
54 |
+
greenery_part = ox.features_from_point(point, tags=tags, dist=distance)
|
55 |
+
if not greenery_part.empty:
|
56 |
+
greenery_list.append(greenery_part)
|
57 |
+
if greenery_list:
|
58 |
+
greenery = pd.concat(greenery_list)
|
59 |
+
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none')
|
60 |
+
|
61 |
# 水域の描画
|
62 |
+
if display_water:
|
63 |
+
# 水域データ取得
|
64 |
+
water_list = []
|
65 |
+
water_tags = [
|
66 |
+
{'natural': 'water'},
|
67 |
+
{'waterway': 'riverbank'},
|
68 |
+
{'landuse': 'reservoir'},
|
69 |
+
{'landuse': 'basin'},
|
70 |
+
{'natural': 'wetland'}
|
71 |
+
]
|
72 |
+
for tags in water_tags:
|
73 |
+
water_part = ox.features_from_point(point, tags=tags, dist=distance)
|
74 |
+
if not water_part.empty:
|
75 |
+
water_list.append(water_part)
|
76 |
+
if water_list:
|
77 |
+
water = pd.concat(water_list)
|
78 |
+
water.plot(ax=ax, facecolor=water_color, edgecolor='none')
|
79 |
+
|
80 |
# 建物の描画
|
81 |
+
if display_buildings:
|
82 |
+
# 建物データ取得
|
83 |
+
buildings = ox.features_from_point(point, tags={'building': True}, dist=distance)
|
84 |
+
if not buildings.empty:
|
85 |
+
building_types = buildings['building'].unique()
|
86 |
+
for i, building_type in enumerate(building_types):
|
87 |
+
building_subset = buildings[buildings['building'] == building_type]
|
88 |
+
building_color = building_colors[i % len(building_colors)]
|
89 |
+
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none')
|
90 |
+
|
91 |
# 道路の描画
|
92 |
+
if display_major_roads or display_medium_roads or display_minor_roads:
|
93 |
+
# OSMデータ取得
|
94 |
+
G = ox.graph_from_point(point, dist=distance, network_type='all')
|
95 |
+
nodes, edges = ox.graph_to_gdfs(G)
|
96 |
+
if not edges.empty and 'highway' in edges.columns:
|
97 |
+
# 主要道路の描画
|
98 |
+
if display_major_roads:
|
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 |
+
if display_medium_roads:
|
105 |
+
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])]
|
106 |
+
if not medium_roads.empty:
|
107 |
+
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color)
|
108 |
+
|
109 |
+
# 小規模な道路の描画
|
110 |
+
if display_minor_roads:
|
111 |
+
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])]
|
112 |
+
if not minor_roads.empty:
|
113 |
+
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color)
|
114 |
+
|
115 |
# 軸をオフに設定
|
116 |
ax.axis('off')
|
117 |
+
|
118 |
+
# 表示範囲を設定
|
119 |
ax.set_xlim([lon - lon_deg, lon + lon_deg])
|
120 |
ax.set_ylim([lat - lat_deg, lat + lat_deg])
|
121 |
+
|
122 |
# バッファに保存して、PIL画像として返す
|
123 |
buf = io.BytesIO()
|
124 |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi)
|
|
|
132 |
# デフォルト値を設定
|
133 |
default_lat = 35.533283
|
134 |
default_lon = 139.642000
|
135 |
+
default_distance = 1.0 # キロメートル
|
136 |
|
137 |
# ユーザー入力
|
138 |
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f")
|
|
|
140 |
distance = st.number_input("距離を選択(km)", value=default_distance, format="%.2f")
|
141 |
|
142 |
# 画像設定
|
143 |
+
dpi = st.number_input("画像のDPI(解像度)を選択", value=72, format="%d")
|
|
|
|
|
|
|
|
|
144 |
width = st.slider("画像の幅(インチ)を選択", 5, 30, 20)
|
145 |
height = st.slider("画像の高さ(インチ)を選択", 5, 30, 20)
|
146 |
|
147 |
+
# 表示設定
|
148 |
+
st.header("表示設定")
|
149 |
+
|
150 |
+
# 背景色
|
151 |
bg_color = st.color_picker("背景色を選択", "#FAF3E0")
|
152 |
+
|
153 |
+
# 緑地の設定
|
154 |
+
st.subheader("緑地の設定")
|
155 |
+
display_greenery = st.checkbox("緑地を表示", value=True)
|
156 |
+
if display_greenery:
|
157 |
+
greenery_color = st.color_picker("緑地の色を選択", "#80C341")
|
158 |
+
else:
|
159 |
+
greenery_color = None
|
160 |
+
|
161 |
+
# 水域の設定
|
162 |
+
st.subheader("水域の設定")
|
163 |
+
display_water = st.checkbox("水域を表示", value=True)
|
164 |
+
if display_water:
|
165 |
+
water_color = st.color_picker("水域の色を選択", "#45A6FF")
|
166 |
+
else:
|
167 |
+
water_color = None
|
168 |
+
|
169 |
+
# 建物の設定
|
170 |
+
st.subheader("建物の設定")
|
171 |
+
display_buildings = st.checkbox("建物を表示", value=True)
|
172 |
+
if display_buildings:
|
173 |
+
default_building_colors = ['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080']
|
174 |
+
building_colors = [
|
175 |
+
st.color_picker(f"建物の色 {i+1}", default_color)
|
176 |
+
for i, default_color in enumerate(default_building_colors)
|
177 |
+
]
|
178 |
+
else:
|
179 |
+
building_colors = []
|
180 |
+
|
181 |
+
# 道路の設定
|
182 |
+
st.subheader("道路の設定")
|
183 |
+
# 主要道路
|
184 |
+
display_major_roads = st.checkbox("主要道路を表示", value=True)
|
185 |
+
if display_major_roads:
|
186 |
+
major_road_color = st.color_picker("主要道路の色を選択", "#FF6347")
|
187 |
+
else:
|
188 |
+
major_road_color = None
|
189 |
+
|
190 |
+
# 中程度の道路
|
191 |
+
display_medium_roads = st.checkbox("中程度の道路を表示", value=True)
|
192 |
+
if display_medium_roads:
|
193 |
+
medium_road_color = st.color_picker("中程度の道路の色を選択", "#FF4500")
|
194 |
+
else:
|
195 |
+
medium_road_color = None
|
196 |
+
|
197 |
+
# 小規模な道路
|
198 |
+
display_minor_roads = st.checkbox("小規模な道路を表示", value=True)
|
199 |
+
if display_minor_roads:
|
200 |
+
minor_road_color = st.color_picker("小規模な道路の色を選択", "#D2691E")
|
201 |
+
else:
|
202 |
+
minor_road_color = None
|
203 |
|
204 |
# マップ生成ボタン
|
205 |
if st.button("マップを生成"):
|
|
|
207 |
map_image = create_artistic_map(
|
208 |
lat, lon, distance*1000, dpi, width, height,
|
209 |
bg_color, greenery_color, water_color, building_colors,
|
210 |
+
major_road_color, medium_road_color, minor_road_color,
|
211 |
+
display_greenery, display_water, display_buildings,
|
212 |
+
display_major_roads, display_medium_roads, display_minor_roads
|
213 |
)
|
214 |
st.image(map_image, caption="生成されたアートマップ", use_column_width=True)
|