绘制一个真实的交通等时圈

近日因为导师要求,要做「交通时距」的分析,所以需要根据「真实的交通情景」来绘制从某一点出发到各个位置的时间。换言之,需要绘制真实的交通等时圈(这是规划常见的分析图之一)。
考虑到这篇文章的读者可能是对规划有兴趣的非专业人士,这里首先介绍一下等时圈可以用来干什么,为什么要画这个分析。
等时圈(isochrone),是指以某地点作为中心(行程的起点,origin),以某种出行方式(步行,骑车,公共交通,驾车等),在一定时间内(比如,15 分钟)能够到达的范围。也可以理解为出行时间的等高线(contour)。
它是交通耗时在地理空间上的反映,可以在一定程度上反映了该地区的交通便利程度。一般来说,做等时圈是做周边公服设施可达性分析,类似社区 15 分钟生活圈,看周边有无超市,买菜,吃饭,娱乐……以及可以用于商业选址,规划路网结构,规划公共交通站点,等等。
大三的时候,要给政苑社区做调研分析,我就绘制过该社区出发步行 15 分钟的等时圈。可以看出,这个等时圈实际不是标准的「圆圈」,而是沿着道路伸出畸形触角的图形。可以说,这「畸形」就是等时圈分析的意义所在,因为它比以某个点出发画一个半径(比如 1.5 公里)的圆更加真实地反映了交通路径的实际情况。
尤其是,比如小区边上有一条大河或者一条快速路,大河或马路对面就不那么好过去了。可能直线距离只有 100 米,但为了过去,得花上二十多分钟。
下面,让我来介绍等时图的几种画法。
构建路网计算法:使用网络分析工具手动计算
有一种原始的美,或许很久很久以前,人们就是这么做的。
或可参考这篇文章,我不细致介绍了。
现成法:使用现成网页分析工具
21 世纪 20 年代了,我们坚信总是有好人会写好现成的工具的。确实。城规在这点上是幸运的,还有一些地图厂商以及想赚钱的企业,做了一点工作为我们提供帮助。
首先要感谢 Mapbox 提供 Isochrone API,这是大部分目前在线版工具的基础。上面的等时图就是我使用 微思 Layers ,调用 Mapbox 的 API 做的。
类似的工具我列在此处,希望所有网站都能一直活下去:
- 微思 Layers,教程:一键生成交通等时线圈 (免费有导出图像的点数限制)
- 等时圈交通圈计算工具 - 规划云 (要 VIP。我不喜欢规划云)
- 等时圈-By小旭学长 (免费导出 geojson)
- Isochrone API Playground (源头,免费,不过 playground 只适合测试)
其中,有几个工具也提供了腾讯地图 API 调用或高德地图 API 调用,后者可以做所谓的公共交通出行(公交+地铁)等时圈。(注:事实上,百度地图也提供等时圈 API,但是并不给普通开发者免费使用,需要额外联系。)
是啊,那么简单,只要点一个起点,然后选一选时间和出行方式就好了。五分钟完成出图!
一般的读者(比如城市研究爱好者,对我的杂文感兴趣的小可爱🥰)看到这里已经可以结束了。你已经知道了最重要的概念和做法,已经可以更好地使用工具认识城市了!
但是对于更严苛更严谨、思考更加深刻的人来说……这件事真的这么简单吗?代价呢?
- Mapbox 的路网数据主要来源是 OSM(OpenStreetMap),众所周知,它的路网数据在国内往往并不准确,会有缺失。
- Mapbox 根据路网的不同「等级」(来自 OSM 的道路标注)来生成的所谓的道路通行速度,然而这个速度并不公开,而且也并非实际道路限速。(注:Mapbox 最新的 API 提供了「driving-traffic」的方法,然而它用的交通数据对于国内……好像也不准确。)
- 如果,你做的研究,还想考虑交通拥堵,某个特定时刻的交通状况……那它也无法满足。
总结起来,就是这个交通时间,还是不够「真实」。
可是……怎么得到最真实准确的交通时间呢?难道真的要开车/走路,走一遍吗?
算路法:使用导航提供商的 API 批量算路
你想到,我们在用百度(高德)地图导航的时候,选一个目的地,总会得到一个「预计时间」,诶,这个时间,其实就是相对准确的真实交通时间。尤其是,它真的可以考虑到交通状况、限速、红绿灯……
那么,我就可以在研究区域内选取一堆终点,记录它们的交通时间,最后把 x 分钟的所有点连起来,就能画出等时圈了!
是的,百度地图和高德地图也分别提供了路径规划(用于导航方案)的 API(百度的,高德的),但是他们返回的都是非常完整的导航方案,固然包含交通时间数据,但是有点大材小用。而且这个请求返回耗时久,百度还把它定为高级功能,个人用户也无法使用。
但好消息是,百度提供了这个计算时间的 API:批量算路,根据起点和终点坐标计算路线规划距离和行驶时间。嗯,这本意并不是给我们规划研究者提供的,其实是「适用于高并发场景,如网约车派单、物流配送派单场景,同时发起多个起终点之间的算路,筛选所需要的订单起终点」。当然,既然能用,我们也拿来用。这样可以自动得得到交通时间(而不用手动在导航软件中测试 qwq)。
有了这个 API,虽然不如 Mapbox 方便,但也有很多手段来具体操作。
以下,我使用 Python + arcpy 库(需要 ArcGIS Pro),通过调用百度批量算路 API 的方式,来示范绘制一个真实的等时圈。
提前的 Acknowledgement:
后续大部分代码来源于该文章: 利用 ArcGIS_Python 制作考虑路况的交通等时圈。非常感谢原作者 Renhai实验室。我针对不规则研究区域和大批量终点的多次调用改进重写了代码,增加了一些针对初学者的解释。
提前的准备
- 基本了解 Python,以及虚拟环境、conda、pip 的相关概念;
- Windows 电脑,安装好 ArcGIS Pro;
- 克隆 ArcGIS 的默认 python 环境
arcgispro-py3,并在你的 IDE 和终端中切换到你克隆的新环境。使用这个新环境作为内核激活 notebook (另外,我推荐使用 vscode)。
绘制研究区域
先在 ArcGIS 中绘制面要素和点要素也是可以的,但是要先创建要素啊,编辑绘制啊,比较麻烦,这里出图之前,直接全程使用 python 工具完成编辑和绘制。
首先确定出发点和框定一个研究区域(区域内的所有点作为出行终点)。这一步需要在 notebook 中完成,需要交互式的环境。(或者,先在 ArcGIS 中画好,后续再通过 python 导入。)
1 | # 可能需要先在终端中执行 pip install leafmap |
执行应当会打开一个地图 widget。选取地图左侧的标注工具,使用 Marker 工具,点出出发点;使用 Polyline 工具(矩形工具也行),绘制需要的研究区域。
绘制多边形,而不是一个简单的矩形,是因为我个人需要绘制最远60分钟左右的驾驶等时圈,而这,会产生大量的终点;但是这个百度的 API 是限额 5000 次/天的,为了节省费用,这里预先测试一下大概的等时圈边界,只把研究范围缩减到一个较精确的范围。另外,考虑到后续的研究实际需求,我也删去了钱塘江另一侧的区域。
输出并记录一下 points 点位的坐标和 polygon 所有顶点的坐标。
1 | data = preview_map.draw_control.data |
由于 notebook 重启后所有中间变量数据会丢失,我不想重新绘制研究区域,我会手动记下这个输出。
1 | points = [[120.20979, 30.252714]] # 根据上一个 cell 的实际输出修改 |
确认一下输出是对的。以后再次打开激活 notebook 时,可以从这个 cell 开始运行。
使用 arcpy 库批量生成终点
先在当前的工作文件夹(notebook 或 python 文件所处的文件夹)下新建一个 resource 文件夹。下面的代码中,我们会在里面新建(如果已有,则是打开)一个叫 data.gdb 的 地理数据库文件。
1 | # 导入arcpy |
根据 polygon 的顶点坐标,在 data.gdb 里生成叫做 study_area 的要素。
1 | # 把 polygon 转化为 arcgis 的几何对象 |
下一步生成渔网。为了让终点覆盖到最靠近研究范围边界的地方,生成渔网时,范围要比研究范围稍微大些。
1 | # 计算多边形的边界框 |
下面的 cell_width 会控制渔网的大小,也就是改变生成终点的数量多少。可以多次修改这个值,将终点的数量调整到合适,满足自己 API 用量的需求。
1 | # 修改间距大小 |
检查一下要素的信息(主要是看数量,如果过多或过少则返回来修改上一个 cell 中的cell_width):
1 | desc = arcpy.Describe(out_label_clip) |
输出应该类似:
1 | 要素类名称: study_area_fishnet_label_clip |
一直到这一步,如果读者对 ArcGIS Pro 的操作更加熟悉,其实也是可以直接在软件中完成的。可以后续再在 python 中读取 out_label_clip,进行下一步 API 的调用。
构造请求 url
百度批量算路 API 存在一些限制,但对于规划的城市研究情景来说,不是很重要。具体可以参考它的开发文档。
在我们的代码中,构造的请求 url 形式如:
1 | url = f'https://api.map.baidu.com/routematrix/v2/{trans_type}? |
其中,trans_type 可选 driving、walking、riding(注:riding 可以在 url 请求参数中进一步区分 riding_type 是自行车还是电动车,但摩托车需要向百度申请权限);tactics 对于驾车情景,是策略选择,具体的说明为:
1 | 10:不走高速; |
百度注明,除 13 外,其他策略的耗时计算都考虑实时路况。也就是说,在一天的早上、中午、晚上不同时间调用 API,由于每次都是按请求时的路况来计算,做出来的等时圈结果也是不一样的。
我们这次试试推荐策略 11,我是在下午 3 点左右运行的代码,此时应当并不会因为早晚高峰改变结果的普适性。
ak 则是你的 access key,可以前往百度地图开放平台的应用管理页面,创建一个应用,得到 ak。代码中不建议明文存储这类访问密钥,我们在工作文件夹下新建一个 .env 文件,写入 baidu_ak = "xxxxxx……(你的ak)",保存。
让 python 读入这个 ak。顺便,定一下我们的交通工具和策略吧。
1 | from dotenv import load_dotenv |
然后,我们根据 out_label_clip 中每个点的坐标,批量构造我们待会儿要请求的 url,把它们保存到字典里:
1 | import urllib.parse |
批量调用 API
我们可以把调用得到的通行时间存进一张表格,这样方便在出错的时候也保留一部分数据,或者,分成好几天来请求百度给我数据。
1 | import asyncio |
输出可能类似
1 | 已完成:0 / 4705 |
你会注意到,oid 的更新并不是按序的。这是因为请求的返回时间并不一致,这并不影响结果。
这段代码是支持当再次调用时,继续从未得到结果的点位开始继续请求的。也就是说,如果你的研究区域比较大,突破了百度一天 5000 次请求的限制,可以分成好几天来运行……(我建议每天在同一个时刻运行)
另外百度可能会发邮件或短信提示你「使用的批量算路服务并发量已接近约定上限」,同时,有些 url 请求结果因此被限制而报错。前者不用理会,后者的话,这段代码结束运行之后,再多运行几次,会对没有得到结果的点位继续请求,最后总会得到完整的、包含所有终点的时间的结果的表格的。
使用请求结果更新 ArcGIS
1 | def update_row(out_feature_class, oid, duration_min): |
绘制等时圈
我们得到的是许许多多个点的时间,然后,我们要进行插值,得到面状的时间分布(好抽象,其实意思是,我们要为没有测量值的点来「预测」值,这个预测是使用周边测量点的已有值来预测的)。
插值的算法还蛮多的,我们就用反距离权重法吧。
1 | Idw_raster = arcpy.sa.Idw( |
我们会得到一张漂亮的栅格。我们把它裁剪到研究区域。
1 | arcpy.management.Clip( |
大功告成!现在,我们可以打开 ArcGIS Pro。找到地理数据库中剪裁后的栅格,把它拖到地图上,然后在符号系统中调整一下不同交通时间段的颜色,就可以看到漂亮的等时图了~
后续,我们就可以在等时圈的基础上做进一步的研究。
结语
大部分规划同学的代码基础真的太弱了……写这篇文章是因为,老师同时让我们好几个师门同学来画真实的等时圈,结果都不知道怎么画,跑来问我。我做了一个分步阐述做法和成果的 PPT,并把我的 notebook 给了他们,然而……最后他们依然画不出来。
当然一部分原因是 ArcGIS 的 arcpy 库太恶心了,并不公开提供(商业软件可以理解),然后 ArcGIS 自己又集成了一套 conda 工具,包管理与调用异常麻烦,和主流 python 世界完全脱轨。
但是最重要的……我想大家找不到手把手的用于规划的分析教程才是主要原因。或者,能找到的都还不够手把手(?)
希望我的文章能教会读者叭。不管是不是专业人士,都能看懂就最好了。如果看完还不会,可以留言或者邮箱联系我😭
参考阅读与参考资料:
觉得本文不错?
本文采用 CC BY-NC-SA 4.0 协议共享,欢迎分享与转载。




