Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,24 +1,15 @@
|
|
| 1 |
# app.py
|
| 2 |
-
# HF Spaces (Gradio) で japan_ver85.shp を単純にプロットするアプリ
|
| 3 |
-
# 使い方:
|
| 4 |
-
# - 「Shapefile (ZIP)」に .shp/.shx/.dbf/.prj を ZIP にまとめたファイルをアップロード
|
| 5 |
-
# - そのまま「描画」ボタンを押すと境界線のみを静的プロット表示
|
| 6 |
-
|
| 7 |
import os
|
| 8 |
import io
|
| 9 |
import geopandas as gpd
|
| 10 |
import matplotlib.pyplot as plt
|
| 11 |
import gradio as gr
|
|
|
|
| 12 |
|
| 13 |
-
DEFAULT_ZIP = "data/japan_ver85.zip"
|
| 14 |
|
| 15 |
def load_gdf_from_zip(zip_path: str) -> gpd.GeoDataFrame:
|
| 16 |
-
"""
|
| 17 |
-
Shapefile を ZIP から読み込む。
|
| 18 |
-
"""
|
| 19 |
-
# pyogrio が入っていれば engine="pyogrio" が高速
|
| 20 |
gdf = gpd.read_file(f"zip://{zip_path}") # , engine="pyogrio"
|
| 21 |
-
# 座標系が設定されていれば WGS84 へ(なくてもそのままプロット可)
|
| 22 |
try:
|
| 23 |
if gdf.crs:
|
| 24 |
gdf = gdf.to_crs("EPSG:4326")
|
|
@@ -28,20 +19,21 @@ def load_gdf_from_zip(zip_path: str) -> gpd.GeoDataFrame:
|
|
| 28 |
|
| 29 |
def plot_boundary(gdf: gpd.GeoDataFrame, linewidth: float = 0.6, figsize=(7,7)):
|
| 30 |
"""
|
| 31 |
-
GeoDataFrame の境界線のみを静的にプロットし、
|
| 32 |
"""
|
| 33 |
fig, ax = plt.subplots(figsize=figsize)
|
| 34 |
gdf.boundary.plot(ax=ax, linewidth=linewidth)
|
| 35 |
ax.set_axis_off()
|
| 36 |
plt.tight_layout()
|
|
|
|
| 37 |
buf = io.BytesIO()
|
| 38 |
fig.savefig(buf, format="png", dpi=200)
|
| 39 |
plt.close(fig)
|
| 40 |
buf.seek(0)
|
| 41 |
-
|
|
|
|
| 42 |
|
| 43 |
def run(zip_file, line_width, width_px):
|
| 44 |
-
# 1) 読み込み元の決定
|
| 45 |
if zip_file is not None and hasattr(zip_file, "name") and os.path.exists(zip_file.name):
|
| 46 |
zip_path = zip_file.name
|
| 47 |
elif os.path.exists(DEFAULT_ZIP):
|
|
@@ -49,34 +41,27 @@ def run(zip_file, line_width, width_px):
|
|
| 49 |
else:
|
| 50 |
return None, "Shapefile の ZIP をアップロードするか、data/japan_ver85.zip を配置してください。"
|
| 51 |
|
| 52 |
-
# 2) 読み込み
|
| 53 |
try:
|
| 54 |
gdf = load_gdf_from_zip(zip_path)
|
| 55 |
except Exception as e:
|
| 56 |
return None, f"読み込みに失敗しました: {e}"
|
| 57 |
|
| 58 |
-
# 3) プロット
|
| 59 |
try:
|
|
|
|
| 60 |
img = plot_boundary(gdf, linewidth=line_width)
|
| 61 |
except Exception as e:
|
| 62 |
return None, f"描画に失敗しました: {e}"
|
| 63 |
|
| 64 |
-
# 4) 出力(画像 + ちょっとした情報)
|
| 65 |
info = []
|
| 66 |
info.append(f"レコード数: {len(gdf)}")
|
| 67 |
if gdf.crs:
|
| 68 |
info.append(f"CRS: {gdf.crs}")
|
| 69 |
-
# 主な列名(多すぎると邪魔なので先頭10件)
|
| 70 |
cols = list(map(str, gdf.columns))
|
| 71 |
info.append("列名(先頭10): " + ", ".join(cols[:10]))
|
| 72 |
return img, "\n".join(info)
|
| 73 |
|
| 74 |
with gr.Blocks(title="Japan Shapefile Plotter") as demo:
|
| 75 |
gr.Markdown("## japan_ver85.shp(ZIP)を単純にプロット")
|
| 76 |
-
gr.Markdown(
|
| 77 |
-
"- **Shapefile を ZIP**(`.shp/.shx/.dbf/.prj` 等を1つに)でアップロードしてください。\n"
|
| 78 |
-
"- 何もアップロードしない場合は `data/japan_ver85.zip` を読み込みます(置いてある場合)。"
|
| 79 |
-
)
|
| 80 |
|
| 81 |
with gr.Row():
|
| 82 |
zip_in = gr.File(label="Shapefile (ZIP)", file_count="single", file_types=[".zip"])
|
|
@@ -85,11 +70,10 @@ with gr.Blocks(title="Japan Shapefile Plotter") as demo:
|
|
| 85 |
width_px = gr.Slider(400, 1600, value=900, step=50, label="画像幅(px)(注: PNGは実質dpi依存)")
|
| 86 |
|
| 87 |
run_btn = gr.Button("描画")
|
| 88 |
-
out_img = gr.Image(label="静的プロット(境界線)", type="pil")
|
| 89 |
out_txt = gr.Textbox(label="メタ情報", lines=4)
|
| 90 |
|
| 91 |
run_btn.click(fn=run, inputs=[zip_in, line_width, width_px], outputs=[out_img, out_txt])
|
| 92 |
|
| 93 |
if __name__ == "__main__":
|
| 94 |
-
# Spaces では基本これでOK
|
| 95 |
demo.launch()
|
|
|
|
| 1 |
# app.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import os
|
| 3 |
import io
|
| 4 |
import geopandas as gpd
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
import gradio as gr
|
| 7 |
+
from PIL import Image # ★ 追加
|
| 8 |
|
| 9 |
+
DEFAULT_ZIP = "data/japan_ver85.zip"
|
| 10 |
|
| 11 |
def load_gdf_from_zip(zip_path: str) -> gpd.GeoDataFrame:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
gdf = gpd.read_file(f"zip://{zip_path}") # , engine="pyogrio"
|
|
|
|
| 13 |
try:
|
| 14 |
if gdf.crs:
|
| 15 |
gdf = gdf.to_crs("EPSG:4326")
|
|
|
|
| 19 |
|
| 20 |
def plot_boundary(gdf: gpd.GeoDataFrame, linewidth: float = 0.6, figsize=(7,7)):
|
| 21 |
"""
|
| 22 |
+
GeoDataFrame の境界線のみを静的にプロットし、PIL.Image を返す
|
| 23 |
"""
|
| 24 |
fig, ax = plt.subplots(figsize=figsize)
|
| 25 |
gdf.boundary.plot(ax=ax, linewidth=linewidth)
|
| 26 |
ax.set_axis_off()
|
| 27 |
plt.tight_layout()
|
| 28 |
+
|
| 29 |
buf = io.BytesIO()
|
| 30 |
fig.savefig(buf, format="png", dpi=200)
|
| 31 |
plt.close(fig)
|
| 32 |
buf.seek(0)
|
| 33 |
+
img = Image.open(buf) # ★ BytesIO → PIL.Image に変換
|
| 34 |
+
return img
|
| 35 |
|
| 36 |
def run(zip_file, line_width, width_px):
|
|
|
|
| 37 |
if zip_file is not None and hasattr(zip_file, "name") and os.path.exists(zip_file.name):
|
| 38 |
zip_path = zip_file.name
|
| 39 |
elif os.path.exists(DEFAULT_ZIP):
|
|
|
|
| 41 |
else:
|
| 42 |
return None, "Shapefile の ZIP をアップロードするか、data/japan_ver85.zip を配置してください。"
|
| 43 |
|
|
|
|
| 44 |
try:
|
| 45 |
gdf = load_gdf_from_zip(zip_path)
|
| 46 |
except Exception as e:
|
| 47 |
return None, f"読み込みに失敗しました: {e}"
|
| 48 |
|
|
|
|
| 49 |
try:
|
| 50 |
+
# width_px は PNG の実寸に直接効かないので、必要なら figsize/dpi を調整してください
|
| 51 |
img = plot_boundary(gdf, linewidth=line_width)
|
| 52 |
except Exception as e:
|
| 53 |
return None, f"描画に失敗しました: {e}"
|
| 54 |
|
|
|
|
| 55 |
info = []
|
| 56 |
info.append(f"レコード数: {len(gdf)}")
|
| 57 |
if gdf.crs:
|
| 58 |
info.append(f"CRS: {gdf.crs}")
|
|
|
|
| 59 |
cols = list(map(str, gdf.columns))
|
| 60 |
info.append("列名(先頭10): " + ", ".join(cols[:10]))
|
| 61 |
return img, "\n".join(info)
|
| 62 |
|
| 63 |
with gr.Blocks(title="Japan Shapefile Plotter") as demo:
|
| 64 |
gr.Markdown("## japan_ver85.shp(ZIP)を単純にプロット")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
with gr.Row():
|
| 67 |
zip_in = gr.File(label="Shapefile (ZIP)", file_count="single", file_types=[".zip"])
|
|
|
|
| 70 |
width_px = gr.Slider(400, 1600, value=900, step=50, label="画像幅(px)(注: PNGは実質dpi依存)")
|
| 71 |
|
| 72 |
run_btn = gr.Button("描画")
|
| 73 |
+
out_img = gr.Image(label="静的プロット(境界線)", type="pil") # ★ PIL を受け取る
|
| 74 |
out_txt = gr.Textbox(label="メタ情報", lines=4)
|
| 75 |
|
| 76 |
run_btn.click(fn=run, inputs=[zip_in, line_width, width_px], outputs=[out_img, out_txt])
|
| 77 |
|
| 78 |
if __name__ == "__main__":
|
|
|
|
| 79 |
demo.launch()
|