☰
QGIS二元分区着色图从入门到实践:一张图看清两个变量的空间关系
2026/10/2 5:27:55 网站建设 项目流程

做空间分析的人早晚会遇到一个尴尬:手里同时有两个变量,都想画到一张图里。比如人口密度和老龄化率,你想看它们在空间上有没有联动;或者犯罪率和服务设施密度,想判断是不是真的负相关。以前的办法是出两张单要素地图,左右摆着对比,但眼睛扫来扫去,经常是看了左边忘右边。二元分区着色图就是来解决这个问题的——它把两个变量同时揉进一个面图层的颜色里,用四宫格或九宫格的颜色逻辑,让你一眼就看出“高-高”“高-低”“低-高”“低-低”在空间上是怎么分布的。

QGIS里做二元分区着色图不算复杂,但确实有个别地方容易踩坑。我这次用一份城市街道数据完整做了一遍,从数据标准化到插件安装、参数配置、图例修改,再到不装插件的手动方案,全部走通。这篇文章把这些实操细节和我在过程中踩过的坑都整理出来,适合刚接触多变量可视化的新手,也适合想从单变量地图升级的进阶用户直接照着操作。

1. 二元分区着色图:一张地图回答两个问题

1.1 为什么单变量地图不够用

常规的专题地图,一个图层往往只表达一个指标。比如用色阶深浅表示人口密度,颜色越深代表密度越高。这种单变量表达方式本身没有问题,信息清楚、直观,入门门槛也低。可当你需要同时观察两个指标的空间关系时,单变量地图就会让你陷入“脑内叠加”的困境:一会儿看密度图,一会儿看老龄化图,试图在脑子里完成两者的空间匹配。小范围研究倒也罢了,一旦地图区域多、指标差异复杂,大脑很快就罢工了。

二元分区着色图(Bivariate Choropleth Map)的逻辑完全不同。它不是把两个指标分别画两张图,而是在同一张地图上,通过色相和明度的组合,同时编码两个变量。这样做最大的好处是节省了“来回切换地图”的认知成本,让你能直接在空间上定位“哪里两个指标都高”“哪里一高一低”等组合状态,这种信息在单变量地图里很难一眼获取。

我记得第一次在项目汇报里用二元分区着色图时,有个评审老师专门停下来问了一句:“这张图信息量很大,但又不乱,怎么做到的?”那次汇报之后,我开始把这个方法固定纳入自己的分析工具箱。它确实有门槛,但一旦掌握,多变量空间表达会顺手很多。

1.2 二元着色图的核心原理:两个变量如何“合体”

要理解二元分区着色图,先看它的基础模型。最常用的是2×2设计,也就是把每个变量按中位数或分位数分成“高”“低”两类,然后两个变量交叉形成四个组合:

组合变量X变量Y视觉逻辑
高-高高于阈值高于阈值两个色相叠加最深/最饱和
高-低高于阈值低于阈值偏向X的色相
低-高低于阈值高于阈值偏向Y的色相
低-低低于阈值低于阈值最浅/最灰

对应到颜色上,通常的做法是给变量X分配一个色相(比如红色系),给变量Y分配另一个色相(比如蓝色系)。当两个变量都高时,颜色就是红蓝混合后的深色;只有X高,就是偏红;只有Y高,就是偏蓝;两个都低,就是接近无色的浅调。

这里面有一个容易忽略但非常重要的细节:两个变量的阈值切分方式直接影响整张图的格局。用中位数切分,四个组合的要素数量大致均衡,视觉上比较均匀;如果你手动设了一个偏高的阈值,那“高-高”区域就会很少,图面会很“偏色”。实操中我建议优先用分位数或标准差来切分,具体怎么选,后面第2章会展开。

如果数据量大、空间分布复杂,2×2不够用,还可以升级为3×3设计,每个变量分成低、中、高三类,交叉出九个组合。九宫格的信息密度更大,视觉复杂度也指数级上升。第一次接触的话,我不建议一上来就用9类,先玩明白4类再说。

1.3 适用场景与反面案例

二元分区着色图的典型应用场景,我可以举几个自己遇到过的:

  • 社会经济分析:把“人均收入”和“老龄化率”放一起,找出“高收入+深度老龄化”和“低收入+年轻化”这两类极端区域,帮助识别社会资源错配的地方。
  • 公共设施规划:把“人口密度”和“便利店数量”同时展示,能很快发现“人口密度高但设施数量低”的短板区域,这就是服务盲区。
  • 环境监测:某些连续面数据,比如“气温”和“湿度”,可以用二元着色来观察高温高湿和高温低湿的不同空间分布。

反面案例也要说。如果你的两个变量相关性太强,比如变量X和变量Y的皮尔逊相关系数超过0.8,那二元分区着色图会退化成一幅“单色渐变色阶图”,四个组合里基本只出现“双高”和“双低”,另外两个组合的空间几乎空白。这种情况还不如老老实实画单变量地图,或者直接用散点图表达相关性。变量之间的相关性偏弱到中等(|r|在0.3到0.6之间)时,二元分区着色图的信息增益是最大的。

还有一类情况不好用:变量分布极度偏态,比如大多数区域数值接近0,只有极个别异常值拉高均值。如果你直接拿原始值做切分,很容易出现“一个区域深红,其他全白”的尴尬效果。这时得先做标准化或者对数变换,不能硬画。

2. 动手前的数据功课:标准化是成败关键

2.1 字段计算器:把原始数据变成可比较的量

我在做二元分区着色图时,最常被问的问题不是“插件怎么装”,而是“我直接把两个原始字段放进去,为什么出来的图没法看”。答案很简单:原始值的量纲和分布差异太大,直接进渲染器,画出来的图基本不是你要的效果。

比如一个字段是“人均收入”,范围从3000到30000;另一个字段是“老龄化率”,范围只有8到25。渲染器在切分类别时,很可能被收入的绝对数值主导,老龄化率的差异完全被淹没。所以动手画图之前,一定要先对字段做预处理,让两个变量进入“可比较”的状态。

QGIS自带的字段计算器(Field Calculator)就能干这件事。打开属性表,点击那个带“abc”标识的按钮,就可以新建字段了。我一般用表达式生成排名、分级或者标准化后的数值,生成之后作为新字段加入属性表,之后画图都用新字段,而不是原始字段。这样做的好处是数据预处理过程和可视化过程分离,万一参数不对,改起来也方便,不用反复调渲染器。

2.2 三种常用标准化方法及选择逻辑

不同的数据分布应该用不同的标准化方法,这里我把自己常用的几种以及适用场景整理一下:

第一种是分位数排名法(Percentile Rank)。在字段计算器里可以用rank()或者借助percent_rank()之类的函数,把每个要素的数值转换为0到100的排名。这种方法最大的优势是对数据分布不敏感,无论原始数据是正态还是偏态,排名的结果始终均匀分布在0到100之间。用这个值做二元分区着色,四个组合的要素数量会很平均,视觉均衡性好。缺点是损失了原始数值差异的“量感”,你只知道A排第80位、B排第60位,但不知道两者的真实差距有多大。

第二种是极差标准化,公式是(x - min) / (max - min),对应的表达式可以写成("field" - minimum("field")) / (maximum("field") - minimum("field"))。结果在0到1之间,保留了原始数据的相对差距。适合分布比较均匀、没有特别极端离群值的数据。一旦有极端值,这个方法的劣势就很明显:一个极高值会把其他所有值压到很小的区间里,地图几乎变成了“一块黑一块白”。

第三种是Z-score标准化。用(x - mean) / stddev计算,表示每个值偏离均值多少个标准差。它保留的正负信息很有用:0表示平均水平,正值表示高于平均,负值表示低于平均。在二元分区着色图里,如果两个变量都做了Z-score,那四个组合的含义就是“双高(都高于平均水平)”“双低”“X高Y低”“X低Y高”,解释起来非常有意义。

我给个简单的选择建议:想快速看空间格局、不想处理分布问题时用分位数排名;数据比较规整、想要保留量差信息时用极差标准化;要做严格的统计分析、解释“相对平均水平”时用Z-score。另外,我习惯分位数排名作为默认方案,因为它的结果对异常值不敏感,出图稳定。

2.3 字段计算器实操:用排名字段双保险

具体到QGIS字段计算器里的操作,我一般分两步走。先给每个变量单独生成排名字段。假设我有两个原始字段,一个叫pop_density,另一个叫shop_count,我想生成两个新的排名字段:

-- 新增字段: rank_density ( "pop_density" - minimum("pop_density") ) / ( maximum("pop_density") - minimum("pop_density") ) * 100

上面的表达式是极差标准化后乘以100,得到0到100的百分制分数。如果担心离群值影响,可以直接用排名:

-- 新增字段: pct_density array_find(array_agg("pop_density", order_by:="pop_density"), "pop_density") / (count("pop_density") - 1) * 100

这个表达式稍微复杂一点,但含义很清楚:先给所有要素按pop_density排序,再找出当前要素在排序中的位置,除以要素总数减1,乘以100,得到的就是它在所有要素中的百分位排名。第二个字段shop_count同样处理,生成pct_shop。

在字段计算器里操作时,有一些容易卡壳的细节。第一个是字段名要用双引号引起来,字符串值用单引号,这个和很多编程语言的用法有点区分;第二个是minimum()和maximum()这类聚合函数在字段计算器里使用,如果“仅计算选中要素”选项没有勾选,计算范围就是整个图层;如果勾了选中范围,结果会基于选中的部分,这个很容易被忽略。我在刚开始用的时候,就因为忘记取消“选中要素”这个勾,导致生成的字段值全错了,排查了好半天。还有一个经验,生成新字段前,最好给字段起一个明确的名字,比如pct_density、z_shop,避免之后在渲染器里找不到对应的字段。

如果你处理的是NetCDF(nc)格式的栅格数据,也别慌。QGIS可以直接加载*.nc文件,但栅格数据本身没法直接做面状二元着色。你需要先通过“栅格计算器”把需要的变量提取出来,再用“栅格转矢量”工具转成面要素,或者提取到点,然后做空间连接,把数值关联到行政区划面图层上,最后再走标准化的流程。处理nc数据时有个小技巧:加载后如果看不到内容,双击图层打开样式面板,把渲染方式改成单波段假彩色,一般就能看到数据了。

3. QGIS实操:从图层到成图

3.1 第一步:安装Bivariate Legend插件

QGIS原生并没有直接提供“二元分区着色图”的渲染器选项,但插件生态帮了大忙。我用得最顺手的一个插件叫Bivariate Legend,直接在插件管理器里搜索就能安装。安装路径是“插件”→“管理并安装插件”,在搜索框里输入“Bivariate Legend”,找到后点“安装插件”就行。这个插件支持2×2和3×3两种分类数量,也支持按分位数或自定义断点切分数据,还可以自动生成对应的二元图例,非常方便。

安装过程中可能会遇到的一个小坑:如果QGIS版本比较老,插件可能无法正常加载。我的建议是尽量保持QGIS更新到比较新的稳定版。QGIS每个大版本发布后,插件生态会陆续跟进,旧版插件的兼容性确实是个现实问题。如果因为版本问题装不上,可以用第3.4节讲的手动规则式渲染方案,不依赖插件也能完成。

插件装好之后,在图层样式面板里操作。右键你的面图层,选择“属性”,在左侧找到“符号化”,然后在最上方的渲染器下拉菜单里,会多出一个“Bivariate renderer”选项。选中之后,你就能在这个面板里配置两个变量字段了。

3.2 第二步:设置二元渲染参数

这一步是整个流程的核心。我以一份模拟的某市街道数据为例,里面有两个标准化字段:pct_density(人口密度百分位排名)和pct_shop(每万人便利店数量百分位排名)。现在我想同时展示这两个指标的空间关系。

在渲染器下拉菜单里选择“Bivariate renderer”后,面板上会出现两个“变量”分组。每个分组里都可以选择一个字段,我分别选择pct_density和pct_shop。然后设置分类数量,这里有两个选项:2x2和3x3。我建议第一次先选2x2,信息量足够,图例也容易解释。

接下来是断点设置。插件默认会用中位数作为划分高低两类的阈值,这一点很好。如果你希望自己控制阈值,也可以手动输入一个数值。比如我想把人口密度排名的前50%定义为“高密度”,那阈值就保持50;如果只想把前30%定义为“高密度”,就把阈值改成70(因为排名数值越低代表越靠前?这里要小心排名的方向)。实操中我建议先选中位数,做出来看分布,如果偏差很大再手动调整。

颜色设置是这个插件的重头戏。它内置了几套颜色方案,比如橙色和蓝色配对、红色和绿色配对等。我在演示项目里选的是橙蓝搭配,橙色代表人口密度方向,蓝色代表设施数量方向。这样出来的图,双高区域是橙蓝混合后的深褐色,双低区域是淡淡的灰白色,偏橙就是高密度低设施,偏蓝就是低密度高设施。

3.3 第三步:图例修改与出图

渲染器设置好之后,还没完,你需要在打印布局里把图例做好。这里有一处经常踩坑的地方:Bivariate Legend插件虽然能生成二元图例,但如果你直接用QGIS自带的图例项插入布局,出来的可能只是一个“分类色块列表”,而不是一个能对应“变量X+变量Y”的二维图例矩阵。

正确做法是:在打印布局中,点击左侧工具栏的“添加图例”,先随便拖一个图例框进去。然后选中这个图例,在右侧“图例”属性面板里,勾选“更新图例”选项,并找到“Bivariate Legend”相关的图例项更新按钮。插件会自动检测当前图层使用的二元渲染器,并把图例替换成一个标准的二维矩阵图例。这个矩阵图例会清楚展示横向和纵向分别代表哪个变量、每个格子对应的高低组合、以及对应的颜色。

图例位置和大小也有讲究。布局里图层本身的色块很直观,图例矩阵最好放在角落,尺寸不要太大,避免遮挡主体区域。我一般会把图例调整到和地图成比例的大小,再加入指北针和比例尺。标题我通常不写成“XX图”,而是尽量写成一个结论导向的描述,比如“各街道人口密度与商业设施丰富度组合分布”,这样看图的人在第一眼就能抓住图的核心信息。

导出图片时,建议用“布局”→“导出为图像”,分辨率选300 DPI,这样印出来或者放大看都清晰。

3.4 不装插件也能做:规则式渲染方案

有一些环境装不了插件,或者就是想最大程度自己控制一切,那可以用QGIS自带的“规则式渲染”来实现二元分区着色图。虽然没有插件自动图例那么方便,但胜在完全可控、没有任何版本依赖。

做法是:右键图层 → 属性 → 符号化 → 渲染器选择“规则式渲染”。然后手动新建四个规则,每个规则对应一种组合。假设我们已经有了两个百分位排名字段pct_density和pct_shop,四个规则可以这么写:

规则表达式颜色
高密度-高设施"pct_density" >= 50 AND "pct_shop" >= 50深褐色
高密度-低设施"pct_density" >= 50 AND "pct_shop" < 50橙色
低密度-高设施"pct_density" < 50 AND "pct_shop" >= 50蓝色
低密度-低设施"pct_density" < 50 AND "pct_shop" < 50浅灰色

在“规则式渲染”面板里,点击“添加规则”,在“筛选器”框里输入上述表达式,然后在“符号”里设置填充颜色。四个规则都建好之后,图就已经能显示了。比较麻烦的是图例,QGIS自带的图例只能列出四个彩色色块,没法生成二维矩阵。我的解决办法是:在布局里不依赖自动图例,直接用“添加标签”工具手动做一个2×2的颜色格子矩阵,就是在每个格子背后放一个矩形块,旁边用文本标注组合含义。这样虽然费一点时间,但成图最终效果完全可以做到跟插件版一样精美,甚至更个性化。

规则式渲染还有一个小优点:你可以用表达式做更复杂的组合,不只是高/低两档,甚至可以加入第三个条件。比如我只关心那些人口密度排名前50%且设施排名后50%的区域,想给它们单独加一个特殊边框,这在规则式渲染里很容易实现,只需新增一个规则并把它放在最上面,优先级设为最高即可。

4. 常见问题与排查技巧实录

4.1 图例与图层颜色对不上

这个问题我遇到不止一次,尤其是第一次用Bivariate Legend插件时,图例生成出来了,但颜色和图层实际显示完全对不上。排查下来发现,原因是“图例与图层样式没有同步更新”。QGIS的图例项本质上是从图层样式里读取的,如果你在图层样式面板里修改了配色,但图例框没有“更新”,旧的颜色就会残留在图例里。

解决办法比较简单。布局里选中图例,在右侧面板找到“更新图例”按钮,点击之后一般能同步;如果还不行,就把图例删除,重新添加一次。另外,如果你在渲染器面板里换了字段或改了断点,也记得回到布局里重新更新图例。我现在的习惯是:先定稿图层样式,再添加图例,之后不再回头改图层样式,这样能避免九成以上不同步问题。

4.2 多数区域集中在一个颜色,地图像“白板”

这是一个非常典型的问题。你兴致勃勃地设置了两个变量,结果出图后发现,图上几乎全是浅灰色,双高区域只有零星几块,整体看起来像一块什么都没画的白板。出现这种情况,大概率是变量分布偏态或者阈值设置不合理。

比如某个变量的原始数值严重右偏,大部分区域数值都很低,只有极少区域特别高。如果你直接用中位数切分,可能看起来还行,但如果你用了固定阈值(比如原始值的平均值),那绝大多数区域都会被归到“低”组,导致只有极少数双高区域有颜色。解决办法有两个方向:一是改用分位数排名生成的新字段做渲染,把每个变量重新切成均匀分布的0-100排名;二是在渲染器里手动把断点改成较低的分位数,比如第40百分位,确保每个组合有足够多的要素。

我的经验是,如果地图上某个组合几乎不出现,别急着调颜色,先回头检查数据分布和断点。这两个环节不调好,后续无论怎么换颜色都很难挽救。

4.3 双变量颜色太相近,图例看不懂

二元分区着色图最常见的吐槽就是“颜色看不懂”“四种颜色区别太小”。尤其是双高和单变量高的颜色,如果色相没有拉开,读者很容易把深褐色误认为橙色或者蓝色。

颜色方案的选择非常重要。理论上,二元分区着色图应该选用两对不同色相的颜色,比如“橙色 vs 蓝色”或者“红色 vs 青色”,然后双高区域就是它们的混合色。但插件内置的某些配色方案,混合出来的颜色饱和度可能偏低,看起来“脏脏的”。我建议优先选择高对比度、互为补色的配对,并且在选择前用一个土办法验证:先在图层样式里渲染出来,然后把图缩小到桌面背景大小,退后两步看,能不能一眼分清四种颜色。如果分不清,就换一套配色。

还有一个技巧:可以在颜色之外再用“边框”辅助区分。比如在规则式渲染方案里,给“双高”区域加一个较粗的深色边框,其他区域保持无边框或细边框。这样即使色弱读者也能通过边框识别关键区域,算是多一重保障。

4.4 在线底图加载失败的替代方案

文章框架里说到了要加底图,但实操中,很多在线底图源在部分网络环境下加载不稳定,甚至完全不显示。最典型的信任我,一个图层能显示半天加载不出来,很影响出图效率。这里写几个我实测比较稳的方案。

首选使用天地图。作为国内运营的地理信息公共服务平台,天地图的影像底图和矢量底图都有公开的瓦片接口,QGIS里可以通过XYZ Tiles添加。一般情况下只要在天地图官网申请一个免费的开发者密钥,把它填进URL模板里,就能稳定加载。相比部分海外图源,天地图在国内网络环境下加载速度更稳定,用起来省心很多。

如果只是做分析底图、不追求影像细节,OpenStreetMap的标准地图(URL模板为https://tile.openstreetmap.org/{z}/{x}/{y}.png)通常也能用,但偶尔会有访问不稳定的时候。我的建议是:把常用的几套底图URL都存成一个QGIS底图集合,哪个能连就临时切哪个,不要死磕某一个源。出图时如果底图加载不出来,也可以先用纯色或简单的网格背景做底,最后成图时再叠底图,互不影响。

4.5 其他零碎问题:字段类型、空值、图层顺序

除了上面几个高频问题,还有一些零碎但同样影响体验的细节。

字段类型不匹配是常见的渲染“暴雷点”。如果你的字段是文本型,但里面存的是数字,渲染器在做大小比较时会出错,或者白屏。看属性表时注意字段类型那一列,如果是字符串(text)而不是整数(integer)或实数(double),就用字段计算器新建一个类型转换的数值字段。表达式很简单,比如to_real("field")就能把文本型数字转成数值型。

空值(NULL)处理也值得提前留意。如果某个字段有大量空值,这些要素在渲染时通常不会参与分类,地图上就会“缺一块”。我的处理办法是在标准化阶段就把空值过滤掉,或者用一个特殊值填充,比如0,但填充0之前要想清楚它是否会影响分位数。最好还是在数据清洗阶段把空值处理掉,不要拖到渲染阶段才面对。

图层顺序问题主要出现在你叠加了多个图层的场景。二元分区着色的面图层应该放在底图之上、标注点之下。如果你把它放到最底下,底图其他图层会把它盖住,那自然什么都看不见。右键图层,在“图层顺序”面板里拖动图层位置就能调整。

5. 最后的几个实操心得

做二元分区着色图做得多了,我慢慢发现一个规律:真正决定这张图好不好看的,往往不是插件或者渲染器,而是画图之前的数据处理和画图之后的图例表达。插件能做出的图,手动规则式渲染几乎也都能复刻;数据处理不到位,哪怕插件再高级也救不回来。所以我建议所有想做这个图的朋友,把时间重点放在字段标准化上,而不是纠结装哪个插件。

另一个体会是:颜色选择一定要考虑到读者,不光是色盲色弱,还有打印灰度的问题。如果这篇图最终要打成黑白报告,那靠颜色区分的二元分区着色图基本失效,这时候不如直接回到单变量地图,或者用点密度图等其他方案。如果只是在屏幕上看,那就选择高区分度的配色,并且尽量在一张图里保留足够多的空间参考信息,比如行政区划边界和主要道路,帮助读者快速定位。

还有一个小技巧想分享:每次我做完一张二元分区着色图,会专门用截图工具把图缩得很小再截一张,看看缩略图状态下能不能看出空间格局。如果缩略图依然清楚,说明图的信息层级是成立的;如果缩略图糊成一团,那放大之后大概率也不会好到哪里去。这个习惯帮我解决了不少“自己看着清晰、别人打开就懵”的问题。

最后多说一句,QGIS里做这类多变量可视化,其实路径不止一种。我这次详细写的二元分区着色图只是其中之一,后面如果你感兴趣,还可以试试气泡地图、双轴图表联动或者小倍数地图(small multiples)等其他方案。多变量可视化最忌讳的就是“一个方法走天下”,不同数据、不同问题,适合的表达方式是不一样的。多掌握几种手段,做分析报告时才有得选。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询