Spaces:
Sleeping
Sleeping
import streamlit as st | |
import matplotlib.pyplot as plt | |
import osmnx as ox | |
import geopandas as gpd | |
import pandas as pd | |
import io | |
from PIL import Image | |
import numpy as np | |
def meters_to_degrees(meters, lat): | |
# 緯度1度あたりの距離は常に約111.32km | |
lat_deg = meters / 111320 | |
# 経度1度あたりの距離は緯度によって変わる | |
lon_deg = meters / (111320 * np.cos(np.radians(lat))) | |
return lat_deg, lon_deg | |
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, | |
display_greenery, display_water, display_buildings, | |
display_major_roads, display_medium_roads, display_minor_roads | |
): | |
# 中心点の設定 | |
point = (lat, lon) | |
# 距離をもとに緯度経度の幅と高さを計算 | |
lat_deg, lon_deg = meters_to_degrees(distance, lat) | |
# 描画設定 | |
fig, ax = plt.subplots(figsize=(width, height)) | |
# 背景色を設定 | |
fig.patch.set_facecolor(bg_color) | |
ax.set_facecolor(bg_color) | |
# 緑地の描画 | |
if display_greenery: | |
# 緑地データ取得 | |
greenery_list = [] | |
greenery_tags = [ | |
{'leisure': 'park'}, | |
{'leisure': 'garden'}, | |
{'landuse': 'grass'}, | |
{'landuse': 'forest'}, | |
{'landuse': 'meadow'}, | |
{'natural': 'wood'}, | |
{'natural': 'scrub'}, | |
{'natural': 'grassland'}, | |
{'natural': 'heath'} | |
] | |
for tags in greenery_tags: | |
greenery_part = ox.features_from_point(point, tags=tags, dist=distance) | |
if not greenery_part.empty: | |
greenery_list.append(greenery_part) | |
if greenery_list: | |
greenery = pd.concat(greenery_list) | |
greenery.plot(ax=ax, facecolor=greenery_color, edgecolor='none') | |
# 水域の描画 | |
if display_water: | |
# 水域データ取得 | |
water_list = [] | |
water_tags = [ | |
{'natural': 'water'}, | |
{'waterway': 'riverbank'}, | |
{'landuse': 'reservoir'}, | |
{'landuse': 'basin'}, | |
{'natural': 'wetland'} | |
] | |
for tags in water_tags: | |
water_part = ox.features_from_point(point, tags=tags, dist=distance) | |
if not water_part.empty: | |
water_list.append(water_part) | |
if water_list: | |
water = pd.concat(water_list) | |
water.plot(ax=ax, facecolor=water_color, edgecolor='none') | |
# 建物の描画 | |
if display_buildings: | |
# 建物データ取得 | |
buildings = ox.features_from_point(point, tags={'building': True}, dist=distance) | |
if not buildings.empty: | |
building_types = buildings['building'].unique() | |
for i, building_type in enumerate(building_types): | |
building_subset = buildings[buildings['building'] == building_type] | |
building_color = building_colors[i % len(building_colors)] | |
building_subset.plot(ax=ax, facecolor=building_color, edgecolor='none') | |
# 道路の描画 | |
if display_major_roads or display_medium_roads or display_minor_roads: | |
# OSMデータ取得 | |
G = ox.graph_from_point(point, dist=distance, network_type='all') | |
nodes, edges = ox.graph_to_gdfs(G) | |
if not edges.empty and 'highway' in edges.columns: | |
# 主要道路の描画 | |
if display_major_roads: | |
major_roads = edges[edges['highway'].isin(['motorway', 'trunk', 'primary'])] | |
if not major_roads.empty: | |
major_roads.plot(ax=ax, linewidth=2, edgecolor=major_road_color) | |
# 中程度の道路の描画 | |
if display_medium_roads: | |
medium_roads = edges[edges['highway'].isin(['secondary', 'tertiary'])] | |
if not medium_roads.empty: | |
medium_roads.plot(ax=ax, linewidth=1.5, edgecolor=medium_road_color) | |
# 小規模な道路の描画 | |
if display_minor_roads: | |
minor_roads = edges[~edges['highway'].isin(['motorway', 'trunk', 'primary', 'secondary', 'tertiary'])] | |
if not minor_roads.empty: | |
minor_roads.plot(ax=ax, linewidth=1, edgecolor=minor_road_color) | |
# 軸をオフに設定 | |
ax.axis('off') | |
# 表示範囲を設定 | |
ax.set_xlim([lon - lon_deg, lon + lon_deg]) | |
ax.set_ylim([lat - lat_deg, lat + lat_deg]) | |
# バッファに保存して、PIL画像として返す | |
buf = io.BytesIO() | |
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=dpi) | |
plt.close() | |
buf.seek(0) | |
return Image.open(buf) | |
# Streamlit UI | |
st.title("カラフルな地図が作成できます") | |
# デフォルト値を設定 | |
default_lat = 35.533283 | |
default_lon = 139.642000 | |
default_distance = 1.0 # キロメートル | |
# ユーザー入力 | |
lat = st.number_input("緯度を入力してください", value=default_lat, format="%.6f") | |
lon = st.number_input("経度を入力してください", value=default_lon, format="%.6f") | |
distance = st.number_input("距離を選択(km)", value=default_distance, format="%.2f") | |
# 画像設定 | |
dpi = st.number_input("画像のDPI(解像度)を選択", value=72, format="%d") | |
width = st.slider("画像の幅(インチ)を選択", 5, 30, 20) | |
height = st.slider("画像の高さ(インチ)を選択", 5, 30, 20) | |
# 表示設定 | |
st.header("表示設定") | |
# 背景色 | |
bg_color = st.color_picker("背景色を選択", "#FAF3E0") | |
# 緑地の設定 | |
st.subheader("緑地の設定") | |
display_greenery = st.checkbox("緑地を表示", value=True) | |
if display_greenery: | |
greenery_color = st.color_picker("緑地の色を選択", "#80C341") | |
else: | |
greenery_color = None | |
# 水域の設定 | |
st.subheader("水域の設定") | |
display_water = st.checkbox("水域を表示", value=True) | |
if display_water: | |
water_color = st.color_picker("水域の色を選択", "#45A6FF") | |
else: | |
water_color = None | |
# 建物の設定 | |
st.subheader("建物の設定") | |
display_buildings = st.checkbox("建物を表示", value=True) | |
if display_buildings: | |
default_building_colors = ['#FF6F61', '#FFAB73', '#FFA07A', '#FFD700', '#F08080'] | |
building_colors = [ | |
st.color_picker(f"建物の色 {i+1}", default_color) | |
for i, default_color in enumerate(default_building_colors) | |
] | |
else: | |
building_colors = [] | |
# 道路の設定 | |
st.subheader("道路の設定") | |
# 主要道路 | |
display_major_roads = st.checkbox("主要道路を表示", value=True) | |
if display_major_roads: | |
major_road_color = st.color_picker("主要道路の色を選択", "#FF6347") | |
else: | |
major_road_color = None | |
# 中程度の道路 | |
display_medium_roads = st.checkbox("中程度の道路を表示", value=True) | |
if display_medium_roads: | |
medium_road_color = st.color_picker("中程度の道路の色を選択", "#FF4500") | |
else: | |
medium_road_color = None | |
# 小規模な道路 | |
display_minor_roads = st.checkbox("小規模な道路を表示", value=True) | |
if display_minor_roads: | |
minor_road_color = st.color_picker("小規模な道路の色を選択", "#D2691E") | |
else: | |
minor_road_color = None | |
# マップ生成ボタン | |
if st.button("マップを生成"): | |
with st.spinner('マップを生成中...'): | |
map_image = create_artistic_map( | |
lat, lon, distance*1000, dpi, width, height, | |
bg_color, greenery_color, water_color, building_colors, | |
major_road_color, medium_road_color, minor_road_color, | |
display_greenery, display_water, display_buildings, | |
display_major_roads, display_medium_roads, display_minor_roads | |
) | |
st.image(map_image, caption="生成されたアートマップ", use_column_width=True) | |