Streamlit入门怎么读?GIS数据可视化项目实战教程(附:交互地图代码)

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

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

Streamlit入门 GIS数据可视化 交互地图代码项目流程图
Streamlit GIS数据可视化项目的基本流程:读取空间数据、筛选属性、渲染交互地图并输出统计结果。

引言: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 数据可视化页面通常由四部分组成:

  1. 数据读取:用 GeoPandas 读取 GeoJSON、Shapefile、GeoPackage 等空间数据。
  2. 数据清洗:检查坐标系、字段、空几何、经纬度范围等问题。
  3. 交互控件:用 Streamlit 的侧边栏、下拉框、多选框、滑块完成筛选。
  4. 地图渲染:用 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. 字段名和代码不一致

如果你的数据中没有 districttypescore 字段,代码会报错。实际项目中要把字段名改成自己的数据字段,或者在读取后做字段映射。

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 图层类型。
  • 字段名称:确认 namedistricttypescore 与实际数据一致。
  • 空值处理:筛选字段中如果有大量空值,需要先填充或单独处理。
  • 数据量:点数量过大时,先抽样、聚合或按范围查询。
  • 缓存策略:数据频繁更新时,谨慎使用缓存。
  • 部署环境:确认服务器能安装 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数据应用”。