Streamlit做地图应用?组件如何嵌入?
如果你正在做一个轻量级 GIS 数据展示或内部分析工具,常会遇到一个问题:Streamlit做地图应用?组件如何嵌入? Streamlit 上手很快,但地图应用往往不只是显示一个点,还涉及底图、矢量图层、交互选择、弹窗、绘制、空间查询结果展示等组件嵌入。本文以 GIS 读者最常见的场景为主线,讲清楚 Streamlit 做地图应用时该选哪种地图组件、如何嵌入 Folium / Leaflet / Pydeck 地图,以及常见坑怎么排查。
引言:Streamlit做地图应用适合哪些 GIS 场景
Streamlit 的优势是“用 Python 快速做可交互 Web 应用”。对于 GIS 学生、空间数据分析师和初级 GIS 工程师来说,它很适合做以下类型的地图应用:
- 展示 CSV、GeoJSON、Shapefile 转换后的点线面数据。
- 做内部用的空间数据质检看板。
- 展示 GeoPandas 分析结果,例如缓冲区、叠加分析、空间连接结果。
- 快速制作 PostGIS 查询结果的地图预览。
- 做一个简单的 WebGIS 原型,用于汇报或方案验证。
但需要注意,Streamlit 不是完整的 WebGIS 框架。它更适合“快速交互式数据应用”,而不是替代 OpenLayers、Leaflet、Cesium 这类前端地图框架做复杂生产系统。

背景:为什么 Streamlit 地图组件嵌入会让 GIS 用户困惑
很多 GIS 用户刚开始用 Streamlit 做地图应用时,通常会遇到三个困惑:
- 不知道用哪个地图组件:Streamlit 自带地图、Folium、Pydeck、Leaflet、Kepler.gl 都能显示地图,但适用场景不同。
- 不知道如何嵌入:有些地图对象不能直接用
st.write()显示,需要专门的 Streamlit 组件。 - 交互结果拿不回来:例如点击地图、框选要素、绘制范围后,想把坐标或属性传回 Python,却发现普通 HTML 嵌入无法直接回传状态。
因此,做 Streamlit 地图应用时,核心不是“能不能显示地图”,而是要判断:你需要的是静态展示、交互浏览,还是需要地图交互结果参与后续分析。
原理:Streamlit 地图应用的几种嵌入方式
Streamlit 做地图应用通常有四类嵌入方式。理解它们的差异,后面选型会简单很多。
1. 使用 Streamlit 原生地图组件
Streamlit 提供了 st.map() 和 st.pydeck_chart()。其中 st.map() 适合快速展示经纬度点数据,代码少,但可定制能力有限。st.pydeck_chart() 基于 Pydeck,适合做大量点、热力图、柱状图、弧线图等可视化。
2. 使用 streamlit-folium 嵌入 Folium 地图
Folium 是 Python GIS 用户非常熟悉的 Leaflet 封装库。它适合加载 GeoJSON、点线面图层、弹窗、图层控制器、简单专题图。要在 Streamlit 中嵌入 Folium,一般使用 streamlit-folium 组件。
3. 使用 HTML 方式嵌入地图
对于一些已生成的 HTML 地图,例如 Folium 导出的 HTML、Kepler.gl 导出的 HTML,可以通过 Streamlit 的 HTML 组件嵌入。但这种方式更偏“展示”,交互状态通常不容易回传给 Python。
4. 使用自定义 Streamlit Component
如果你要把复杂 Leaflet、Mapbox GL、OpenLayers 或 Cesium 组件嵌入 Streamlit,并且需要前后端交互,就需要开发 Streamlit 自定义组件。这种方式灵活,但开发成本最高。
步骤:Streamlit嵌入Folium地图的实用做法
下面用一个最常见的 GIS 场景演示:读取点位数据,在 Streamlit 页面中嵌入 Folium 地图,并显示点位弹窗。
步骤 1:安装依赖
pip install streamlit folium streamlit-folium pandas geopandas
如果只是显示经纬度 CSV 点数据,geopandas 不是必需的;如果你要读取 Shapefile、GeoPackage、GeoJSON,建议安装。
步骤 2:准备一个点位数据
假设有一个 points.csv,字段如下:
name,lon,lat,type
点位A,116.391,39.907,监测点
点位B,116.405,39.915,采样点
点位C,116.382,39.899,巡查点
注意:Folium 和 Leaflet 默认使用 WGS84 经纬度,也就是 EPSG:4326。字段顺序常见写法是经度 lon、纬度 lat,但 Folium 的位置参数通常是 [lat, lon]。
步骤 3:编写 Streamlit 地图应用
import streamlit as st
import pandas as pd
import folium
from streamlit_folium import st_folium
st.set_page_config(page_title="Streamlit 地图应用", layout="wide")
st.title("Streamlit 地图应用示例")
df = pd.read_csv("points.csv")
st.sidebar.header("筛选条件")
selected_type = st.sidebar.multiselect(
"选择点位类型",
options=df["type"].unique(),
default=list(df["type"].unique())
)
filtered = df[df["type"].isin(selected_type)]
center_lat = filtered["lat"].mean()
center_lon = filtered["lon"].mean()
m = folium.Map(
location=[center_lat, center_lon],
zoom_start=13,
tiles="OpenStreetMap"
)
for _, row in filtered.iterrows():
folium.Marker(
location=[row["lat"], row["lon"]],
popup=f"{row['name']} - {row['type']}",
tooltip=row["name"]
).add_to(m)
map_data = st_folium(
m,
width=1000,
height=600
)
st.write("当前筛选点位数量:", len(filtered))
st.write("地图交互返回信息:")
st.write(map_data)
运行应用:
streamlit run app.py
这就是一个最小可用的 Streamlit 地图应用。它包含侧边栏筛选、地图嵌入、点位弹窗和地图交互信息返回。
步骤 4:读取 GeoJSON 并显示面图层
如果你的数据是 GeoJSON,可以用 GeoPandas 读取,然后转成 Folium 可识别的 GeoJSON 图层。
import streamlit as st
import geopandas as gpd
import folium
from streamlit_folium import st_folium
gdf = gpd.read_file("districts.geojson")
if gdf.crs is not None and gdf.crs.to_epsg() != 4326:
gdf = gdf.to_crs(epsg=4326)
center = gdf.geometry.centroid
center_lat = center.y.mean()
center_lon = center.x.mean()
m = folium.Map(location=[center_lat, center_lon], zoom_start=10)
folium.GeoJson(
gdf.to_json(),
name="行政区",
tooltip=folium.GeoJsonTooltip(fields=["name"])
).add_to(m)
folium.LayerControl().add_to(m)
st_folium(m, width=1000, height=650)
这里最重要的一步是坐标系转换。Web 地图展示通常要求经纬度数据。如果你的 Shapefile 是投影坐标,例如 CGCS2000 高斯投影、UTM 或地方坐标,直接显示可能会偏移或完全看不到。
步骤:使用 st.pydeck_chart 做高性能点数据地图
如果你要显示几万甚至更多点位,Folium 可能会变慢。此时可以考虑 Pydeck。它更适合大量点数据可视化,例如散点、热力、聚合、三维柱状图。
import streamlit as st
import pandas as pd
import pydeck as pdk
df = pd.read_csv("points.csv")
layer = pdk.Layer(
"ScatterplotLayer",
data=df,
get_position="[lon, lat]",
get_radius=80,
get_fill_color=[255, 80, 80, 160],
pickable=True
)
view_state = pdk.ViewState(
latitude=df["lat"].mean(),
longitude=df["lon"].mean(),
zoom=12,
pitch=0
)
deck = pdk.Deck(
layers=[layer],
initial_view_state=view_state,
tooltip={"text": "{name}n{type}"}
)
st.pydeck_chart(deck)
对于 Streamlit 做地图应用来说,Pydeck 的优势是渲染性能和可视化效果,缺点是传统 GIS 图层控制、编辑绘制、复杂弹窗等能力不如 Leaflet 生态直观。
常见坑:Streamlit地图组件嵌入失败如何排查
1. 地图空白或点位不显示
- 检查经纬度是否写反。Folium 的
location是[lat, lon],而 GeoJSON 坐标通常是[lon, lat]。 - 检查数据是否为 EPSG:4326。不是经纬度坐标时,需要先用 GeoPandas 的
to_crs(epsg=4326)转换。 - 检查是否存在空几何、空经纬度、异常坐标,例如经度大于 180 或纬度大于 90。
2. Streamlit嵌入Folium地图后不能交互
如果只是用 HTML 方式嵌入 Folium,地图可以缩放和平移,但很多交互结果不会返回给 Streamlit。建议使用 streamlit-folium 的 st_folium(),它可以返回部分点击、缩放、边界等状态信息。
3. GeoJSON 文件太大导致页面卡顿
- 先在 QGIS 或 GeoPandas 中简化几何,减少节点数量。
- 只加载当前业务需要的字段,删除无关属性。
- 大规模矢量切片场景不建议直接用 Streamlit + Folium 承载。
- 如果是大量点数据,优先考虑 Pydeck 或后端聚合。
4. 底图无法加载
底图无法加载通常不是 Streamlit 代码问题,而是瓦片服务访问问题。常见原因包括网络限制、瓦片服务被屏蔽、服务地址失效、需要 Token、浏览器混合内容限制等。正式部署时应使用稳定、合规、可访问的底图服务。
5. 部署后本地文件路径失效
Streamlit 部署到服务器后,读取 C:dataxxx.shp 这类本地路径通常会失败。建议将数据放在项目相对路径中,或改用数据库、对象存储、HTTP 地址等方式管理数据。
方法比较:Streamlit地图组件应该怎么选
| 方案 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
st.map() |
快速显示经纬度点 | 代码最少,上手最快 | 样式和交互能力有限 |
st.pydeck_chart() |
大量点数据、热力图、三维可视化 | 渲染效果好,适合数据可视化 | 传统 GIS 图层管理能力较弱 |
streamlit-folium |
Leaflet/Folium 地图、GeoJSON、弹窗、图层控制 | Python GIS 用户友好,生态丰富 | 大数据量时容易卡顿 |
| HTML 嵌入 | 展示已生成的地图页面 | 简单,适合嵌入现成 HTML | 交互状态不易回传 Python |
| 自定义 Streamlit Component | 复杂 Leaflet、OpenLayers、Cesium 组件 | 灵活度最高 | 需要前端开发能力 |
简单判断:如果你只是做点位展示,用 st.map();如果要做 Folium 地图和 GeoJSON 图层,用 streamlit-folium;如果要做大量点数据可视化,用 st.pydeck_chart();如果要做复杂 WebGIS,建议认真评估是否直接使用 Leaflet、OpenLayers 或 Cesium 开发前端。
检查清单:发布前确认 Streamlit 地图应用是否可靠
- 数据坐标系是否已经转换为 EPSG:4326。
- 经纬度字段是否没有写反。
- 是否处理了空值、无效几何和异常坐标。
- GeoJSON 或 Shapefile 是否过大,是否需要简化或抽稀。
- 底图服务是否稳定、合法、可在部署环境访问。
- 地图交互结果是否真的需要回传 Python,如果需要,是否选择了支持交互返回的组件。
- 文件路径是否使用相对路径或可部署的数据源。
- 是否通过侧边栏筛选减少一次性加载的数据量。
- 是否在部署环境测试过依赖安装和数据读取。
FAQ:Streamlit做地图应用常见问题
Streamlit 可以做真正的 WebGIS 系统吗?
可以做轻量级 WebGIS 原型、内部工具和分析看板,但不建议把它当作完整 WebGIS 前端框架。复杂图层管理、空间编辑、瓦片服务、权限系统、前端路由和大规模并发场景,通常更适合用 OpenLayers、Leaflet、Mapbox GL 或 Cesium 搭配后端服务实现。
Streamlit嵌入Folium地图推荐用什么库?
推荐使用 streamlit-folium。它比简单 HTML 嵌入更适合 Streamlit 应用,可以把 Folium 地图放入页面,并返回部分地图交互状态。
为什么 Folium 地图中的点位偏移很远?
最常见原因是坐标系不对或经纬度顺序写反。Web 地图通常需要 WGS84 经纬度数据。对于 Shapefile、GeoPackage 等数据,建议先用 QGIS 查看图层 CRS,再用 GeoPandas 转换到 EPSG:4326。
Streamlit 地图应用可以读取 Shapefile 吗?
可以。通常使用 GeoPandas 的 read_file() 读取 Shapefile。需要注意 Shapefile 由多个文件组成,至少包括 .shp、.shx、.dbf,坐标系文件 .prj 也很重要。部署时不要只上传一个 .shp 文件。
大量 GeoJSON 在 Streamlit 中加载很慢怎么办?
先简化几何、减少字段、按范围或条件筛选数据。如果数据量仍然很大,不建议直接把完整 GeoJSON 塞进前端。可以考虑 PostGIS 后端查询、矢量切片、数据聚合,或改用更适合大规模可视化的方案。
Streamlit 地图点击后能获取坐标吗?
使用合适的组件可以获取部分交互结果。例如 streamlit-folium 的返回值中可以包含地图点击位置、边界范围、缩放级别等信息。具体支持哪些交互,需要看你使用的组件接口。
结论:先明确交互需求,再选择嵌入方式
Streamlit做地图应用的关键,不是把地图“显示出来”这么简单,而是选对组件嵌入方式。简单点位展示用 st.map(),大量点数据可视化用 st.pydeck_chart(),常规 GIS 图层展示和 Folium 生态用 streamlit-folium。如果你需要复杂地图编辑、矢量切片、三维场景或完整 WebGIS 交互,就要考虑专门的前端地图框架。
对于 GIS 学习和项目原型来说,Streamlit 是非常实用的工具。只要处理好坐标系、数据量、底图访问和交互返回这几个问题,就能快速搭建一个可用、可演示、可扩展的地图应用。