从0到1打造一个能上传任意GeoJSON的交互式Web地图
目录
- 项目背景与目标
- 关键库的导入
- 完整代码
- 效果图
本文将详细介绍如何使用Python中的
Streamlit
、
Geopandas
和
Folium
库,从零开始构建一个功能完善的Web应用。该应用允许用户上传自己的
GeoJSON
文件,并将其渲染为可交互的在线地图。
项目背景与目标
在数据可视化项目中,创建一个能接收用户输入、处理并展示数据的通用工具,远比为单个文件编写一次性脚本更有价值。本文的目标就是构建这样一个工具:一个通用的GeoJSON
文件查看器。
核心功能需求:
- 提供一个Web界面,允许用户上传
.geojson
格式的文件。 - 后台能自动加载数据,并处理常见的无效几何图形(invalid geometries)问题。
- 动态生成以数据为中心的交互式地图,并在界面上展示。
关键库的导入
Streamlit
: 用于快速构建Web应用的前端界面,包括文件上传、侧边栏和组件布局。Geopandas
: 作为地理空间数据处理的核心,负责读取文件、数据校验和修复。Folium
: 用于在Python中创建交互式的Leaflet.js地图。
完整代码
import streamlit as st
import geopandas as gpd
import pandas as pd
import folium
from folium import GeoJson, GeoJsonTooltip# --- 页面基础设置 ---
st.set_page_config(page_title="交互式GIS地图", layout="wide")
st.title("通用GeoJSON交互式地图查看器")
st.markdown("---")# --- 数据加载与预处理函数 ---
@st.cache_data
def load_data(file):"""加载并预处理上传的GeoJSON文件。"""gdf = gpd.read_file(file)# 1. 自动检查并转换日期时间列为字符串for col in gdf.columns:if pd.api.types.is_datetime64_any_dtype(gdf[col]):st.warning(f"警告:检测到日期时间列 '{col}',已自动转换为字符串。")gdf[col] = gdf[col].astype(str)# 2. 自动修复无效的几何图形gdf['geometry'] = gdf['geometry'].apply(lambda geom: geom.buffer(0) if not geom.is_valid else geom)return gdf# --- 主程序界面 ---# 侧边栏:文件上传组件
st.sidebar.header("上传数据文件")
uploaded_file = st.sidebar.file_uploader("选择一个GeoJSON文件", type=["geojson"])if uploaded_file is not None:# 文件上传成功后,执行主逻辑gdf = load_data(uploaded_file)# 排除几何列,获取可用的属性字段available_columns = [col for col in gdf.columns if col != 'geometry']# 侧边栏:地图显示设置st.sidebar.header("地图设置")selected_column = st.sidebar.selectbox("选择一个字段用于地图悬停提示:",options=available_columns,index=0)# --- Folium 地图渲染 ---# 自动计算数据中心点center_point = gdf.geometry.unary_union.centroidcenter_lat, center_lon = center_point.y, center_point.xm_display = folium.Map(location=[center_lat, center_lon], zoom_start=11)# 创建GeoJSON图层并设置Tooltipgeojson_layer = GeoJson(gdf,tooltip=GeoJsonTooltip(fields=[str(selected_column)],aliases=[f"{selected_column}:"],sticky=True))geojson_layer.add_to(m_display)# --- 核心技巧:解决Streamlit渲染兼容性问题 ---# 1. 将Folium地图对象保存为临时的HTML文件map_html_path = "temp_map.html"m_display.save(map_html_path)# 2. 读取HTML文件的内容with open(map_html_path, "r", encoding="utf-8") as f:map_html_content = f.read()# 3. 使用st.components.v1.html将HTML内容嵌入Streamlit应用st.subheader("地理空间数据可视化")st.components.v1.html(map_html_content, height=800)else:st.info("请在左侧侧边栏上传一个GeoJSON文件以开始。")
只需运行以下命令即可:
streamlit run app.py