Streamlit入门怎么读?GIS数据可视化项目实战教程(附:交互地图代码)
如果你正在搜索“Streamlit入门怎么读?GIS数据可视化项目实战教程(附:交互地图代码)”,大概率不是想看一篇抽象介绍,而是想知道:Streamlit到底适不适合GIS项目?能不能快速做一个带交互地图、属性筛选、图表统计的数据可视化页面?这篇文章就用一个最小可运行的GIS案例,把 Streamlit 入门、GeoPandas 读取空间数据、PyDeck 交互地图展示和属性筛选串起来。

引言:Streamlit入门先不要从概念开始
很多GIS同学第一次接触 Streamlit,会先纠结“Streamlit入门怎么读”“是不是要先学前端”“能不能做WebGIS”。我的建议是:先用一个真实数据可视化页面跑通,再回头理解组件和状态。
Streamlit 是一个用 Python 快速构建数据应用的框架。它不要求你写 HTML、CSS 和 JavaScript,比较适合 GIS 数据分析人员、Python GIS 初学者、空间数据工程师做内部工具、数据质检页面、专题图展示原型和项目汇报看板。
本文目标很具体:做一个可以读取 GeoJSON 点数据、按属性筛选、在交互地图上显示点位,并输出简单统计结果的 GIS 数据可视化小项目。
背景:为什么GIS项目适合用Streamlit做快速可视化
在GIS工作中,经常会遇到这类需求:
- 拿到一份点位、线或面数据,想快速查看空间分布。
- 需要按区县、类型、等级、时间字段筛选数据。
- 想把筛选结果做成一个可交互页面,方便同事或甲方查看。
- 不想为一个临时分析工具搭完整的前后端项目。
传统做法可能是用 QGIS 或 ArcGIS Pro 打开数据、设置样式、截图导出。如果需要交互式网页,就要使用 Leaflet、OpenLayers 或 Cesium,再处理前端工程、数据接口和部署问题。
Streamlit 的优势在于:只用 Python 脚本就能快速生成一个数据应用。对于很多“轻量级GIS数据可视化项目”,它可以显著降低原型开发成本。
但也要注意,Streamlit 不是完整替代 WebGIS 框架的工具。它更适合数据分析、内部看板、快速验证和小型项目展示;如果要做复杂地图编辑、多图层权限管理、海量瓦片服务和高并发WebGIS系统,仍然应考虑专业的前端GIS技术栈。
原理:Streamlit交互地图代码背后的基本逻辑
一个 Streamlit GIS 数据可视化页面通常由四部分组成:
- 数据读取:用 GeoPandas 读取 GeoJSON、Shapefile、GeoPackage 等空间数据。
- 数据清洗:检查坐标系、字段、空几何、经纬度范围等问题。
- 交互控件:用 Streamlit 的侧边栏、下拉框、多选框、滑块完成筛选。
- 地图渲染:用 PyDeck、Folium 或 streamlit-folium 显示交互地图。
这里使用 PyDeck,是因为它和 Streamlit 集成方便,适合点数据、热力图、分级符号和简单可视化。PyDeck 底层基于 deck.gl,适合做浏览器中的交互式地图图层。
GIS读者要特别关注一个核心问题:多数 Web 地图显示要求经纬度坐标,也就是 WGS84 坐标系,EPSG:4326。如果你的数据是 CGCS2000 高斯投影、Web Mercator、地方投影或米制坐标,直接拿来显示就可能出现点位偏移、地图空白或飞到国外的问题。
步骤:从零搭建一个Streamlit GIS数据可视化项目
1. 准备项目环境
建议新建一个独立 Python 环境。下面示例适合已经安装 Anaconda 或 Miniconda 的用户。
conda create -n streamlit-gis python=3.11 -y
conda activate streamlit-gis
pip install streamlit geopandas pydeck pandas shapely
如果你需要读取 Shapefile、GeoPackage 或其他格式,GeoPandas 会依赖 GDAL、Fiona、pyogrio 等库。Windows 用户如果安装失败,建议优先使用 conda-forge:
conda install -c conda-forge geopandas streamlit pydeck pandas shapely -y
2. 准备一份GeoJSON示例数据
为了让代码容易复现,本文假设你有一份点数据文件:
data/poi_sample.geojson
字段结构可以类似这样:
| 字段名 | 含义 | 示例 |
|---|---|---|
| name | 点位名称 | 人民公园 |
| district | 所属区县 | 武侯区 |
| type | 点位类型 | 公园 |
| score | 评分或等级 | 4.6 |
| geometry | 空间几何 | Point |
如果你手头是 Shapefile,也可以把读取路径改为:
gdf = gpd.read_file("data/poi_sample.shp")
3. 编写Streamlit应用主文件
在项目根目录新建文件:
app.py
写入下面这份完整的交互地图代码:
import streamlit as st
import geopandas as gpd
import pandas as pd
import pydeck as pdk
st.set_page_config(
page_title="Streamlit GIS数据可视化项目",
layout="wide"
)
st.title("Streamlit GIS数据可视化项目实战")
st.caption("GeoPandas读取空间数据,Streamlit构建交互界面,PyDeck渲染交互地图")
@st.cache_data
def load_data(path):
gdf = gpd.read_file(path)
if gdf.empty:
return gdf
if gdf.crs is None:
st.warning("数据缺少坐标系信息,当前示例假设它是 EPSG:4326。请在正式项目中先确认坐标系。")
gdf = gdf.set_crs(epsg=4326)
if gdf.crs.to_epsg() != 4326:
gdf = gdf.to_crs(epsg=4326)
gdf = gdf[gdf.geometry.notnull()].copy()
gdf = gdf[gdf.geometry.geom_type == "Point"].copy()
gdf["lon"] = gdf.geometry.x
gdf["lat"] = gdf.geometry.y
return gdf
data_path = "data/poi_sample.geojson"
gdf = load_data(data_path)
if gdf.empty:
st.error("没有读取到有效数据,请检查文件路径、字段和几何类型。")
st.stop()
st.sidebar.header("筛选条件")
district_options = sorted(gdf["district"].dropna().unique().tolist())
type_options = sorted(gdf["type"].dropna().unique().tolist())
selected_districts = st.sidebar.multiselect(
"选择区县",
district_options,
default=district_options
)
selected_types = st.sidebar.multiselect(
"选择类型",
type_options,
default=type_options
)
score_min = float(gdf["score"].min())
score_max = float(gdf["score"].max())
selected_score = st.sidebar.slider(
"评分范围",
min_value=score_min,
max_value=score_max,
value=(score_min, score_max)
)
filtered = gdf[
(gdf["district"].isin(selected_districts)) &
(gdf["type"].isin(selected_types)) &
(gdf["score"] >= selected_score[0]) &
(gdf["score"] <= selected_score[1])
].copy()
left, right = st.columns([2, 1])
with left:
st.subheader("交互地图")
center_lon = filtered["lon"].mean() if not filtered.empty else gdf["lon"].mean()
center_lat = filtered["lat"].mean() if not filtered.empty else gdf["lat"].mean()
layer = pdk.Layer(
"ScatterplotLayer",
data=filtered,
get_position="[lon, lat]",
get_radius=120,
get_fill_color="[255, 80, 80, 180]",
pickable=True
)
view_state = pdk.ViewState(
longitude=center_lon,
latitude=center_lat,
zoom=10,
pitch=0
)
tooltip = {
"html": "<b>名称:</b>{name}<br/>"
"<b>区县:</b>{district}<br/>"
"<b>类型:</b>{type}<br/>"
"<b>评分:</b>{score}",
"style": {"backgroundColor": "white", "color": "black"}
}
deck = pdk.Deck(
layers=[layer],
initial_view_state=view_state,
tooltip=tooltip
)
st.pydeck_chart(deck, use_container_width=True)
with right:
st.subheader("统计概览")
st.metric("筛选后点位数量", len(filtered))
st.metric("原始点位数量", len(gdf))
if not filtered.empty:
st.write("按类型统计")
type_count = filtered.groupby("type").size().reset_index(name="count")
st.bar_chart(type_count, x="type", y="count")
st.write("属性表预览")
st.dataframe(
filtered[["name", "district", "type", "score", "lon", "lat"]],
use_container_width=True
)
else:
st.info("当前筛选条件下没有数据,请调整侧边栏筛选项。")
4. 启动Streamlit应用
在命令行进入项目目录,执行:
streamlit run app.py
浏览器会自动打开本地页面。你应该能看到左侧筛选栏、地图窗口、统计指标、柱状图和属性表。
5. 检查地图是否正确显示
运行后重点检查三件事:
- 地图中心是否在数据实际所在城市或区域。
- 点位是否与底图大致匹配。
- 筛选区县、类型、评分后,地图和统计图是否同步变化。
如果地图显示为空白,优先检查坐标系、经纬度字段和数据是否被筛选为空。
常见坑:Streamlit入门做GIS可视化最容易出错的地方
1. 坐标系不是EPSG:4326
交互地图代码中最常见的问题是坐标系错误。Web地图通常需要经纬度坐标,如果你的数据是投影坐标,点位可能显示到海上、国外或完全不可见。
解决方法是在读取后统一转换:
if gdf.crs.to_epsg() != 4326:
gdf = gdf.to_crs(epsg=4326)
但前提是原始数据必须有正确的 CRS 信息。如果 CRS 缺失,不要随便 set_crs,应先确认数据真实坐标系。
2. Shapefile中文字段或路径乱码
Shapefile 对中文字段名、编码和长字段名并不友好。Streamlit 读取后如果字段乱码,建议优先把数据转换为 GeoPackage 或 GeoJSON。
gdf = gpd.read_file("data/source.shp")
gdf.to_file("data/poi_sample.geojson", driver="GeoJSON")
如果是正式项目,更推荐使用 GeoPackage,因为它比 Shapefile 更适合保存字段、编码和复杂数据结构。
3. 数据量太大导致页面卡顿
Streamlit 适合快速应用,但如果一次性加载几十万点并全部渲染到浏览器,页面会明显卡顿。解决思路包括:
- 先按行政区、时间或类型过滤,再渲染地图。
- 对点数据进行抽样展示。
- 使用聚合图层或热力图图层。
- 把大数据放入 PostGIS,前端只请求当前范围内的数据。
4. 缓存没有更新
示例中使用了 @st.cache_data 缓存读取结果。优点是刷新页面时不用反复读取文件,缺点是数据文件修改后可能没有立即更新。
调试阶段如果怀疑缓存影响结果,可以临时删除缓存装饰器,或在 Streamlit 页面菜单中清理缓存。
5. 字段名和代码不一致
如果你的数据中没有 district、type、score 字段,代码会报错。实际项目中要把字段名改成自己的数据字段,或者在读取后做字段映射。
gdf = gdf.rename(columns={
"区县": "district",
"类别": "type",
"评分": "score"
})
方法比较:Streamlit、QGIS、Leaflet和OpenLayers怎么选
| 方案 | 适合场景 | 优点 | 限制 |
|---|---|---|---|
| Streamlit | Python数据分析、GIS看板、内部工具、快速原型 | 开发快,不需要前端基础,适合结合GeoPandas和Pandas | 复杂WebGIS交互能力有限,高并发和大型系统需谨慎 |
| QGIS | 桌面制图、空间分析、数据检查、专题图出图 | GIS功能完整,插件丰富,适合专业制图 | 网页交互和多人访问不如Web应用方便 |
| Leaflet | 轻量级WebGIS地图展示 | 简单、生态成熟、适合常规二维地图 | 需要JavaScript基础,复杂数据分析要另配后端 |
| OpenLayers | 专业WebGIS、复杂图层、投影和交互控制 | GIS能力强,适合工程化WebGIS项目 | 学习曲线比Leaflet和Streamlit更高 |
| PostGIS + Web前端 | 空间数据库、海量数据、空间查询服务 | 适合正式系统和多用户访问 | 架构更复杂,需要数据库和后端开发能力 |
简单说,如果你是GIS分析人员,想快速展示分析结果,Streamlit 很合适。如果你要做正式WebGIS平台,Streamlit 可以作为原型验证工具,但不建议直接替代完整的前后端架构。
检查清单:发布前确认这些GIS细节
- 数据路径:确认
data/poi_sample.geojson在项目目录中真实存在。 - 坐标系:确认空间数据已经转换到 EPSG:4326。
- 几何类型:本文示例是点数据,如果是线或面,需要更换 PyDeck 图层类型。
- 字段名称:确认
name、district、type、score与实际数据一致。 - 空值处理:筛选字段中如果有大量空值,需要先填充或单独处理。
- 数据量:点数量过大时,先抽样、聚合或按范围查询。
- 缓存策略:数据频繁更新时,谨慎使用缓存。
- 部署环境:确认服务器能安装 GeoPandas 相关依赖。
FAQ:Streamlit入门和GIS交互地图常见问题
Streamlit入门需要先学前端吗?
不需要。Streamlit 的优势就是用 Python 写交互页面。你只要熟悉 Pandas、GeoPandas 和基础 Python,就可以完成很多 GIS 数据可视化项目。但如果要做复杂地图控件、权限系统和前后端分离架构,仍然需要学习前端和WebGIS框架。
Streamlit能直接读取Shapefile吗?
可以。GeoPandas 支持读取 Shapefile,代码是 gpd.read_file("data/xxx.shp")。不过 Shapefile 容易遇到编码、字段长度和多文件管理问题,项目中更推荐使用 GeoPackage 或 GeoJSON。
为什么我的Streamlit交互地图不显示点?
优先检查四个问题:坐标系是否为 EPSG:4326,经纬度是否写反,筛选后数据是否为空,几何是否为 Point。很多地图空白问题不是 Streamlit 本身导致的,而是空间数据预处理不正确。
Streamlit适合做正式WebGIS系统吗?
Streamlit 更适合数据应用、内部工具、分析看板和快速原型。正式WebGIS系统通常还需要用户权限、地图服务、空间数据库、瓦片服务、前端地图框架和后端接口,建议使用 PostGIS、GeoServer、Leaflet、OpenLayers 或 Cesium 等组合。
PyDeck和Folium在Streamlit里怎么选?
如果你想快速做点图、热力图、柱状图层和较现代的交互效果,可以优先试 PyDeck。如果你更熟悉 Leaflet 生态、需要加载常规瓦片底图和插件,可以使用 Folium 或 streamlit-folium。
Streamlit GIS项目可以部署到服务器吗?
可以。常见方式包括部署到 Linux 服务器、Docker 容器或支持 Python 应用的平台。部署前要重点测试 GeoPandas、GDAL、pyogrio、Fiona 等地理空间依赖是否能正常安装。
结论:用一个小项目读懂Streamlit入门更高效
对于GIS读者来说,Streamlit入门不必停留在组件介绍上。最有效的方法是围绕一个真实的 GIS 数据可视化项目,把空间数据读取、坐标系处理、属性筛选、交互地图代码和统计图表完整跑通。
本文示例适合做学习模板:GeoPandas 负责读取和处理空间数据,Streamlit 负责页面和交互控件,PyDeck 负责地图渲染。掌握这个结构后,你可以继续扩展线图层、面图层、热力图、行政区统计、PostGIS查询和在线部署。
如果你后续要把它用于正式项目,请重点加强三部分:坐标系校验、数据量控制和部署环境管理。这样 Streamlit 才能从“能跑的演示”变成“真正可用的GIS数据应用”。