中文 | English
可扩展的 Python 滑块地图(Slippy Map)控件:核心逻辑与 UI 分离,提供 Tkinter、PyQt5、PyQt6、PySide6 栅格后端,以及独立的 PySide6 + MapLibre 矢量地图控件。
- 多 URL 模板瓦片下载(
{x}/{y}/{z}、Bing{quadkey}),支持 HTTP 代理 - aiohttp 异步下载,可配置并发数(默认 8),关闭时安全取消在途请求
- HTTP Content-Type 预检(拒绝明确的文本/JSON/XML,兼容缺失类型和 octet-stream)+ 常见图片文件头检查
- 分层磁盘缓存 + SQLite 索引
- 默认中心点、默认缩放级别
- 鼠标拖拽平移、滚轮缩放
- 占位瓦片(下载中显示灰色块)
- 独立
PySide6MapLibreWidget:通过 Qt WebEngine + MapLibre GL JS 渲染 MVT/PBF、Style JSON、glyph、sprite、GeoJSON 行政区/POI与瓦片调试边界,不改变栅格瓦片链路
cd pymapwidget
pip install -e .
pip install -e ".[pyqt5]" # 可选,运行 PyQt5 demo
pip install -e ".[pyqt6]" # 可选,运行 PyQt6 demo
pip install -e ".[pyside6]" # 可选,运行 PySide6 demo
pip install -e ".[maplibre-pyside6]" # 可选,运行 MapLibre PBF demo
pip install -e ".[pbf-image]" # 可选,运行单瓦片 PBF → SVG/PNG demo
pip install -e ".[dev]" # 可选,运行测试(需 Python ≥ 3.10)python demos/demo_tkinter.py
python demos/demo_pyqt5.py
python demos/demo_pyqt6.py
python demos/demo_pyside6.py
python demos/demo_maplibre_pyside6.py
python demos/pbf_to_image.py --pbf "<PBF_URL>" --output-image tile.svg
python demos/pbf_to_image.py --pbf "<PBF_URL>" --output-image tile.pngpbf_to_image.py 也接受本地 .pbf/.mvt 路径和可选 --size。不传 --pbf 或 --output-image 时会在终端提示输入。输入为 HTTP(S) URL 时,输出 tile.svg / tile.png 还会在同一目录保存同名 tile.pbf;URL 路径以 .mvt 结尾时保存为 tile.mvt,下载只执行一次。本地输入只生成图片,不复制 PBF/MVT。终端会分别打印下载/读取、解析、主要地点筛选、几何绘制、PNG 编码、文件写入和总耗时。图片会从当前瓦片所有带名称的要素中动态选择:结合 rank、地点类型、道路等级等排出优先级,在低 zoom 可显示城市和水域,在高 zoom 可改为道路、车站、医院、景点、小区或商铺;最多显示 40 个并进行简单文字避让。单个 PBF 不包含完整 MapLibre Style,因此输出使用按 source layer 分配的诊断配色,用于观察瓦片内的点、线、面和主要名称,而不是复原在线地图最终样式。
初次接触矢量瓦片时,可阅读 PBF / MVT 矢量瓦片入门。文档从基础概念讲到单瓦片 SVG/PNG 绘制、中文标注、文字避让、分段计时与局部 mask 性能优化,不要求先理解具体代码。
MapLibre 矢量控件直接加载完整 Style JSON,支持连续 zoom:
from pymapwidget.maplibre import PySide6MapLibreWidget
map_widget = PySide6MapLibreWidget(
"https://tiles.openfreemap.org/styles/liberty",
center=(32.05, 118.78),
zoom=10.0,
)
map_widget.set_on_feature_clicked(
lambda event: print(event.lat, event.lon, event.features)
)该控件由 Chromium/MapLibre 自行下载、缓存和渲染矢量资源,不使用栅格控件的 MapController、TileManager 或 tiles.db。Demo 的地图状态、屏幕四角、鼠标坐标和 PBF 瓦片 URL 均由网页端通过 Qt WebChannel 推送,并提供瓦片边界及南京行政区/POI 开关。详见 接口文档 §3.8。
PyQt5 Demo 效果:
Demo 左侧提供配置面板,支持:
- 多个配置分组(如 Google / OSM / 高德 / Bing),下拉切换并自动应用
- 共用默认 zoom / 中心(所有图源同一组数字,便于对比厂商偏移);缓存目录、多行 URL、代理、User-Agent 仍按分组
- 「设置当前地图中心为默认加载位置」写入共用默认坐标
- 配置保存到项目根目录
demo_settings.json - 切换分组、应用配置、设为当前中心、关闭窗口时均自动保存
- 窗口大小在退出时保存,下次启动恢复
- PyQt5 / PyQt6 / PySide6:勾选「显示南京行政区 + POI」与「行政区域高亮」——区县边界(DataV GCJ-02)+ 可点击 POI;缩放时智能显隐;坐标系原理见 WGS84、GCJ-02 与坐标转换入门
{cache_dir}/
├── tiles.db
└── tiles/
└── z{zoom}/
└── xb{x//256}/
└── yb{y//256}/
└── {x}_{y}.png
注意: 缓存只按
(z, x, y)标识瓦片,不记录或校验 URL 瓦片源。同一个cache_dir若先后用于不同地图源,相同坐标会直接复用原来源的缓存文件,可能出现底图混用或“切换来源后画面不变”。请为不同地图源配置不同的cache_dir;若必须复用目录,应先自行清空旧缓存。
桶编号 xb00105 表示 x // 256 == 105(不是 x=105)。详见 docs/implementation.md。
from pathlib import Path
from pymapwidget import MapConfig
config = MapConfig(
cache_dir=Path("./map_cache"),
tile_url_templates=[
"https://mt0.google.com/vt/lyrs=m&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}",
"https://mt1.google.com/vt/lyrs=m&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}",
],
proxy="http://127.0.0.1:7890", # 可为 None
default_zoom=15,
default_center=(39.9042, 116.4074),
max_concurrency=8,
)地图控件坐标换算(所有后端均提供):
# 经纬度 + zoom -> 瓦片索引
tile_x, tile_y = map_widget.lat_lon_to_tile_xy(39.9042, 116.4074, 15)
# 瓦片索引 + 瓦片内像素 (默认 0..256) -> 经纬度
lat, lon = map_widget.lat_lon_at_tile_pixel(tile_x, tile_y, 15, 128.0, 64.0)也可直接使用 core 模块:
from pymapwidget.core.mercator import lat_lon_to_tile, tile_pixel_to_lat_lon- 接口文档 — 控件 /
MapController/ 经纬度范围约定 - 实现文档 — 架构与加载/重绘流程
- WGS84、GCJ-02 与坐标转换入门 — 坐标系、偏移、转换原理与项目用法
- PBF / MVT 矢量瓦片入门 — 矢量瓦片、Style 与 MapLibre 数据流
- AGENTS.md — AI 助手协作说明
Google 等瓦片服务可能有使用条款限制。示例 URL 仅供学习,请替换为你有权使用的瓦片源。
