仓库源文站点原文


title: 小心,这饼有毒! subtitle: 饼图的正确打开方式 time: 2017.05.05 15:33:58 layout: post tags:


你是否有这样的困惑?

到底什么时候该用饼图?使用的时候有哪些注意事项?作为最常用的图表类型之一,你真的了解饼图应该怎么用吗?

想写这篇文章很久了,迟迟没有动笔。直到这周第三次和同事争论『南丁格尔图用半径比而非面积比表示数据比是否合适』之后,我觉得实在有必要写下本文。

做可视化的时候,最重要的是什么

<img class="single-img" src="{{ site.loadingImg }}" data-src="{{ site.url }}/img/post/2017-05-05-choosing-chart-types-jiaozi.jpg">

大雾……

做可视化最重要的一定不是帅!

而是明确你想通过可视化的方式讲什么故事——也就是你的论点是什么。

我们说『一图胜千言』,好的图表是应该作为一种论证方式证明你的论点的,如果没有这个『论点』,只是把图表随意地放在那里,那就和你放了一堆没有分析的数据在用户面前一样没用。

既然如此,一个图表是否正确地起到了传达论点的作用,才是最关键的。

面积与半径之争

传统的饼图用角度比表示数据比,因为半径是相同的,所以面积比也是数据比。这一点是符合我们的认知常识的。

『南丁达尔图』是一种用同样角度、但是不同半径的扇形表示数据比例的图,其中扇形的半径比等于数据比,如下图的第一种图所示。但是在这种情况下,扇形的面积比就等于数据比的平方。那么,在不加说明『该图的半径比等于数据比』的情况下,读者究竟会将半径还是面积视为数据比呢?

在写这篇文章之前,我做了一个小问卷,你也可以问一下自己。以下的三个图中,你认为『邮件营销』的数据分别是『直接访问』的多少倍?

<div id="request-pies" style="width: 100%; height: 500px"></div>

很多人做完以后问我正确答案。

但什么是『正确』的答案呢?

这就好比你看完一本书,想要知道自己对某些情节寓意的理解正不正确。所谓『正确』,指的是你所理解的和作者想表达的是一致的(暂时不考虑作者想表达多元寓意的情况),至于你所理解的这件事本身是不是一个真理则无关紧要。举个例子来说,以《西游记》为例,假如一个读者从『三打白骨精』的故事中解读出了『人很容易被表面现象蒙蔽,看不到事情的本质』,而如果作者的确是想表达这个意思,那么这种解读就是『正确』的;至于人是不是真的很容易被蒙骗则跟理解的正确性无关。

对于一个图表而言,作者想表达的意图,是不是真正被读者理解才是重要的;至于作者想表达的本身是不是正确,则不在可视化理论的范围内。本文将从减少读者对图表作者意思的错误解读的角度,探讨在选择图表类型的时候,需要注意的事项。

<div class="split"></div>

其实,『直接访问』和『邮件营销』的数据在上面每个饼图中均为 1:2。而上面的三种饼图的变种,因为不同的视觉映射方式(第一种图将数据映射到半径;第二种图将数据映射到半径和角度;第三将图将数据映射到角度)给读者的理解上带来了困扰。

需要注意的是,如果你在任何一个选项中选择了 2 倍之外的答案,错误都不在于你,而在于作者有意或无意地传递错了信息。

我这里之所以提到『有意』,是因为的确有很多图表,就是出于迷惑读者的目的,被作者刻意传递出偏离真相的意思的。

一个常见的例子是,金融理财产品会显示每日收益率的变化图,但是收益率通常在一周的尺度上变化不大。如果想要夸张地表现某个产品在一周内收益率的提升幅度,一个狡猾而常见的套路就是,把本该从 0 开始的坐标轴,偷偷换成最低的数据值,这样相对而言数据的变化幅度就很明显了。之所以说这是在误导读者,并不是这图本身有逻辑上的错误,而是利用了读者认为『坐标轴肯定是从 0 开始的』这样的心理。

将数据映射到半径或角度本身并没有对错之分,但是如果作者不给出足够的信息说明,因而导致读者理解上产生偏差,这个过错不在于读者或图表库,而只在于作者。

<div class="split"></div>

让我们来看看问卷调查的结果。截止到本文发表前,共收到 202 份回答。

<div id="request-result" style="width: 100%; height: 300px"></div>

顺便说一句,我上面做的是比较好的饼(羡辙卖饼,自卖自顶):

首先,饼图中的类目不应太多,否则信息很分散,不知道作者想表达什么信息。

其次,饼图的颜色不要五颜六色,除了用以区分类目之外,颜色还可以传递更多有效信息。比如上图用绿色表示正确,灰色表示错误,是符合一般对颜色的认知的,并且绿色的类目更醒目,第一眼就能关注到;相反,如果用普通的三种颜色表示三个类目,则读者很难一眼从图中解读出有效信息。

第三,区分出想表明特定意思的类目。比如上图将正确的类目和错误的类目分隔开,读者很容易抓取到关键信息。

那么,这个统计结果说明了什么呢?

从第三种图的结果来看,即使是标准的饼图,也有超过 10% 的读者错误解读了。这一点可能有些出乎意料之外,但其实在饼图中,数据比要通过角度比察觉,的确不如柱状图比较长度来得直观

对于第一种图(南丁格尔图),注意重点不是『60% 的读者解读正确了』,而是『40% 的读者误解了』。想象一下,你做的图表有四成用户理解错了是一件多么可怕的事!

然而更可怕的是,对于同时映射到半径和角度的第二种图,用户简直就完全分不清了。

从统计结果得到的结论

从上面的结果我们可以发现,当数据映射到半径而非面积的时候,会造成面积比不等于数据比,这很可能会引起读者的误会。

因而在设计图表的时候——

读者是弱势群体,他们无法针对带有歧义的图表进行提问,甚至可能大多数情况下,他们都没察觉到这一现象的存在。而利用这种信息不对称性,将图表设计得有歧义,如果不是出于无知,就是太过无耻了。

南丁格尔图的适用场景

虽然南丁格尔图和上面的第三种图(ECharts 特有)比较容易引起读者的误会,但是对于特定的应用场景仍然是有价值的。比如当扇形比较多的时候,用饼图常常会有很散乱的感觉,而用南丁格尔图就有一种整齐的美感。由于扇形比较多的情况下角度较小,形状较接近柱状图,因而引起的误差也较小。在这样的场景下,南丁格尔图不妨为一种好的可视化选择。

所以,不能怪图表库提供这种容易引起歧义的图表类型,而在于作者对于自己创建的图表缺乏必要的认识,导致在实际的场景下使用了错误的图表。这一点,一方面以后我们会在 ECharts 的文档和教程中加以更多的说明,另一方面也需要大家提高对可视化知识的了解。

下面是一个我虚拟了数据的例子,在这个图中,有 24 个扇形,观察每个扇形比例的时候,注意力更容易集中在扇形的半径上。由于半径比也就是数据比,在这样的场景下,南丁格尔图是不错的选择。

<div id="energy-chart" style="width: 100%; height: 400px"></div>

南丁格尔图本身带有一些夸张的效果,作为图表的创建者,应在告知读者正确的阅读方法的情况下谨慎使用。

饼图 vs. 柱状图 vs. 折线图

这三种图仅从风格上看,就是风马牛不相及的。但是,我们倒常常会产生这样的困惑——好像我的这个数据,用饼图也可以,用柱状图、折线图也行。我究竟应该如何选择呢?

很多人是从视觉效果上选择的,比如如果数据比较少,用折线图的话,画面就太空,于是选择了柱状图;看着 ECharts 的饼图挺好看的,那就用饼图吧。这种方式不得不说是比较偷懒的,因为懒得研究用哪种图表比较好,就随便用了一种顺手的。

其实,我们应该从图表类型的隐喻上进行区分

饼图表达的是一个整体局部的关系,也就是一个部分占据整体的多少比例。柱状图和折线图较为接近,通常前者表示不同对象数据的对比,后者更常用作表示同一对象数据在不同(时间)维度上的趋势。当然,这三种都是非常通用的常见图表,因此应用场景的变化也很多,用这样的规律概况可能不尽准确。但仍然重要的是,在你选择了一种图表类型的时候,记得多问一下自己,为什么选了这种图表,而不是另一种

比如,左下图是一个常见的使用饼图的错误场景,是问卷星提供的我上面做的问卷来源的统计。

<figure class="half-img"> <img src="{{ site.loadingImg }}" data-src="{{ site.url }}/img/post/2017-05-05-choosing-chart-types-city-chart.png"> <figcaption>饼图的误用案例</figcaption> </figure> <figure class="half-img"> <img src="{{ site.loadingImg }}" data-src="{{ site.url }}/img/post/2017-05-05-choosing-chart-types-city-bar.png"> <figcaption>使用柱状图比饼图更能清晰地表达意图</figcaption> </figure>

虽然从逻辑上说,这表示来源是各城市的数据量占总体的比例,这一点没有问题。但是,这一图表传递的信息却很杂乱,读者很难抓到重点。而且上文提到过,其实从扇形的角度感知比例是比较困难的。相比之下,右图用柱状图(因为是横着的,也可以成为条形图)就清楚多了(不过这个柱状图的文字和数据对不上,也是存在问题的)。

理论上,上面的图也能用折线图表示,但是会给人以奇怪的暗示,表示数据的变化趋势。折线图更适合用于『在一定时间内,温度的变化情况』这样的场景。

饼图 vs. 环形图

<div id="donut-chart" style="width: 100%; height: 400px"></div>

环形图就是饼图中间挖了个洞。除了可以解肚子饿之困,通常因为中间可以写一些额外的信息而被使用。

不过同样需要小心的是,有可视化理论认为,这样的洞可能影响到读者对于数据比例的认知,所以在选择的时候也需要谨慎。

小结

可视化是一个工具,用来帮助人们更快速直观地理解抽象的数据,它常常是基于约定俗成、甚至不言而喻的共识。因而,当我们说一种可视化方法是『正确』的,并不意味着它像数学上那样严谨地『正确』,而是说,绝大部分人对此不会产生歧义。

从图表创建者的角度,我们希望尽可能地消弭这一误解;而从图表库维护者的角度,我们更希望图表创建者能够深刻地理解这些共识和潜在的歧义,帮助创建者做出更得心应手的图表,也帮助读者领会创建者的良苦用心。

很多时候,武器的强大并不必然带来决斗的胜利。但更多时候,我们之所以产生这样的埋怨,其实是因为对武器缺乏足够的认识,因而难以发挥出绝世好刀的强大功效,甚至反而为其所累。

明白了这一点,大概也就比较能体会,我们在为大家磨练出最强大利器的同时,是多么希望大家对武器本身能有更多了解。

<script type="text/javascript"> var loadJs = [[['{{ site.url }}/js/echarts-all.js'], function() { var chart = echarts.init(document.getElementById('request-pies')); chart.setOption({ color: ['#c23531','#2f4554', '#61a0a8', '#d48265', '#91c7ae'], title: [{ text: '第一种图', left: '25%', top: '55%', textAlign: 'center' }, { text: '第二种图', left: '75%', top: '55%', textAlign: 'center' }, { text: '第三种图', left: '50%', top: '95%', textAlign: 'center' }], series: [{ type: 'pie', radius: '40%', center: ['25%', '30%'], data: [{ value: 100, name: '直接访问' }, { value: 200, name: '邮件营销' }, { value: 300, name: '联盟广告' }, { value: 400, name: '视频广告' }, { value: 500, name: '搜索引擎' }], roseType: 'area' }, { type: 'pie', radius: '40%', center: ['75%', '30%'], data: [{ value: 100, name: '直接访问' }, { value: 200, name: '邮件营销' }, { value: 300, name: '联盟广告' }, { value: 400, name: '视频广告' }, { value: 500, name: '搜索引擎' }], roseType: true }, { type: 'pie', radius: '35%', center: ['50%', '70%'], data: [{ value: 100, name: '直接访问' }, { value: 200, name: '邮件营销' }, { value: 300, name: '联盟广告' }, { value: 400, name: '视频广告' }, { value: 500, name: '搜索引擎' }] }] }); chart = echarts.init(document.getElementById('request-result')); chart.setOption({ color: ['#22C3AA', '#BBB', '#999'], legend: { show: true, data: ['2 倍', '4 倍', '8 倍'], formatter: function (name) { if (name === '2 倍') { return '正确理解图表'; } else if (name === '4 倍') { return ''; } else { return '错误理解图表'; } } }, title: [{ text: '第一种图', left: '16.67%', top: '75%', textAlign: 'center' }, { text: '第二种图', left: '50%', top: '75%', textAlign: 'center' }, { text: '第三种图', left: '83.33%', top: '75%', textAlign: 'center' }], series: [{ type: 'pie', data: [{ value: 126, name: '2 倍', selected: true }, { value: 72, name: '4 倍' }, { value: 4, name: '8 倍' }], radius: '33.3333%', center: ['16.67%', '50%'], label: { normal: { formatter: '{b}:\n{d}%' } } }, { type: 'pie', data: [{ value: 77, name: '2 倍', selected: true }, { value: 46, name: '4 倍' }, { value: 79, name: '8 倍' }], radius: '33.3333%', center: ['50%', '50%'], label: { normal: { formatter: '{b}:\n{d}%' } } }, { type: 'pie', data: [{ value: 166, name: '2 倍', selected: true }, { value: 22, name: '4 倍' }, { value: 1, name: '8 倍' }], radius: '33.3333%', center: ['83.3333%', '50%'], label: { normal: { formatter: '{b}:\n{d}%' } } }] }); var data = []; var labelData = []; for (var i = 0; i < 24; ++i) { data.push({ value: Math.random() * 10 + 10 - Math.abs(i - 12), name: i + ':00' }); labelData.push({ value: 1, name: i + ':00' }); } chart = echarts.init(document.getElementById('energy-chart')); chart.setOption({ title: { text: '基础能量消耗', left: '50%', textAlign: 'center', top: '20%' }, color: ['#22C3AA'], series: [{ type: 'pie', data: data, roseType: 'area', itemStyle: { normal: { color: 'white', borderColor: '#22C3AA' } }, labelLine: { normal: { show: false } }, label: { normal: { show: false } } }, { type: 'pie', data: labelData, radius: ['75%', '100%'], zlevel: -2, itemStyle: { normal: { color: '#22C3AA', borderColor: 'white' } }, label: { normal: { position: 'inside' } } }] }); chart = echarts.init(document.getElementById('donut-chart')); chart.setOption({ title: { text: '环形图的例子', left: 'center', top: 'center' }, series: [{ type: 'pie', data: [{ value: 100, name: '直接访问' }, { value: 200, name: '邮件营销' }, { value: 300, name: '联盟广告' }, { value: 400, name: '视频广告' }, { value: 500, name: '搜索引擎' }], radius: ['40%', '70%'] }] }); }]]; </script>