Streamlit开发WebGIS?地图组件怎么嵌?
很多做 GIS 原型系统的同学都会遇到一个问题:Streamlit开发WebGIS?地图组件怎么嵌? 如果只是展示一个点图,几行代码就能跑起来;但一旦涉及 GeoJSON、底图、点击交互、图层控制和部署,选择哪个地图组件、数据怎么传、性能怎么控制,就会直接影响项目是否可用。
本文以 Streamlit 开发轻量级 WebGIS 为场景,重点讲清楚 Streamlit 嵌入地图组件的几种常用方式:st.map、pydeck、streamlit-folium 和自定义 HTML 组件。你可以根据数据量、交互需求和部署环境,快速选出合适方案。
引言:Streamlit开发WebGIS时为什么地图组件是关键
Streamlit 的优势是开发快,特别适合做 GIS 数据看板、空间分析演示、内部工具和算法原型。但 Streamlit 本身不是传统意义上的 WebGIS 框架,它更像是一个 Python 数据应用框架。
所以在 Streamlit 开发 WebGIS 时,地图能力通常来自外部组件。例如:
- 只看经纬度点位:使用 st.map。
- 需要大规模点、线、面可视化:使用 pydeck。
- 想用 Leaflet 生态和常见 GIS 图层:使用 streamlit-folium。
- 需要接入已有 OpenLayers、Cesium 或复杂前端地图:使用 Streamlit 自定义 HTML 组件。
如果选错组件,常见结果是:地图能显示但不能交互,GeoJSON 加载慢,坐标系不对,部署后底图空白,或者 Streamlit 每次刷新导致地图状态丢失。

背景:Streamlit嵌入地图组件的典型需求
在 GIS 项目中,Streamlit 嵌入地图组件通常不是为了做一个完整的互联网地图平台,而是解决以下几类实际问题:
- 展示采样点、门店、设备、事件等经纬度点位。
- 叠加行政区、网格、缓冲区、分析结果等 GeoJSON 图层。
- 在地图上点击要素,并把属性返回给 Streamlit 表格或图表。
- 快速验证空间分析结果,例如选址、覆盖范围、轨迹可视化。
- 把 Python 处理后的 GeoPandas 数据直接展示成 WebGIS 地图。
这些需求看起来都叫“嵌地图”,但技术复杂度差异很大。一个只读点图和一个支持点击交互的多图层 WebGIS,选型完全不同。
原理:Streamlit地图组件到底是怎么嵌进去的
理解 Streamlit 地图组件嵌入方式,先要分清两层:
- Python 后端层:负责读取 Shapefile、GeoJSON、PostGIS 查询结果,进行 GeoPandas 或 Pandas 处理。
- 前端地图层:负责在浏览器中渲染地图,例如 Leaflet、deck.gl、Mapbox GL 或 OpenLayers。
Streamlit 的地图组件本质上是在这两层之间做桥接。Python 端把数据转换成组件可识别的格式,前端组件在浏览器里完成地图渲染。
常见组件的原理可以简单理解为:
- st.map:Streamlit 内置地图接口,适合快速显示经纬度点。
- pydeck:基于 deck.gl,适合点云、轨迹、热力图、面图层等可视化。
- streamlit-folium:把 Folium 生成的 Leaflet 地图嵌入 Streamlit,适合传统 WebGIS 图层展示。
- components.html:直接把 HTML、JavaScript 地图页面嵌入 Streamlit,灵活度最高,但维护成本也最高。
GIS 数据还要注意一个核心前提:大多数 Web 地图组件默认使用经纬度坐标,也就是 WGS84 坐标系,EPSG:4326。很多国内项目数据可能是 CGCS2000、地方投影坐标或 Web Mercator,如果不转换,地图会出现偏移、变形或完全看不到。
步骤:用st.map快速嵌入最简单的点位地图
如果你的需求只是把点位展示在地图上,st.map 是最省事的方案。它适合教学演示、数据预览和非常轻量的点位可视化。
1. 准备经纬度字段
st.map 默认识别 lat 和 lon 字段,也可以识别 latitude 和 longitude。示例代码如下:
import streamlit as st
import pandas as pd
st.set_page_config(page_title="Streamlit WebGIS 点位示例", layout="wide")
data = pd.DataFrame({
"name": ["点位A", "点位B", "点位C"],
"lat": [31.2304, 31.2201, 31.2406],
"lon": [121.4737, 121.5002, 121.4558]
})
st.title("Streamlit 点位地图")
st.dataframe(data)
st.map(data, latitude="lat", longitude="lon", zoom=11)
2. 适合使用st.map的场景
- 只需要展示点位,不需要复杂图层控制。
- 数据量不大,主要用于快速预览。
- 不需要点击要素返回属性。
- 不需要叠加 GeoJSON 面图层或矢量瓦片。
如果你想做 Streamlit 开发 WebGIS 的正式原型,st.map 只能作为入门方案。它的优势是简单,限制也很明显。
步骤:用streamlit-folium嵌入Leaflet地图
如果你希望在 Streamlit 中使用更接近传统 WebGIS 的地图能力,streamlit-folium 是非常实用的选择。它可以使用 Folium 创建 Leaflet 地图,并在 Streamlit 页面中显示。
1. 安装依赖
pip install streamlit folium streamlit-folium geopandas
如果你需要读取 Shapefile,还要确保本机 GeoPandas 环境可以正常读取矢量数据。建议使用 Conda 环境安装 GIS 依赖,避免 GDAL、Fiona、pyproj 版本冲突。
2. 嵌入一个基础 Leaflet 地图
import streamlit as st
import folium
from streamlit_folium import st_folium
st.set_page_config(page_title="Streamlit Folium WebGIS", layout="wide")
st.title("Streamlit 嵌入 Folium 地图")
m = folium.Map(
location=[31.2304, 121.4737],
zoom_start=11,
tiles="OpenStreetMap"
)
folium.Marker(
location=[31.2304, 121.4737],
popup="上海中心点",
tooltip="点击查看属性"
).add_to(m)
st_folium(m, width=1000, height=600)
这段代码会在 Streamlit 页面中嵌入一个 Leaflet 地图,并显示一个可点击 Marker。对于 GIS 初学者来说,这是最容易理解的 WebGIS 嵌图方式。
3. 加载GeoJSON面图层
实际 GIS 项目中,常见需求是把行政区、网格、缓冲区或分析结果作为 GeoJSON 图层叠加到地图上。
import streamlit as st
import geopandas as gpd
import folium
from streamlit_folium import st_folium
st.set_page_config(page_title="Streamlit GeoJSON 图层", layout="wide")
geojson_path = "data/district.geojson"
gdf = gpd.read_file(geojson_path)
if gdf.crs is not None and gdf.crs.to_epsg() != 4326:
gdf = gdf.to_crs(epsg=4326)
center = gdf.geometry.centroid.iloc[0]
m = folium.Map(location=[center.y, center.x], zoom_start=10, tiles="OpenStreetMap")
folium.GeoJson(
gdf,
name="行政区图层",
tooltip=folium.GeoJsonTooltip(fields=["name"], aliases=["名称"])
).add_to(m)
folium.LayerControl().add_to(m)
st_folium(m, width=1000, height=650)
这里有一个关键点:在加载 GeoJSON 之前,先检查坐标系。如果原始数据不是 EPSG:4326,就用 to_crs(epsg=4326) 转换。很多 Streamlit 地图不显示的问题,本质上都是坐标系错误。
4. 获取地图点击结果
streamlit-folium 可以把部分地图交互结果返回给 Streamlit。比如用户点击地图后,可以获取点击点坐标:
import streamlit as st
import folium
from streamlit_folium import st_folium
m = folium.Map(location=[31.2304, 121.4737], zoom_start=11)
map_data = st_folium(m, width=1000, height=600)
st.write("地图交互返回结果:")
st.write(map_data)
if map_data and map_data.get("last_clicked"):
lat = map_data["last_clicked"]["lat"]
lng = map_data["last_clicked"]["lng"]
st.success(f"你点击的位置:纬度 {lat}, 经度 {lng}")
这类交互适合做点选查询、人工标注、坐标拾取等轻量 WebGIS 功能。但如果你要做复杂编辑、拓扑检查或大量要素选择,建议使用专业前端 WebGIS 框架。
步骤:用pydeck嵌入高性能空间可视化地图
当数据量较大,或者你需要热力图、轨迹、柱状图、点云效果时,可以考虑 pydeck。它基于 deck.gl,更适合数据可视化型 WebGIS。
1. 安装依赖
pip install streamlit pydeck pandas
2. 显示点图层
import streamlit as st
import pandas as pd
import pydeck as pdk
st.set_page_config(page_title="Streamlit Pydeck 地图", layout="wide")
df = pd.DataFrame({
"name": ["点位A", "点位B", "点位C"],
"lat": [31.2304, 31.2201, 31.2406],
"lon": [121.4737, 121.5002, 121.4558],
"value": [10, 30, 20]
})
layer = pdk.Layer(
"ScatterplotLayer",
data=df,
get_position="[lon, lat]",
get_radius=300,
get_fill_color="[255, 80, 80, 180]",
pickable=True
)
view_state = pdk.ViewState(
latitude=31.2304,
longitude=121.4737,
zoom=10,
pitch=0
)
deck = pdk.Deck(
layers=[layer],
initial_view_state=view_state,
tooltip={"text": "{name}n数值:{value}"}
)
st.pydeck_chart(deck)
pydeck 的优势是图层表达能力强,适合 GIS 数据看板。缺点是它更偏空间可视化,不像 Leaflet 那样直接适配大量传统 GIS 插件。
步骤:用components.html嵌入自定义WebGIS页面
如果你已经有 OpenLayers、Leaflet、Mapbox GL JS 或 Cesium 写好的前端地图页面,也可以用 Streamlit 的 HTML 组件直接嵌入。
import streamlit as st
import streamlit.components.v1 as components
html = """
<div id="map" style="width:100%;height:600px;background:#eef;">
这里可以放置自定义 WebGIS 地图容器
</div>
<script>
console.log("在这里初始化 Leaflet、OpenLayers 或 Cesium 地图");
</script>
"""
components.html(html, height=650)
这种方式灵活度最高,适合接入已有 WebGIS 前端代码。但要注意,Streamlit 与 JavaScript 之间的数据交互并不像完整前后端项目那样自由。如果需要复杂状态同步,需要额外封装 Streamlit Component。
常见坑:Streamlit地图组件怎么嵌都不对时先查这些
1. 坐标系不是EPSG:4326
这是最常见问题。Web 地图组件通常使用经纬度坐标,很多 GIS 数据是投影坐标。比如米制坐标直接传给地图,地图当然找不到正确位置。
import geopandas as gpd
gdf = gpd.read_file("data/input.shp")
print(gdf.crs)
gdf_4326 = gdf.to_crs(epsg=4326)
gdf_4326.to_file("data/output.geojson", driver="GeoJSON")
2. 经纬度字段写反
很多组件位置字段要求是 [lon, lat],也就是先经度后纬度。但表格里经常写成 lat, lon。如果地图点位跑到海里或国外,优先检查这个问题。
3. GeoJSON文件太大导致页面卡顿
Streamlit 每次脚本重新运行时,地图组件也可能重新渲染。如果 GeoJSON 文件很大,页面会明显变慢。建议:
- 先用 QGIS 或 GeoPandas 简化几何。
- 只加载当前分析需要的字段。
- 大数据量场景考虑矢量瓦片或 PostGIS 后端查询。
- 在 Streamlit 中使用缓存减少重复读取。
import streamlit as st
import geopandas as gpd
@st.cache_data
def load_data(path):
gdf = gpd.read_file(path)
return gdf.to_crs(epsg=4326)
gdf = load_data("data/district.geojson")
4. 部署后底图不显示
本地能显示,部署后底图不显示,通常和网络访问、瓦片服务、HTTPS、跨域或 Token 配置有关。尤其是使用第三方底图服务时,要确认部署环境能访问该服务。
5. Streamlit刷新导致地图状态丢失
Streamlit 的运行机制是交互触发脚本从上到下重新执行。如果没有使用 st.session_state 或组件返回值保存状态,地图选择、点击结果和筛选条件可能会丢失。
方法比较:st.map、pydeck、streamlit-folium和自定义组件怎么选
| 方案 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| st.map | 快速点位预览 | 内置、代码少、上手快 | 图层和交互能力有限 |
| pydeck | 空间数据可视化、热力图、轨迹、较大点数据 | 视觉表达强,适合数据看板 | 传统 GIS 图层管理能力较弱 |
| streamlit-folium | Leaflet 地图、GeoJSON 图层、Marker、图层控制 | GIS 友好,生态成熟,易于教学和原型 | 大数据量 GeoJSON 性能有限 |
| components.html | 嵌入已有 OpenLayers、Cesium 或复杂前端地图 | 灵活度最高 | 需要前端能力,交互同步成本高 |
如果你是 GIS 学生或刚入门的 GIS 工程师,建议从 streamlit-folium 开始。它既能体现 WebGIS 的图层思想,又不会像完整前端开发那样复杂。
检查清单:Streamlit开发WebGIS地图组件嵌入前后要确认什么
- 数据是否有明确坐标系,是否已转换为 EPSG:4326。
- 点数据字段是否明确区分经度 lon 和纬度 lat。
- GeoJSON 是否过大,是否需要简化几何或裁剪范围。
- 是否需要点击、框选、弹窗、图层控制等交互。
- 是否需要接入 PostGIS、Shapefile、GeoPackage 或在线接口。
- 底图服务在部署环境中是否可以访问。
- 是否使用
st.cache_data缓存空间数据读取结果。 - 是否需要用
st.session_state保存地图交互状态。 - 项目是内部原型,还是面向公众访问的正式 WebGIS。
FAQ:Streamlit开发WebGIS常见问题
Q1:Streamlit适合开发正式WebGIS系统吗?
Streamlit 更适合 GIS 原型、内部工具、分析看板和教学演示。如果是高并发、复杂权限、海量图层、地图编辑和长期运维的正式 WebGIS,建议使用前后端分离架构,例如 FastAPI、PostGIS、OpenLayers 或 Cesium。
Q2:Streamlit地图组件怎么嵌GeoJSON最方便?
最方便的是使用 streamlit-folium。先用 GeoPandas 读取 GeoJSON,再确认坐标系为 EPSG:4326,最后通过 Folium 的 GeoJson 图层添加到地图中。
Q3:streamlit-folium和pydeck哪个更适合GIS?
如果你的重点是传统 GIS 图层、Marker、弹窗和图层控制,streamlit-folium 更合适。如果重点是数据可视化、大量点位、热力图和三维柱状表达,pydeck 更合适。
Q4:为什么Streamlit地图在本地能显示,部署后不显示?
常见原因包括底图服务无法访问、网络被限制、Token 没配置、HTTPS 混合内容问题、GeoJSON 路径错误。建议先检查浏览器控制台,再确认部署服务器是否能访问瓦片服务。
Q5:Streamlit能不能嵌入OpenLayers或Cesium?
可以通过 components.html 嵌入简单页面,也可以开发自定义 Streamlit Component。但如果项目核心是 OpenLayers 或 Cesium 复杂交互,建议把 Streamlit 作为分析后台或管理界面,而不是承担全部前端 WebGIS 功能。
结论:先按需求选组件,再处理坐标系和性能
回到标题中的问题:Streamlit开发WebGIS?地图组件怎么嵌? 最实用的答案不是只选一个组件,而是按需求分层选择。
只做点位预览,用 st.map;做 GIS 教学、GeoJSON 图层和常规交互,用 streamlit-folium;做空间数据可视化和较大规模点图层,用 pydeck;要嵌入已有 OpenLayers、Cesium 或复杂前端地图,用 components.html 或自定义组件。
无论选择哪种方案,都要优先检查三个问题:坐标系是否正确、数据量是否适合前端直接加载、部署环境是否能访问底图服务。把这三点处理好,Streamlit 开发轻量级 WebGIS 就会稳定很多。