MapLibre Native的Python封装
项目描述
PyMGL:Maplibre GL Native静态渲染器,用于Python
此包提供了一个接口,用于将Mapblibre Native渲染为PNG图像的Mapbox GL / Maplibre GL样式。
警告:此包处于积极开发中,API可能会不通知而更改。
目标
此包旨在提供一个轻量级接口,用于使用Python将Mapbox GL / Maplibre GL样式渲染到PNG图像数据中。这对于在报告中使用服务器端渲染地图特别有用。
此包仅提供与maplibre-native
交互的Python API;它不提供更高层次的功能,如Web服务器或CLI。
安装
支持的操作系统
MacOS 12+,Ubuntu 18+,Debian 10+,Fedora 29+,RHEL 8+,Alma Linux 8+
PyPI上提供了x86_64和arm64的wheel包
pip install pymgl
注意:目前MacOS上不支持x86_64的wheel包。
要验证pymgl是否安装正确,请使用测试依赖项安装,并运行包含的测试套件
pip install pymgl[test]
pytest --pyargs pymgl -v
Windows
Windows目前不支持,将来也不会支持。
使用方法
要创建地图对象,您必须始终提供一个Mapbox GL / Maplibre GL样式JSON字符串或指向Mapbox或Maptiler托管的有效样式的URL
from pymgl import Map
style = """{
"version": 8,
"sources": {
"basemap": {
"type": "raster",
"tiles": ["https://services.arcgisonline.com/arcgis/rest/services/Ocean/World_Ocean_Base/MapServer/tile/{z}/{y}/{x}"],
"tileSize": 256
}
},
"layers": [
{ "id": "basemap", "source": "basemap", "type": "raster" }
]
}"""
map = Map(style, <height=256>, <width=256>, <ratio=1>, <longitude=0>, <latitude=0>, <zoom=0>, <token=None>, <provider=None>)
有关地图样式的更多信息,请参阅样式部分。
除了样式外,所有其他参数都是可选的,并具有默认值。
注意:一旦实例构造完成,style
和ratio
就不能更改。
您可以使用已知样式而不是提供样式JSON字符串,但您还必须提供令牌并确定正确的提供者
map = Map("mapbox://styles/mapbox/streets-v11", token=<mapbox token>, provider="mapbox")
有效的提供者有mapbox
、maptiler
和maplibre
。
地图属性
在创建地图实例后,您可以在其上设置额外的属性
map.setCenter(longitude, latitude)
map.setZoom(zoom)
map.setSize(width, height)
map.setBearing(bearing) # map bearing in degrees
map.setPitch(pitch) # map pitch in degrees
map.setFilter(layerId, filterJSON or None)
map.setPaintProperty(layerId, property, value)
map.setVisibility(layerId, True / False)
如果需要,您可以使用属性来检索这些值
map.size # (width, height)
map.center # (longitude, latitude)
map.zoom
map.bearing
map.pitch
您还可以检索有关地图样式或特定层的信息
map.listLayers() # [<layerId1>, ...]
map.listSources() # [<sourceId1>, ...]
map.getFilter(<layerId>) # returns JSON value or None
map.getPaintProperty(<layerId>, <property>) # returns JSON value or None
map.getLayerJSON(<layerId>) # returns JSON describing layer
注意:绘制属性可能被解码为其内部表示。例如,CSS颜色字符串#FF0000
将返回为["rgba", 255, 0, 0, 1]
。
重要:如果您正在使用远程托管样式,您需要在列出样式层、源或其他属性之前强制地图加载(这会加载所有底层资产)。
map = Map("mapbox://styles/mapbox/streets-v11", token=<mapbox token>, provider="mapbox")
map.listLayers() # []
map.load()
map.listLayers() # [<layerId1>, ...]
或者,您可以自己下载样式并将其作为Map的输入提供,这样它将显示所有层,而不需要先进行渲染。但是,直到第一次渲染,并非所有资产都会被加载。
from urllib.request import urlopen
url = f"https://api.mapbox.com/styles/v1/mapbox/streets-v11?access_token={MAPBOX_TOKEN}"
with urlopen(url) as r:
style = r.read()
map = Map(style.decode("UTF-8") token=<mapbox token>, provider="mapbox")
map.listLayers() # [<layerId1>, ...]
您可以自动将地图拟合到边界,而不是使用中心经纬度和缩放级别
map.setBounds(xmin, ymin, xmax, ymax, <padding=0>)
您可以通过提供ID、原始图像字节数、宽度、高度、像素比以及指示是否将其解释为SDF来注册图像以供您的样式使用
map.addImage("id", img_bytes, width, height, <ratio=1>, <make_SDF=False>)
有关使用SDF图像的更多信息,请参阅SDF图像文档。
渲染
您可以将地图渲染为PNG字节数据
img_bytes = map.renderPNG()
这返回包含RGBA PNG数据的bytes
。
您可以将地图渲染为numpy数组(uint8
数据类型)的原始缓冲区
array = map.renderBuffer()
该数组是图像中每个像素的RGBA值序列。
如果您打算立即将图像数据读入其他包(如Pillow
或pyvips
)以进行其他图像操作,这可能会很有用。
地图实例
警告:如果您将新的地图实例分配给该变量,则必须手动删除地图实例,否则此包将崩溃(尚未确定原因)。如果将单独的实例分配给不同的变量,则不会出现此问题。
map = Map(<style>, <width>, <height>)
del map # must manually delete BEFORE creating a new instance assigned to this
map = Map(<style>, <width>, <height>)
因此,您应该考虑使用上下文管理器
with Map(<style>, <width>, <height>) as map:
map.renderPNG()
如果您不需要在地图实例上设置其他属性,您还可以使用地图实例直接渲染到PNG
Map(<style>, <width>, <height>).renderPNG()
样式
PyMGL应支持Mapbox GL JS 1.13的基本样式。
远程瓦片集、源和资产
远程瓦片集、瓦片源和资产(符号、精灵)应得到良好支持。这些由我们无法控制的底层C++库加载。通常,无效的URL将引发错误。但是,网络超时或不正确的格式可能导致进程崩溃。
本地mbtiles
本地MBTiles得到支持,但必须使用绝对路径作为瓦片集的url
源提供mbtiles文件;它必须解析为实际文件。
本地MBTiles使用mbtiles://
URI前缀表示。
示例
{
"sources": {
"source_id": {
"url": "mbtiles:///<pymgl_root_dir>/tests/fixtures/geography-class-png.mbtiles",
...
}
},
"layers": [...],
...
}
本地文件
GeoJSON文件和其他本地文件资源受支持,但必须使用到文件源点的绝对路径提供。
示例
{
"sources": {
"geojson": {
"type": "geojson",
"data": "file:///<pymgl_root_dir>/tests/fixtures/test.geojson"
}
},
"layers": [...],
...
}
警告:当前Maplibre Native不支持在源的tiles
键下提供瓦片URI;尝试这样做将失败。
图像
在渲染地图之前,您必须将图像与地图实例注册。请参阅上面的map.addImage()
。
{
"sources": {...},
"layers": [
{
...,
"paint": {
"fill-pattern": "pattern"
}
},
]
}
您可以使用地图图像作为填充图案或图标图像。
构建后添加来源和图层
您可以在构建地图实例后动态地添加来源和图层。
import json
map = Map("") # construct with empty style
map.addSource("my_id", json.dumps({
"type": "geojson",
"data": {"type": "Point", "coordinates": [0, 0]}
}))
map.addLayer(json.dumps({
"id": "geojson-point",
"source": "geojson",
"type": "circle",
"paint": { ... }
}))
要素状态
地图加载后,您可以获取、设置和删除要素状态。
map = Map(<style with source "exampleSource" and layer "exampleLayer">, ...)
map.load()
map.getFeatureState("exampleSource", "exampleLayer", "0") # returns None
map.setFeatureState("exampleSource", "exampleLayer", "0", "{\"a\": true}")
map.getFeatureState("exampleSource", "exampleLayer", "0") # returns "{\"a\": true}"
# remove the state value for key "a"
map.removeFeatureState("exampleSource", "exampleLayer", "0", "a")
map.render()
map.getFeatureState("exampleSource", "exampleLayer", "0") # returns None
注意:要素必须已在每个要素上设置一个唯一的、数字的ID。当前不支持Maplibre GL JS中的promoteId
。
重要:在获取或设置要素状态之前,地图必须已加载。在删除状态键后,您必须手动强制渲染,以便地图更新要素状态。
不支持的功能
PyMGL不支持替代投影或3D地形。
开发
依赖项
MacOS
在MacOS上开发需要通过homebrew
安装以下二进制库
- cmake
- ninja
在Ubuntu上开发需要以下二进制库
- cmake
- ninja-build
- build-essential
- libcurl4-openssl-dev
- libicu-dev
- libpng-dev
- libwebp-dev
- libprotobuf-dev
- libjpeg-turbo8-dev
- libx11-dev
- libegl-dev
- libopengl-dev
- xvfb
在Linux上运行时,XVFB也必须运行;否则进程将崩溃。
有关更多信息,请参阅docker/README.md
。
nanobind
nanonbind
用于提供Python对封装maplibre-native
的C++类的绑定,以简化渲染操作。
它作为git子模块包含在此处,按照安装说明。
git submodule add https://github.com/wjakob/nanobind vendor/nanobind
cd vendor/nanobind
git submodule update --init --recursive
然后,如果需要,升级到特定版本的nanobind进行开发
cd vendor/nanobind
git checkout <version tag>
Maplibre Native
Maplibre Native作为git子模块包含在内,它还包括许多自己的子模块。
git submodule add -b main https://github.com/maplibre/maplibre-native vendor/maplibre-native
Git子模块
运行
git submodule update --init
我们只需要maplibre-native下的某些子模块。特别是,我们不需要maplibre-gl-js
或Android / IOS依赖项。
运行以下命令
cd vendor/maplibre-native
git submodule update --init --recursive \
vendor/boost \
vendor/cpp-httplib \
vendor/earcut.hpp \
vendor/eternal \
vendor/googletest \
vendor/metal-cpp \
vendor/polylabel \
vendor/protozero \
vendor/mapbox-base \
vendor/unique_resource \
vendor/unordered_dense \
vendor/vector-tile \
vendor/wagyu \
vendor/zip-archive
以更新maplibre-native
cd vendor/maplibre-native
git checkout main
git pull origin
cd ../..
git commit -am "update maplibre-native" to latest
架构
此包由两部分组成
- Maplibre Native类的包装,以便更容易构建和管理地图属性
- 使用nanobind针对该包装器创建的Python绑定
包装器位于src/map.cpp
中。
构建
C++测试
有关更多信息,请参阅tests/README。
构建Python扩展
Python setup.py
脚本管理使用CMake构建库和扩展。
从项目根目录
python setup.py build_ext --inplace
Docstrings / 类型信息
Docstrings维护在src/_pymgl.cpp
和pymgl/__init__.pyi
中。
Python友好的类型注释维护在pymgl/__init__.pyi
中。
注意:pymgl/__init__.pyi
对于支持VSCode中的自动完成和工具提示是必要的。
构建wheel
大多数wheel在推送新的版本标签时由GitHub自动构建。Linux Arm64 wheel必须在Arm64机器上本地构建(例如,MacOS主机)。
这些是用manylinux_2_28 Docker容器创建的。
docker build -f ci/Dockerfile.manylinux_2_28_aarch64 -t pymgl-manylinux_2_28_aarch64 .
docker run -v "$PWD/:/app" pymgl-manylinux_2_28_aarch64 ci/build_linux_wheels.sh
这将创建位于dist
中的aarch64 wheel,可以直接上传到PyPI。
另请参阅
mbgl-renderer([链接](https://github.com/consbio/mbgl-renderer))提供了一个基于Mapbox GL Native的NodeJS API、命令行界面和服务器。
致谢
本项目得到了美国鱼类和野生动物管理局([链接](https://www.fws.gov/))和东南部保护适应策略([链接](https://secassoutheast.org/))的支持,用于在[东南部保护蓝图查看器](https://blueprint.geoplatform.gov/southeast/)中应用。
本项目得以实现,得益于Mapbox的[mapbox-gl-native](https://github.com/mapbox/mapbox-gl-native/)项目,Mapbox社区在[maplibre-native](https://github.com/mapbox/mapbox-native/)上维护了这个开源分支的努力。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源代码分发
构建分发
哈希值 for pymgl-0.5.0-cp313-cp313-manylinux_2_28_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | e47d826f6d534e6b50ab54a30afa709aaa9c61c2e36eff8f51ef5bc39f139b47 |
|
MD5 | 57861899505f6eca809e1c75615aa217 |
|
BLAKE2b-256 | d82077638a79c127f4814952166ba4bee358b5c1b0cc37ede30d24a40bbe3875 |
哈希值 for pymgl-0.5.0-cp313-cp313-manylinux_2_28_aarch64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 6c283d971691ff25cf9913f101db88747d551455fb081d86ec3e39c31106d0ee |
|
MD5 | fb308a984bd824cdf428c3d788b35301 |
|
BLAKE2b-256 | 81796e42d22fa090e0f6b245a36f38c751a1739a96011ca6ff7cbcc915b8e06a |
哈希值用于pymgl-0.5.0-cp312-cp312-manylinux_2_28_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 79cd0bd0011a040adfd8f7fe259f88e4a5b897133525a16c22bc67721f11aded |
|
MD5 | 96d089ea548fdff61beceb1d8d5585ee |
|
BLAKE2b-256 | 3a166271dff48faa53933b6c7f79c4a4ae73c1eb0b1c26f94b93ab53d566b370 |
哈希值用于pymgl-0.5.0-cp312-cp312-manylinux_2_28_aarch64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0bb0ab32abf5b96e16683a19b972958faf868fabc1ff8b537ec9a166ccd19c6c |
|
MD5 | 98f73efbdfde02d392ceb1c18da9cba4 |
|
BLAKE2b-256 | a449ae076c89104e31af01f874cdcc9306065a6404d069ba8f7ad207a66bf731 |
哈希值用于pymgl-0.5.0-cp311-cp311-manylinux_2_28_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 49a69cfd0b4f73bd26a5ca3266a271642e72d35cac36ebb9c71aa613abb83057 |
|
MD5 | 3f48419a0e217730f50f5b88191b2087 |
|
BLAKE2b-256 | 1f17c847929395e916070ce7b2c521759301019f15881351fb765e8deb7c6ff1 |
哈希值用于pymgl-0.5.0-cp311-cp311-manylinux_2_28_aarch64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7bbc9a0975c5df58fc12c3be9843e7c16fe7e2434d7636a49355d14472967883 |
|
MD5 | af4bcb5612e7a6a5eec8f4b399dece6e |
|
BLAKE2b-256 | d3d0c9314a319f82f78ea256ea17cf9e6b66bd6676336da0147db5c0b94f29bf |
哈希值用于pymgl-0.5.0-cp310-cp310-manylinux_2_28_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a0e90da9d45aaa2816e7f838507ccb16a9e12dd7c0765e6c565e030d8f1e66e1 |
|
MD5 | cbfce93e57d7e2a810c11092e10a24dd |
|
BLAKE2b-256 | 4f8bc61be5c0d3e1f5be7374c8aca6926beb0e6aade824259effd19f5b0ed10a |
哈希值用于pymgl-0.5.0-cp310-cp310-manylinux_2_28_aarch64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 46fa4dfae2baf7d3acf23a060c059562d947cabd908cdd4bfdd11558f3cad4ee |
|
MD5 | b86d470472b574c8e0b5cb37c6930234 |
|
BLAKE2b-256 | 939e6c291c12219067f3abb6ca90141d5254ca8d6cd7f0304b6db41950d4468d |
哈希值用于pymgl-0.5.0-cp310-cp310-macosx_12_0_universal2.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 57a146031d795fe198e402191061e5c23be2ae8590c4d8e5689a4f02b9e7ac24 |
|
MD5 | 69b10488d94b837c40b86e093b72e395 |
|
BLAKE2b-256 | 4aa086710829084b697c010858a2c6330ccff45dd4c1416875479153242c366f |
哈希值用于pymgl-0.5.0-cp39-cp39-manylinux_2_28_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | ab29884fd0ae3d4a33859dc1effeaa77e7cd60bdcc1173e8e65054a77e65ba90 |
|
MD5 | 45583775e80d7776f73545116b14c9fb |
|
BLAKE2b-256 | f32ff0729d1fc3f01ec85577170d09908116c7ef108b79e89fe80af1a81a67be |
哈希值用于pymgl-0.5.0-cp39-cp39-manylinux_2_28_aarch64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 06eafb82fcf04565477332edd086a9615091d006cd0a78b726e83501ed18277c |
|
MD5 | f8575afe7e7862d42bbe05833a64f187 |
|
BLAKE2b-256 | ccbaa0788be4555ef93bc89a154b5f452bfc314d236179b409b73d57a93ea997 |
哈希值用于pymgl-0.5.0-cp39-cp39-macosx_12_0_universal2.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9e2c66824201062bfde1ceee82e789819f283a3c821a2e574bf2e9af3602faa6 |
|
MD5 | 5e9b5713a0d37f7ae0be0fd7b4b6e769 |
|
BLAKE2b-256 | 58315fe6aa2d1e40b72e0879730b9b77c2ecae0e704842f3ec28bd36646baf22 |