普通在线地图更关心道路导航、地点搜索和路线规划,但如果需求变成“把一座城市的街道、建筑、水域和绿地绘制成一张具有设计感的图片”,传统地图服务往往不是最方便的工具。

Prettymaps解决的就是这一类问题。它并不是一个导航软件,而是一个Python地图绘制库:从OpenStreetMap获取地理数据,再借助OSMnx、Matplotlib、Shapely和vsketch等工具,将道路、建筑、水域、绿地等对象转换成可以自由调整样式的地图图形。

从项目目前的定位来看,它更接近“地图数据获取 + Python绘图 + 生成艺术”之间的一层封装。用户不必从头处理完整的OpenStreetMap数据流程,就可以通过相对简洁的代码生成一个地点的风格化地图。

Prettymaps:用Python和OpenStreetMap生成风格化地图

Prettymaps主要解决什么问题

如果直接使用OpenStreetMap原始数据制作地图,通常需要处理地点查询、道路网络、建筑轮廓、空间范围、坐标投影以及Matplotlib绘图等多个环节。对于只是想制作一张视觉化地图的用户,这些步骤容易让代码迅速变得复杂。

Prettymaps把其中不少流程集中到了prettymaps.plot()接口中。最简单的情况下,只需要提供一个地点:

import prettymaps

plot = prettymaps.plot(
    'Stad van de Zon, Heerhugowaard, Netherlands'
)

项目教程显示,查询位置不仅可以使用地址或地名,还可以直接传入经纬度坐标,也可以提供GeoDataFrame形式的自定义边界。

这意味着它既适合快速绘制某个街区,也可以用于已经掌握GIS数据、希望进一步控制地图范围的Python用户。

地图数据和绘图是怎样组合的

Prettymaps生成的地图并不是简单截取一个在线地图页面。它会根据配置获取OpenStreetMap中的不同地理对象,然后分别进行绘制。

例如一张城市地图可能包含:

  • 道路和不同等级的街道;

  • 建筑物轮廓;

  • 公园、草地和森林;

  • 河流、湖泊、海湾等水域;

  • 停车场、步行区域或码头;

  • 地图边界和背景。

这些对象可以被拆分成不同图层,再分别设置颜色、边框、线宽、透明度以及其他Matplotlib样式参数。因此,同一个地点并不只能生成一种固定地图。

这也是Prettymaps和普通“地图截图工具”的主要差别:地图中的建筑、道路和自然区域仍然是可以通过代码分别控制的地理数据,而不是一张已经完全扁平化的底图。

图层和样式是核心控制方式

项目当前教程中比较重要的两个参数是layersstyle

layers决定从OpenStreetMap中获取哪些对象。例如,可以根据OpenStreetMap标签查询建筑、水域、森林和公园:

layers={
    "green": {
        "tags": {
            "landuse": "grass",
            "natural": ["island", "wood"],
            "leisure": "park"
        }
    },
    "water": {
        "tags": {
            "natural": ["water", "bay"]
        }
    },
    "building": {
        "tags": {
            "building": True
        }
    }
}

style则负责决定这些图层最终怎样显示。用户可以为不同对象定义填充颜色、轮廓颜色、线宽和调色板。

例如建筑和水域完全可以使用不同的视觉语言,建筑甚至可以从一组颜色中选择调色板,而不是所有建筑使用同一种颜色。

对于需要制作海报、城市插画、项目封面或地理主题视觉素材的用户,这种“先选择地图对象,再控制视觉样式”的方式要比修改一张地图截图灵活得多。

不想从零配色可以使用预设

并不是所有人都希望每次生成地图时重新配置道路宽度、建筑颜色和背景。Prettymaps因此提供了Preset预设机制。

调用时可以直接指定预设:

plot = prettymaps.plot(
    'Stad van de Zon, Heerhugowaard, Netherlands',
    preset='minimal'
)

项目当前文档还列出了default、minimal、macao、tijuca等预设示例。通过prettymaps.presets()可以查看可用预设,通过prettymaps.preset()可以检查具体配置。

如果已经形成自己的地图视觉方案,还可以使用prettymaps.create_preset()创建预设,将图层和样式配置保存下来。

对于需要重复制作不同城市地图的场景,这一点尤其有价值。比如一套文章封面需要分别绘制北京、东京和巴黎,与其分别调整三套颜色,不如先确定统一的视觉规范,再让不同地点复用同一套预设。

生成结果还能继续用Matplotlib处理

prettymaps.plot()返回的并不只是最终图片。当前项目将结果封装为一个Plot数据类,其中包含各图层的GeoDataFrame,以及Matplotlib的figax对象。

因此,地图生成以后仍然可以继续进行Matplotlib级别的修改。例如增加标题:

plot.fig.patch.set_facecolor('#F2F4CB')
plot.ax.set_title('Barcelona', font='serif', size=50)

用户也可以直接访问某一个图层对应的GeoDataFrame,继续筛选建筑、检查几何对象,或者把这些数据用于其他空间分析和绘图流程。

从这个角度看,Prettymaps更像一个可继续扩展的Python绘图流程,而不是点击“生成”之后就无法再修改的成品地图工具。

除了普通地图还能做哪些效果

项目当前教程已经覆盖了一些比基础街区地图更进一步的用法。

绘制完整行政或地理区域

默认绘图通常围绕指定地点和一定半径展开。如果希望按照实际区域边界进行绘制,可以将radius设置为False

plot = prettymaps.plot(
    'Bom Fim, Porto Alegre, Brasil',
    radius=False
)

在同一画布组合多个地区

项目提供prettymaps.multiplotprettymaps.Subplot,可以把多个区域放到同一张画布中,并为不同区域指定不同样式。

这种方式可以用于城市街区对比、多地点主题海报,或者将几个相关区域组合成一张视觉作品。

加入地形阴影

当前版本支持hillshade地形阴影。对于山地、海岛或地形变化明显的地区,可以将高低起伏产生的阴影加入地图,让单纯的道路和建筑图层获得更多地形信息。

标记关键地点

Prettymaps还支持keypoints。项目示例中既可以按照OpenStreetMap标签寻找海滩等对象,也可以搜索指定名称的地点。

如果制作的是旅游区域、自然地理主题或者特定地点的地图,这种方式比单纯展示道路更加实用。

还可以为绘图机输出SVG

Prettymaps集成了vsketch相关能力,并提供plotter模式。官方教程给出的用途是生成适合pen plotter绘图机使用的SVG。

plot = prettymaps.plot(
    (41.39491, 2.17557),
    mode='plotter',
    layers=dict(perimeter={}),
    preset='barcelona-plotter',
    scale_x=0.6,
    scale_y=-0.6
)

这使它的用途不仅停留在网页图片或数据可视化,还可以延伸到实体绘图、地图艺术和生成艺术作品。

如果用户只是需要一张标准导航地图,这些能力可能没有太大价值;如果目标本身就是地图视觉设计,输出方式的可控性才是Prettymaps真正值得关注的部分。

安装和运行需要哪些环境

项目官方提供的本地安装方式比较直接:

pip install prettymaps

也可以在Google Colab中从GitHub仓库安装。官方说明中,Colab安装完成后需要重启Runtime再导入Prettymaps。

仓库当前还包含一个Streamlit前端,安装项目后可以从仓库目录启动:

streamlit run app.py

这为不希望每一次都直接操作Python函数的用户提供了另一种交互方式,不过Prettymaps整体仍然是一个Python开发工具,并不是完全免配置的桌面地图软件。

需要注意的是,当前主分支的setup.py声明Python版本要求为3.12及以上,而PyPI上已经发布的1.4.2版本元数据显示Python要求为3.11及以上。使用GitHub主分支和使用PyPI稳定包时,环境要求可能并不完全一致,安装前最好根据实际使用的版本检查依赖。

参考资料

  1. Prettymaps GitHub项目仓库

  2. Prettymaps官方使用教程

  3. Prettymaps版本发布记录

  4. Prettymaps PyPI软件包页面

  5. Prettymaps项目许可证