跳转到主要内容

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>)

有关地图样式的更多信息,请参阅样式部分。

除了样式外,所有其他参数都是可选的,并具有默认值。

注意:一旦实例构造完成,styleratio就不能更改。

您可以使用已知样式而不是提供样式JSON字符串,但您还必须提供令牌并确定正确的提供者

map = Map("mapbox://styles/mapbox/streets-v11", token=<mapbox token>, provider="mapbox")

有效的提供者有mapboxmaptilermaplibre

地图属性

在创建地图实例后,您可以在其上设置额外的属性

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值序列。

如果您打算立即将图像数据读入其他包(如Pillowpyvips)以进行其他图像操作,这可能会很有用。

地图实例

警告:如果您将新的地图实例分配给该变量,则必须手动删除地图实例,否则此包将崩溃(尚未确定原因)。如果将单独的实例分配给不同的变量,则不会出现此问题。

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.cpppymgl/__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/)上维护了这个开源分支的努力。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

本发布中没有可用的源代码分发文件。请参阅[生成分发存档的教程](https://packaging.pythonlang.cn/tutorials/packaging-projects/#generating-distribution-archives)。

构建分发

pymgl-0.5.0-cp313-cp313-manylinux_2_28_x86_64.whl (23.6 MB 查看哈希值)

上传时间 CPython 3.13 manylinux: glibc 2.28+ x86_64

pymgl-0.5.0-cp313-cp313-manylinux_2_28_aarch64.whl (23.0 MB 查看哈希值)

上传时间 CPython 3.13 manylinux: glibc 2.28+ ARM64

pymgl-0.5.0-cp313-cp313-macosx_12_0_arm64.whl (2.7 MB 查看哈希值)

上传时间 CPython 3.13 macOS 12.0+ ARM64

pymgl-0.5.0-cp312-cp312-manylinux_2_28_x86_64.whl (23.6 MB 查看哈希值)

上传时间 CPython 3.12 manylinux: glibc 2.28+ x86_64

pymgl-0.5.0-cp312-cp312-manylinux_2_28_aarch64.whl (23.0 MB 查看哈希值)

上传时间 CPython 3.12 manylinux: glibc 2.28+ ARM64

pymgl-0.5.0-cp312-cp312-macosx_14_0_arm64.whl (2.7 MB 查看哈希值)

上传时间 CPython 3.12 macOS 14.0+ ARM64

pymgl-0.5.0-cp311-cp311-manylinux_2_28_x86_64.whl (23.6 MB 查看哈希)

上传时间 CPython 3.11 manylinux: glibc 2.28+ x86-64

pymgl-0.5.0-cp311-cp311-manylinux_2_28_aarch64.whl (23.0 MB 查看哈希)

上传时间 CPython 3.11 manylinux: glibc 2.28+ ARM64

pymgl-0.5.0-cp311-cp311-macosx_14_0_arm64.whl (2.7 MB 查看哈希)

上传时间 CPython 3.11 macOS 14.0+ ARM64

pymgl-0.5.0-cp310-cp310-manylinux_2_28_x86_64.whl (23.6 MB 查看哈希)

上传时间 CPython 3.10 manylinux: glibc 2.28+ x86-64

pymgl-0.5.0-cp310-cp310-manylinux_2_28_aarch64.whl (23.0 MB 查看哈希)

上传时间 CPython 3.10 manylinux: glibc 2.28+ ARM64

pymgl-0.5.0-cp310-cp310-macosx_12_0_universal2.whl (2.7 MB 查看哈希)

上传时间 CPython 3.10 macOS 12.0+ universal2 (ARM64, x86-64)

pymgl-0.5.0-cp39-cp39-manylinux_2_28_x86_64.whl (23.6 MB 查看哈希)

上传时间 CPython 3.9 manylinux: glibc 2.28+ x86-64

pymgl-0.5.0-cp39-cp39-manylinux_2_28_aarch64.whl (23.0 MB 查看哈希)

上传时间 CPython 3.9 manylinux: glibc 2.28+ ARM64

pymgl-0.5.0-cp39-cp39-macosx_12_0_universal2.whl (2.7 MB 查看哈希)

上传时间 CPython 3.9 macOS 12.0+ universal2 (ARM64, x86-64)

支持者:

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面