做城市公园分析这件事,不少人都被困在第一步——数据从哪来。官方开放数据覆盖的城市有限,手动勾绘又费时费力。我前阵子接手一个城市公园可达性评估的活儿,最终用QGIS配合百度地图AOI数据,把一条从数据获取到分析出图的完整链路跑通了。这套方案其实是绕开各种数据框框最接地气的一条路:只要百度地图里能搜到的公园,就能抓下来作为面状边界,再用QGIS做缓冲区、覆盖率、出图,全程不碰商业化GIS平台。适合规划从业者、GIS学生、做城市研究的朋友参考。
1. 项目思路与方案设计
1.1 公园分析最头疼的问题:数据从哪来
做城市公园空间分析,第一步永远是数据。如果单位没有采购商业地理数据库,获取公园面状数据通常只有三条路:从官方开放平台下载、在遥感影像上手动勾绘、从在线地图抓取。
官方数据的问题在于覆盖不全,很多城市连基础绿地数据都没公开,或者只有分类粗到没法用的"绿地"图层。手动勾绘则是在熬时间:一个中等城市两三百个公园,对着影像来回描边,画完基本到凌晨。而且勾绘结果往往缺字段,没有公园名称、没有面积、没有类型,后续做标注和统计时非常被动。
百度地图AOI数据在这时候就显出价值了。AOI全称Area of Interest,兴趣面,是地图平台在地图数据中维护的实体区域,不只是经纬度点,而是一个真实边界。公园、小区、学校、商场都有AOI。百度地图AOI覆盖面广,全国县城级别以上城市都有数据,属性里带名称、分类、地址、面积等字段,更新时间比大多数公开发布的数据都快。缺点是坐标系是百度自己的BD09,没法直接吃。
1.2 为什么选QGIS而不是ArcGIS或在线平台
项目选型时我也纠结过:ArcGIS的功能成熟,但有授权成本;在线分析平台比如百度慧眼、极海,确实简单,可往往不给数据导出权限,或者要企业版付费,做研究写论文时数据可追溯性也说不清。
最后选QGIS,核心原因是三点。一是免费开源,学生和预算有限的团队都能用。二是插件生态丰富,尤其是国内地图数据接入这块,社区里有现成工具可用。三是Python控制台很强大,遇到插件覆盖不了的需求,几十行脚本就能自己搞定,而这套能力在大型商业平台上往往被打包成付费模块。
当然QGIS也有学习曲线,它的一些窗口布局和操作逻辑和ArcGIS差异较大,刚上手会有点别扭。但熟悉之后,你会发现它做空间分析和制图完全扛得住。至少在这个公园分析项目里,QGIS从始至终没让我换回ArcGIS。
1.3 整体技术流程拆解
整个项目的流程可以分成四个阶段。
第一段是数据获取:申请百度地图开放平台开发者密钥,通过地点检索接口把目标城市所有公园POI和AOI信息拉回来,再用Python脚本把JSON数据转成带坐标的GeoJSON文件。
第二段是数据预处理:关键操作用脚本或其他工具做坐标偏移校正,把BD09坐标转成CGCS2000或WGS84;然后在QGIS里清洗字段,删掉重复数据,剔除面积过小的"口袋公园干扰项",统一字段类型。
第三段是空间分析:叠加行政区划边界,做公园分布核密度分析;用缓冲区和网络分析评估服务半径覆盖;有可能的话再叠加人口栅格数据计算受影响人群比例。
第四段是制图出图:把分析结果按专题图标准排版,套用地形底图,输出300dpi的PNG或PDF,直接能用于汇报或论文配图。
这套流程每一步都有坑,尤其是坐标转换和AOI抓取这两个环节,后续我会展开讲细节。
2. 环境准备与工具链搭建
2.1 QGIS版本怎么选,安装时要注意什么
QGIS目前主推两个稳定版线:长期支持版(LTR)和最新版。建议直接装长期支持版,比如3.34系列。LTR版本的好处是核心功能和插件兼容性都经过了长时间的稳定性验证,社区里讨论的问题大多基于这个版本,搜索报错更容易命中答案。最新版虽然新功能多,但个别插件还不兼容,项目期间来回折腾很耽误事。
安装细节上,Windows用户建议用OSGeo4W网络安装器,而不是下载独立安装包。OSGeo4W的好处是能统一管理QGIS及其依赖库的更新,后续如果要用GRASS、SAGA等外部分析工具,也方便一并装。Python环境也建议用OSGeo4W内置的版本,不要自己另装Python,不然QGIS里跑脚本时经常出现库冲突。
如果你在Linux或macOS上跑,直接装发行版对应包管理器里的版本就行。团队内多人协作时,尽量统一QGIS版本和插件版本,否则同一个项目文件在不同机器上打开,图层样式很容易乱。
2.2 必装插件清单与配置
这个项目我装了四个插件,可以说缺一不可。
QuickMapServices,用来加载在线底图。出图时没有底图做参考,分析结果就像悬在空中。装好之后建议在Settings里把贡献服务器加上,这样能多出Esri等图源,图源在国内访问速度也相对稳定。
QNEAT3是基于矢量路网做网络分析的插件,算服务区、等时圈比QGIS自带的网络分析模块顺手得多。公园可达性分析主要靠它。
Group Stats用于快速统计分组汇总数据,比如按行政区统计公园面积、按类型统计公园数量,几秒钟出结果,省去很多字段运算操作。
还有一个社区里的AOI下载相关工具,具体名称每个版本不一样,网上搜索"QGIS 百度 AOI 插件"就能找到。它的作用是直接在QGIS面板里输入城市名,自动抓取百度地图对应区域的AOI面数据。不过这类社区插件的稳定性参差不齐,我更推荐自己用Python调API抓数据,后面细说。
2.3 项目坐标系:从开头就设置成CGCS2000
项目开工前,务必先把QGIS工程的坐标系设为CGCS2000。具体操作是Project菜单下Properties,在CRS选项卡里勾选"Enable 'on the fly' CRS transformation",然后搜索EPSG:4490选中。CGCS2000是国家大地坐标系,与WGS84在精度允许范围内基本等效,做国内项目写报告、投论文都认这个基准。
这里有个容易犯迷糊的点:EPSG:4490是地理坐标系,单位是度,计算距离和面积必须先投影。常用做法是在工程设置里保留EPSG:4490做显示,但对图层做投影变换到CGCS2000分带投影,比如3度带EPSG:4547之类按城市经度选择;也可以用墨卡托通用投影,看项目需求。投影选择不对,后面算面积和缓冲区都会出大问题,这个坑我栽过,提醒大家注意。
3. 百度地图AOI数据获取实战
3.1 AOI到底是什么,为什么比POI好用
先搞清楚概念。POI是兴趣点,地图上那个红色图钉,本质是一个点坐标,附上名称、地址、分类这些属性,没有边界。AOI则是点对应的那块"面",比如一个公园,POI告诉你入口在哪儿,AOI告诉你整个公园范围有多大。
做公园分析,边界就是生命线。有了准确的AOI边界,才能计算公园真实面积、判断它是否与居住区相邻、分析它的轮廓形状。只用POI点做分析,误差会大到不可接受:一个占地几十公顷的郊野公园,在点分析里可能被当成一个路口大小的存在,结果是完全失真。
百度地图AOI的属性信息也比较完整,通常包括名称、地址、分类、评分、人均消费等字段。其中分类字段对公园分析很有用,可以筛出"公园""植物园""动物园"等细类,也可以把"广场"排除在外,避免混入非公园的开放空间。
3.2 申请百度地图开放平台密钥
获取AOI数据的第一步是去百度地图开放平台申请开发者密钥,这一步没有技术难度但容易被卡住,因为现在平台需要实名认证。
流程大致是:注册百度账号,进入百度地图开放平台控制台,创建应用。应用类型选择"服务端"或"浏览器端"都可以,因为我直接用HTTP请求拉数据,选服务端更合适。提交后拿到一串英文数字混合的AK,这就是后面所有API请求的凭证。
需要注意配额限制。免费版的"地点检索"接口,普通应用每天的配额一般有几百到几千次,对拉取一个城市的公园AOI来说完全够用。但如果你的城市特别大,公园数量特别多,可能需要规划好请求次数。遇到配额异常报错也别慌,控制台能看到配额使用情况。
3.3 用Python脚本批量拉取公园AOI数据
拿到AK之后,用Python脚本调百度地图地点检索接口来拉取数据。接口URL长这样:
https://api.map.baidu.com/place/v2/search?query=公园®ion=北京市&output=json&ak=你的AK&page_size=20&page_num=0核心参数是query(关键词)、region(城市名)、page_size和page_num(分页)。有一个关键限制:单次请求最多返回20条记录,所以必须翻页拉取,而百度对翻页上限有硬性限制,一般page_num到20左右就不再返回更后面的结果了。
这意味着如果一个城市的公园超过400个,直接接口可能拉不全。解决方法是按行政区拆开请求,比如把城市按区县分别搜索,或者用bounds参数按矩形框分区域搜索。我这次跑某个地级市,就是用区县分片的方式拼齐了全部公园数据。
实际脚本流程不复杂:requests发GET请求、解析JSON、循环翻页、把结果存到列表里。有个细节值得注意:返回的JSON里,location字段是百度坐标(BD09)的经纬度,不是我们最后要用的坐标,转存时要单独记录。
抓完所有公园数据后,把结果保存成GeoJSON。如果用的是API返回的POI点,可以按名称和地址去重后保存为点图层;如果用的是AOI抓取工具,那得到的就是面图层,字段里会带一个面积值。
3.4 把数据导入QGIS的两种方式
第一种方式,直接在QGIS菜单Layer,Add Layer,Add Vector Layer,选择生成的GeoJSON文件。导入后QGIS会自动识别几何类型和字段,应该是点或面对应展开。
第二种方式,用QGIS的Python控制台。打开Plugins菜单下的Python Console,跑一段脚本,把刚才抓取的数据直接处理成QGIS内存图层。这种方式的好处是可以在导入的同时完成坐标转换、字段补充这些操作,一步到位。对后续要反复试参数的情况尤其方便。
无论用哪种方式,导入后第一件事就是打开属性表检查:名称字段是否完整、是否有空白值、面积字段是否可读。有问题就在这个阶段解决,别拖到分析时再返工。
4. 数据清洗与预处理:最容易被低估的环节
4.1 坐标偏移校正:BD09到CGCS2000
所有百度系的坐标数据,最基本的特点就是经过了两层偏移:BD09是基于GCJ02再加一次偏移,GCJ02是国测局加密的坐标系统。直接拿BD09的数据和WGS84/CGCS2000底图叠,会发现所有要素整体偏移几百米甚至更远,这在城市尺度下直接不可用。
网上有两种说法,一种说QGIS自带坐标转换能处理,实际效果很有限,因为BD09和WGS84之间存在的是非线性偏移。另一种说法是找个在线转换工具挨个转,数据量大的时候能烦死。
专业做法是在Python里做整体转换。现在社区里有一些开源转换库挺成熟的,比如gcoord,一行代码就能把BD09坐标系转成WGS84:
import gcoord # 从BD09转到WGS84 transformed = gcoord.transform(gcoord.BD09, gcoord.WGS84, lng, lat)转换完坐标之后,在QGIS里将其另存为Shapefile或GeoPackage,导出时选择目标坐标系为EPSG:4490。这样图层在工程里就和其它WGS84/CGCS2000数据对齐了。
一个容易被忽略的精度问题:gcoord这类库的转换精度通常是米级,做宏观城市分析够用,但如果要精确计算某个公园出入口坐标,还是要去现场打点校准。你做的分析尺度决定了你所能接受的容差。
4.2 字段处理与面积计算
数据进QGIS之后,第一件事是检查字段。AOI数据里经常出现同名公园重复出现的现象,比如搜索"公园"时同时返回了"某某公园"和"某某公园(东门)"。属性表里按名称排序,人工扫一遍能发现很多低级问题。
去重可以分两步走:先在属性表里按名称字段做一次聚合统计,找出完全重名的记录;再用空间位置检查,删除距离极近(比如几十米内)且名称高度相似的记录。
面积计算建议用字段计算器,新建一个area_ha字段,公式里用transform操作把几何投影到合适的分带投影后再算面积。务必记住:在EPSG:4490这种地理坐标系下直接用$area,QGIS会用椭球体算法算真实面积,这个结果是可用的;但如果你用投影坐标系的长度单位去求面积,就要注意投影带来的变形。
公园AOI的面积字段是从百度抓下来的官方值,但它和实际投影计算出的面积可能有一定偏差,偏差来源是地图平台数据本身的轮廓精度。我建议最后统计用QGIS计算值,原始area字段只作为校验参考。
4.3 边界质量检查与修复
AOI数据来自在线地图,边界质量参差不齐。需要检查的问题有几类:一是图形自相交,多边形自身边界交叉。二是节点过于密集,边界呈锯齿状。三是共边问题,比如两个相邻公园边界重叠或留缝。
检查工具在QGIS里不算核心功能,但可以用Vector Geometry多边形的Check Validity工具。找到问题要素后,用Voronoi多边形或Simplify工具修复,也可以直接数据覆盖重绘。
实际工作中我还碰到过一种情况:AOI边界和遥感影像上肉眼可见的公园边界差异较大。这一般是地图平台数据更新滞后或者自动勾绘精度不佳。如果做精细到单公园的研究,建议对重点公园手动修正边界,不要盲信平台数据。
5. 分析与可视化:公园空间格局怎么呈现
5.1 公园分布核密度分析
拿到清洗后的公园AOI数据,第一张能拿得出手的图是公园分布核密度图。它能直观反映城市里公园资源的集中和空白区域。
在QGIS里打开Processing Toolbox,搜索Kernel Density Estimation工具。输入图层选公园面要素,输入参数里注意Population field选一个合适的字段,比如按公园面积作为权重,这样大公园对周围的影响应该大于小公园。半径可以用1000米到2000米,这个参数决定了结果平滑程度,多试几次找到既不过度平滑也不细碎的值。
输出的栅格会有一个像"温度图"的色带,红色代表高密度区。把Alpha通道调低,叠加到底图上,能非常直观地看出公园密集区和资源盲区。这步做出来,听汇报的人一般都会觉得项目有深度。
5.2 服务半径与缓冲区分析
做服务半径评估,通常用缓冲区叠加来判断多大范围的城市居民能享受到公园服务。缓冲区的选择有讲究:中国《城市绿地分类标准》对社区公园和综合公园的服务半径有建议值,大致在500米到1500米,加上日常步行15分钟约为1000米的舒适距离。
在QGIS里用Vector Geometry中的Buffer工具,输入公园图层,距离填1000,勾选Dissolve Result将重叠区域的缓冲区合并。输出后的合并缓冲区图层,和居住用地图层做重叠查询,就能统计出有多少居住区在公园服务范围内,再除以总居住区面积,得到覆盖率。
这个指标能用来横向对比不同城市、不同片区的公园服务公平性。多算几组不同半径的覆盖结果,还能做距离衰减分析,说明公园服务随着距离增加而减少的规律。
5.3 基于路网的可达性分析
缓冲区分析有一个硬伤:它假设人是直线飞过去的,没考虑路网。真实出行要拐弯,要穿过天桥、过街设施,实际到达时间跟直线距离差很多。所以更严谨的做法是基于路网分析。
在QGIS中,用QNEAT3插件的Service Area功能,输入路网和公园入口点。为了让分析更贴近真实,应该在OSM或当地路网数据里选取公园周边的道路特征点,但一般做法是把公园AOI质心作为出发原点,简化处理。
设置断离距离(如1500米)或断离时间(如15分钟步行,以步行速度5公里每小时换算),运行后得到沿路网的可达范围。这个结果和缓冲区叠加在一起,能看出实际覆盖的差异,哪个区域看似在1000米直线范围内但实际绕路太多,一目了然。
这类分析结果对规划决策很有说服力。这也是为什么一个单位采购的网络数据集通常很贵——数据的价值在这时就体现出来了。
5.4 叠加人口数据做精准人群覆盖
公园服务评价的最后一步,是看它覆盖了多少人。这一步需要人口栅格数据,可以使用WorldPop或者国内的人口分布栅格。
QGIS里用Raster工具集中的Zonal Statistics工具,以缓冲区或等时圈范围作为overlay图层,统计栅格的像元值总和。因为在预先准备的数据中,每个栅格像元代表该位置的人口数,所以总和就是服务范围内的估算人口总量。
再以总人口做分母,得到服务覆盖人口的百分比。这个指标比几何覆盖率更有社会意义,也更能体现项目价值。我之前做的一个街道尺度分析,按人口加权后的覆盖率比几何覆盖率低了近20%,说明很多公园分布在人口稀疏区,服务效率不高,这类洞察就是分析的价值所在。
6. 制图出图:把成果做成能交付的专题图
6.1 底图与图层符号化
出图前先保证底图正常。QuickMapServices加载的底图作为背景,但注意底图通常是Web墨卡托投影,和你的CGCS2000数据空间参考可能不一致。最佳实践是先在Properties里为底图图层设置“渲染相关投影”,或者在打印布局中统一输出CRS。
公园面要素建议直接采用分层设色,按公园分类填充不同颜色。比如综合公园用绿色系、社区公园用浅绿、专类公园用青色。不要只用一个颜色,那样看不出等级差异。面色透明度调至70%左右,方便底图信息透出来。
如果需要标注公园名称,在Layer Properties的Labels里开启,字体大小控制在8pt左右,用白色描边+深色正文字,保证底图再花哨文字也清晰可辨。
6.2 打印布局设置与出图规范
QGIS主界面的New Print Layout就是打印布局编辑器。我习惯按A3横向设置图幅,分辨率默认渲染为300dpi。这样导出的PNG足够清晰,可以直接放进论文或汇报PPT。
布局内容核心元素有:主图、图例、指北针、比例尺、标题、数据来源说明。比例尺一定用双单位,公制显示为千米或米,方便读者直接量算。图例要注意精简,只保留核心图层,别把底图每个类目都列出来。
坐标格网值得花时间设置:打开Map Item Properties的Grids,选择建立经纬网或方里网,标注间隔根据城市尺度选择,比如0.01度或1公里。有格网辅助,读图的人能快速定位和估算距离。
6.3 导出与常见输出问题
布局里一切就绪,Export as Image选择PNG,分辨率300dpi,颜色模式选RGB,尺寸按A3比例。导出前一定要先Preview刷新一遍,我用Print Layout多年,最大的教训就是忘记刷新导致输出内容缺失。有时图层缺失是因为打印机兼容性,但更多时候是缓存没刷新。
除此之外,Qs管项目文件里的样式在导出后全部正常,但换电脑打开却崩了。这类问题常见于字体和SVG符号的绝对路径引用,建议把项目文件夹里附带的资源文件统一放在相对路径下,而不是散落在根目录,避免后续交付给同事时出现样式丢失。
7. 常见问题与排查技巧实录
7.1 坐标偏移问题
- 症状:公园AOI和影像底图边缘重叠,偏差几百米以上。
- 原因:没做BD09到WGS84/CGCS2000的偏移转换,直接把百度坐标当成标准坐标用了。
- 解决:用gcoord之类库做整体转换再导入QGIS。注意转换要一次性到位,导入后再用与Reproject Layer转换无法消除偏移。
- 防范:写脚本时统一封装坐标转换函数,并在导入后叠加影像底图做目检。
7.2 插件装不上或功能异常
- 症状:插件管理器里搜不到目标插件,或安装成功但工具消失。
- 原因:插件库访问不稳定、QGIS版本不兼容、插件相互冲突。
- 解决:先确认QGIS版本,再到插件官网下载zip包手动安装。如果仍然不可用,检查Python控制台报错,在开发者引导下可以定位到插件源码的问题。
- 防范:生产环境优先用LTR版QGIS,新版上线前先在测试工程里验证所有插件可用。
7.3 百度API请求失败或配额不足
- 症状:requests返回错误码401或403,或搜索结果明显少一截。
- 原因:AK配置错误、请求参数格式不对、当日配额耗尽、IP不在白名单。
- 解决:单独在浏览器里跑一遍接口URL,看返回内容。确认query的编码是URL编码,AK拼写无误。实时查看控制台配额,必要时临时申请提高配额。
- 防范:脚本加重试机制和延时,控制请求频率,避免并发太猛被限流。
7.4 底图图层显示不全或加载慢
- 症状:QuickMapServices底图出现灰色瓦片或加载不出。
- 原因:网络环境对某些瓦片服务器不稳定,或底图服务本身做了限制。
- 解决:多备几个底图源,比如在QuickMapServices中加载Esri底图、OpenStreetMap和Esri影像,按需切换。也可以通过自定义URL接入国内可用的瓦片源,网上有现成的QGIS底图URL配置模板。
- 防范:出图前至少提前半天把底图瓦片缓存到本地,避免演示/汇报当天由于网络问题翻车。
8. 最后的实操心得
这套流程前后我跑了两个项目,最大的感受是:数据预处理的时间至少占整个项目的一半以上,而这部分恰恰是网上教程最容易略过的。AOI数据拿下来简单,但要让数据真正可用于分析,需要你对坐标系统、属性语义、空间精度都有清晰的判断。
有几个细节回头看尤其值得强调。第一,坐标转换不要拖到QGIS里再做,是在抓取阶段就应该完成;第二,AOI属性里的面积只能当参考,最终面积一定要用投影后的几何计算结果;第三,别迷信任何单一数据源,有条件就用影像或实地核查抽检几个关键公园的边界。
后续扩展方向也不少。你可以把AOI抓取的范围从公园扩展到学校、医院、商业中心,做成城市公共服务设施分布系列图;也可以把核密度、缓冲区和人口覆盖组合成一套可复用的分析模板,下次换城市只需要改参数就能跑。这套基于QGIS加在线地图数据的组合拳,在数据获取难度越来越大的今天,反而成了一种务实的选择。