
做空间分析的人早晚会遇到一个尴尬手里同时有两个变量都想画到一张图里。比如人口密度和老龄化率你想看它们在空间上有没有联动或者犯罪率和服务设施密度想判断是不是真的负相关。以前的办法是出两张单要素地图左右摆着对比但眼睛扫来扫去经常是看了左边忘右边。二元分区着色图就是来解决这个问题的——它把两个变量同时揉进一个面图层的颜色里用四宫格或九宫格的颜色逻辑让你一眼就看出“高-高”“高-低”“低-高”“低-低”在空间上是怎么分布的。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避免之后在渲染器里找不到对应的字段。如果你处理的是NetCDFnc格式的栅格数据也别慌。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等其他方案。多变量可视化最忌讳的就是“一个方法走天下”不同数据、不同问题适合的表达方式是不一样的。多掌握几种手段做分析报告时才有得选。