MapToPoster:用一行命令把任意城市路网变成极简装饰海报(OSM + OSMnx)
阅读时间: 大约 14 分钟
MapToPoster:用一行命令把任意城市路网变成极简装饰海报(OSM + OSMnx)

MapToPoster(仓库原名 City Map Poster Generator)是 GitHub 用户 originalankur 开源的 Python 单脚本工具:输入城市名与国家,从 OpenStreetMap(OSM)取路网数据,渲染成一张极简风格的竖版地图海报 PNG。MIT 协议。本文基于仓库 README、requirements 与仓库页面做一手核对。
一、背景动机:把”城市轮廓”变成可打印的墙饰
城市路网本身具有强装饰性:曼哈顿的方格、威尼斯的运河网、东京的有机街道、巴黎的放射大道。现成的地图海报多为付费素材或手工设计,而 OSM 已经提供了开放的全球路网数据。MapToPoster 把”地理编码 → 取路网 → 按主题配色渲染”串成一条命令,让没有设计基础的人也能批量生成自己城市的装饰画。仓库页面(2026-10-19 快照)显示约 14.2k stars、1.3k forks、47 watching;Koala 项目库收录时(#1540)记录为 6900+ star,两个数字对应不同时间点,不宜混用。
二、是什么:CLI 脚本,不是 App
- 形态:核心是
create_map_poster.py一个脚本,配合font_management.py管理字体,主题放在themes/目录的 JSON 文件里;无 Web 界面、无桌面 App。 - 依赖:requirements.txt 锁定
matplotlib==3.10.8、osmnx==2.0.7;推荐用 uv(uv run ./create_map_poster.py --city "Paris" --country "France"),也支持 pip + venv。 - 协议:MIT。
- 输出:PNG 写入
posters/,命名{city}_{theme}_{YYYYMMDD_HHMMSS}.png。
三、技术机制:地理编码 → OSMnx 取图 → matplotlib 分层渲染
README 的架构图把管线分为四段:CLI Parser(argparse)→ Geocoding(Nominatim)→ Data Fetching(OSMnx)→ Rendering(matplotlib)→ Output。
- 地理编码:
get_coordinates()调用 OpenStreetMap 的 Nominatim 服务,把城市名+国家名转成经纬度;也可用--latitude/-lat、--longitude/-long直接覆盖中心点。 - 路网获取:OSMnx 的
ox.graph_from_point(point, dist=dist, network_type=...)以中心点为圆心、按半径拉取街道网络;network_type可选 drive/bike/walk,README 性能提示推荐drive(只取机动车道)以加速。 - 分层渲染(z-order):
| z 值 | 图层 |
|---|---|
| z=11 | 文字标签(城市名、国家、坐标) |
| z=10 | 上下渐变压暗(gradient fades) |
| z=3 | 道路(ox.plot_graph) |
| z=2 | 公园(绿色面) |
| z=1 | 水域(蓝色面) |
| z=0 | 背景色 |
- 道路层级配色与线宽(
get_edge_colors_by_type()/get_edge_widths_by_type()按 OSM highway tag):
| OSM 道路类型 | 线宽 | 视觉 |
|---|---|---|
| motorway / motorway_link | 1.2 | 最粗、最深/最亮 |
| trunk / primary | 1.0 | 粗 |
| secondary | 0.8 | 中 |
| tertiary | 0.6 | 细 |
| residential / living_street | 0.4 | 最细、最浅 |
- 排版与文字检测:
is_latin_script()用 Unicode 区间(U+0000–U+024F)判定,字母占比超过 80% 即视为拉丁文字,给城市名加字距形成 “P A R I S” 效果;日文、阿拉伯文、韩文等非拉丁文字保持自然间距。文字用transform=ax.transAxes归一坐标定位:y=0.14 城市名、0.125 装饰线、0.10 国家名、0.07 坐标、0.02 右下角 attribution。 - 多语言与字体:
--display-city/-dc、--display-country/-dC自定义显示名,--font-family指定 Google Fonts 家族(如 Noto Sans JP / Noto Sans KR / Cairo / Noto Sans SC / Noto Sans Thai / Noto Sans Khmer),字体自动下载并缓存到fonts/cache/。

四、关键参数与规格
| 项目 | 默认 / 取值 | 说明 |
|---|---|---|
| 必选 | --city/-c、--country/-C | 用于 Nominatim 地理编码 |
主题 --theme/-t | terracotta | 内置 17 个,--list-themes 列出,--all-themes 全量生成 |
半径 --distance/-d | 18000 米 | 4000–6000m 小城密集中心;8000–12000m 中等城市市中心;15000–20000m 大都市全景 |
画布 --width/-W / --height/-H | 12 × 16 英寸 | 上限各 20 英寸 |
| 分辨率 | 300 DPI | 默认 12×16in 即 3600×4800px |
README 给出的 300 DPI 目标分辨率对照:Instagram 1080×1080 = 3.6×3.6in;手机壁纸 1080×1920 = 3.6×6.4in;HD 壁纸 1920×1080 = 6.4×3.6in;4K 3840×2160 = 12.8×7.2in;A4 印刷 2480×3508 = 8.3×11.7in。
17 个内置主题:gradient_roads、contrast_zones、noir、midnight_blue、blueprint、neon_cyberpunk、warm_beige、pastel_dream、japanese_ink、emerald、forest、ocean、terracotta、sunset、autumn、copper_patina、monochrome_blue。自定义主题只需在 themes/ 放一个 JSON,字段覆盖 bg/text/gradient_color/water/parks/road_motorway/primary/secondary/tertiary/residential/default。

五、评测方法与口径批判:它测的是什么、不是什么
- 无客观评测,只有视觉样例:README 给出的是 10 个城市的成品海报与推荐半径,没有渲染耗时、内存占用、定位成功率等量化指标;“好不好看”是主观判断,本文不把样例效果外推为对所有城市的保证。
- 星数是实时快照:14.2k 为浏览当日页面读数,随时间变动;Koala 条目里的 6900+ 是收录时点值,两者不是矛盾,而是时间差。
- 地图不是测绘产品:海报不提供比例尺、指北针与精确方位,中心坐标是城市中心点而非图幅范围;它是艺术化投影,不能用于导航、量距或选址。
- 半径靠经验推荐:4–6 / 8–12 / 15–20km 三档是作者按城市规模给的经验区间,同一座城市换半径会得到完全不同的构图,不存在”正确值”。
六、适用与不适用场景
适合:
- 想为自己所在城市、母校、故乡做个性化装饰画或礼物的个人;
- 需要批量出图(
--all-themes)做壁纸、社媒封面的内容创作者; - 学习 OSMnx 取路网、matplotlib 分层绘图的 Python 学习者;
- 愿意本地跑命令、不需要界面的技术用户。
不适合:
- 想要网页上传即出图、零配置的非技术用户(README 的 Contributors Guide 明确不收 Web/桌面 UI);
- 需要精确地图、可交互地图或商用测绘底图的项目;
- 期望开箱支持铁路、建筑等高阶图层的用户(README 仅以代码片段示例如何自行加铁路层)。
七、客观分析:优势与局限
优势:
- 零设计门槛:一行命令出图,配色、线宽、排版全部预设;
- 主题扩展成本低:新增主题只是写一个 JSON,不必改代码;
- 管线透明:Nominatim + OSMnx + matplotlib 都是常见开源组件,方便二次改造;
- 多语言排版考虑周到:拉丁字距与非拉丁自然间距自动切换,支持中日韩阿泰柬文;
- MIT 协议,可自由修改与自用。
局限与官方/工程口径偏差:
- 地理编码依赖公共 Nominatim,有限流且可能定位错误:同名城市、拼写偏差会落到错误点位,作者建议本地缓存坐标;定位错了海报整张都错。
- 数据质量取决于 OSM 志愿贡献:偏远地区、新城路网可能缺失或不成体系,不同城市出图密度差异大。
- 大半径性能代价明确:README 自陈 dist>20km 下载慢、内存重;预览应把 dpi 从 300 降到 150;
drive网络比all快但丢步行/自行车道。 - 无界面、不 Docker 化:Contributors Guide 明确不收 Web/桌面 UI、暂不 Dockerize,大功能需先在 Discussions/Issue 征询;本地需自备 Python/uv 环境。
- 主题 JSON 只覆盖既有图层:加铁路、建筑等新图层必须改 Python 代码并给主题 JSON 加回退字段。
- ODBL 署名义务:海报右下角自带 ”© OpenStreetMap contributors”,这是 ODbL 许可要求;商用分发时不能去掉署名,也需遵守相同方式共享条款。
- 版权归属两层:脚本 MIT,但底图数据归 OSM 贡献者,二者不可混为一谈。
八、它意味着什么 / 谁该关注
MapToPoster 代表了”开放地理数据 + 轻脚本 + 审美模板”的小工具路线:不做平台、不做服务,把一件具体的装饰需求做到可复现。值得关注:想学习 OSMnx 的 Python/可视化开发者、需要个性化城市海报的个人与礼品场景、以及研究 ODBL 数据二次创作合规边界的作者。上手建议先小半径(如 5–8km)出预览,确认定位与构图后再放大到 300 DPI 正式渲染。