R Statistical Graphics: Base Graphics, lattice, and ggplot2
我们希望在作图的函数开始之前,聊一聊我们应该怎么作图,也就是作图的原则。
完整的图库部分我们迁移到 R Visualization中进行介绍,从而降低阅读的负担。
经典图形
统计图形的意义在于引导我们观察到统计数据中的信息。用著名统计学家 John Tukey 的话来讲,就是“图形的最大价值就是使我们注意到我们从来没有料到过的信息”(The greatest value of a picture is when it forces us to notice what we never expected to see)。从这个意义上讲,统计图形的重要性自然不言而喻。
在统计图形历史上,能够达到“揭示人们不曾料到的信息”这种高度的图形并不多,这里我们首先来看看那些在统计作图历史中留下了自己身影的图形
饼图与线图的起源
饼图和线图都是使用历史非常悠久的统计图形 他们都由Playfair发明;虽然他们在现在看起来并不稀奇 但是这已经是近300年前的产物了
这幅图主要展示了 1700 年至 1780 年间英格兰的进出口时序数据,左边表明了对外贸易对英格兰不利,而随着时间发展,大约 1752 年后,对外贸易逐渐变得有利
上方的大图展示了各个国家的领土面积(和圆圈成比例)以及人口(左垂线)、税收(右垂线)、国土在各大洲分布比例等数据,两条垂线连线的斜率可表示税负的轻重
霍乱传染问题
John Snow发现死亡发生的地点有明显的地理规律 如下图所示 最后综合一些调查最终确定了霍乱的根源是一个水井

玫瑰图
南丁格尔是历史上使用极坐标面积图的先驱。这种图形外形如玫瑰,因此后来也称之为玫瑰图,其主要构思是用“花瓣”的面积表示统计数值的大小
玫瑰图不仅清楚展示了这两年军队死亡人数的变化,而且更重要的是,她将每个月中三种死亡情况也分别用不同颜色标记出来:蓝色表示死于可预防的疾病、红色表示死于战争伤害、黑色表示死于其它原因。这样我们可以清楚知道军队伤亡原因的结构,尤其是“绝大多数士兵死于可预防的疾病”(图中最高的花瓣)。凭借这一条重要信息,她让英国政府意识到,真正影响战争伤亡的并非战争本身,而是由于军队缺乏有效的医疗护理!

拿破仑的俄罗斯远征
Minard 绘制的地图,展现了 1812 年拿破仑的大军团进军俄国的路线(上半部分)和撤退时的气温变化(下半部分)。这一历史事件中,法军数量的急剧减少以及恶劣的气候条件一览无遗
它包括了下面的信息
- 军队的位置和前进方向,以及一路上军队的分支和汇合情况
- 士兵数目的减少 使用线条的粗细表示
- 撤退时的气温变化 参见图的下半部分

小结与开始
前面四个小节中的每一幅统计图形都诞生在计算机诞生之前 全部是作者手工绘制而成的;但是不妨碍他们都有着重大的价值。
当然统计图形领域还有大批卓有成就的研究者,为统计图形的发展做出了不少贡献;这里进行简单的介绍
比较有名的有数据达芬奇” Tufte 他的研究成果数据墨水比(Data-Ink Ratio) 以及 最小化图表垃圾(Minimizing Chartjunk) 要求我们创建简洁有效的图,他的很多著作都值得我们再看一看
统计图形真正迈入主流学界依赖于 John. W. Tukey 他提出的探索性数据分析技术探索性数据分析 引领了一个统计学的新方向,在数理统计为主导的统计界注入了一股新活力,探索性数据分析的主要工具就是统计图形
为了让统计图形更加有理论化的解释 Wilkinson 给出了一个很好的框架,这是 ggplot 诞生的基础
贝尔实验室的的 Cleveland 在图形认知方面做了不少工作 他可能是最早研究统计图形对读者心理感知的影响的统计学家之一
M. Friendly and Denis 整理、记载了自 17 世纪以前至今数百年历史中较有影响力的统计图形 是研究统计图形历史的一份很好的资料
近代统计图形以 John. W. Tukey 的探索性数据分析为里程碑式的起点,诞生了大批具有数理统计意义和计算机应用的图形著作和图形种类 我们所使用的箱线图 直方图和密度曲线 都是在此后提出的
现代统计图形的发展则更偏重计算机工具的开发以及高维图形和动态图形的展示 高维图形的一个经典是打破笛卡尔坐标系常规的平行坐标图;至于动态图形软件我们则会留在本书的最后来解释
传统的统计分析大约可以分为三类:
- 描述性统计分析:Descriptive Statistical Analysis
- 推断性统计分析:Inferential Statistical Analysis
- 探索性统计分析:Exploratory Statistical Analysis
前者都是基于一些统计模型,统计方法来构建的,只有探索性数据分析更多的以图形为基础,而要使用这种手段,则必须清楚了解如何制图以及现有图形有哪些种类,这样才能真正开发出统计图形的价值。
“图形统计分析”也不是一个新概念,平常的统计图示已经或多或少用到了这样的思想,只是我们往往更倾向于数理意义上的统计模型分析,而不会把图形统计分析作为主要分析手段。当然,由于图形的表达限制以及统计图形的普及程度,也使得它不可能替代模型分析
特别的 数据解读存在主观性(数据说话本质上是人在解读) 过度依赖数据可能会让我们忽视掉一些重要的信息(数据目前来看还无法完全取代专业的解读)
在图库之前
工具
我们对统计工具提出下面的三点要求
- 统计计算功能齐全
- 统计元素易于控制
- 图形类型丰富多样
图形的首要作用的确是直观展示信息,然而这里的信息未必是简单的。一幅优秀的统计图形背后也许隐藏着重要的统计量,而统计量是统计图形的最关键构成因素。
Excel是最常见的统计图形工具 但是 Excel 的图形总体看来只有三种,
- 第一种是表现绝对数值大小,如条形图、柱形图、折线图等,
- 第二种是表现比例,如饼图,
- 第三种则是表示二维平面上的变量关系,如 X-Y 散点图;
- 从更广泛的意义上来说,Excel 展示的几乎都是原始数据,基于数据的统计推断的意味比较淡薄。
Excel现在提供了数据透视表的功能,他本质上就是一种交互式的图形界面,把三种基础的图形放在了一起,并且提供一种固定的格式来展示,还是对原始数据的展示 论 Excel 的图形如何搭配色彩、怎样变得立体化,都跳不出上面三种类型的限制,而且不能全面妥善表达统计学的要义
统计图形会直观,但不一定是简单的,更不是没有推断意义的,更不应该是对原始数据的堆叠
统计学不是是研究数据该如何展示的 他们的核心是让我们基于数据进行推断 就经典统计学而言 分布是我们最需要研究的东西;诸如均值 方差 相关和”概率”等概念都可以归为分布的范畴
从这里 我们已经找到统计作图真正重要的是什么了 统计量是统计作图的核心,越复杂的统计量或者统计量集合意味着包含着更充足数据的统计图形,而如何设计这个统计量是让统计图形保持直观的核心
菜单化的GUI界面不是一个“完美的”统计作图方式,GUI是不可能无限制增多的,但是统计图形会;由单一公司运营的闭源软件也无法成为一个优秀的统计作图方式,因为他们不可能跟上高速发展的学术界,只得挂一漏万;
一个开源的 纯代码化 的平台是统计作图的最优解 至此 R 与 Python 将会是现代统计作图方式的终点 直到一种新的 划时代的作图方式被发现 抛弃整个旧有的体系
我们说图形并不意味着简单,指的是统计图形的构造可以很细致入微(包括统计量的选定和图形元素的设计),而不是指作图的过程或程序很复杂。 考虑多少作图的细节是我们可能需要纠结的问题 我们需要找到效率和美观的平衡 当然我们后面对于各种作图方式都会介绍到
在工具一节的结束 我们用R代码重新绘制一些拿破仑的俄罗斯远征 图 理解他的高度自定义程度
1 | troops <- read.table(system.file("extdata", "troops.txt", package = "MSG"), header = TRUE) |

下面我们通过一些数据实例来说明统计图形的创建过程,以及应用中可能存在的问题
价格走势
我们使用一组手工录入的数据集来看看我们会对他进行什么样的图形表示
1 | year <- c(2006, 2007, 2008, 2009, 2010 + c(1, 4, 7, 10, 13) / 12) |
我们能够发现 这个数据集前四横坐标的对应的单位是一年,而后面五横坐标的单位却变成了三个月 看看直接做折线图会有什么样的变化
R 自动帮助我们把后面的折线图进行了压缩;如果直接让横坐标等距进行绘图的话 原本的剧烈增长会平滑 我们在统计图形中实现了一些trick 可以改变读者的第一感觉
除此之外 在绘制这样的时间序列数据的时候 我们可能会同时考虑折线图或者直方图 同时考虑零点的选择是从0开始或者从最小点开始
- 条形图容易观察差异大小(比较条的长短)
- 而折线图更容易观察斜率大小(升降速度)
- 如果将零点选在真实的 0 上,那么我们更容易计算真实的比率(高度之比)
- 若选在最小值上,那么更容易看出绝对变化值(因为差异被“放大”了)
给出对应的图形有

演员薪酬
我们收集演员名称、电视剧名称、类别(正剧 Drama 或喜剧 Comedy)、平均每集的收入,演员性别、IMDB (环球电影数据库)评分等信息 来考虑一下薪酬与性别 薪酬与作品评分(包含作品类型)之间的联系
对于分性别的薪酬问题 直接比较分布就非常的直观 直方图基本上是我们最好的选择;对于后者 LOWESS曲线 是一个很好的选择 他可以被看作一种类似二元回归的手段
LOWESS 局部加权回归散点平滑法;他抽取局部的数据进行多项式拟合,然后重复这个过程直到拟合完全部数据,可以被看作一种非参数的方法,相较于回归有很好的优势
如下图
直方图直观的体现了性别倒置的薪酬差异:可以看出女演员平均薪酬比男演员略高 直方图呈右偏趋势,这是由少数演员的薪酬极高造成的;
正剧而言, IMDB 评分与演员薪酬似乎没有关系,曲线几乎为一条水平线;对喜剧而言,这个关系并非直线关系,评分在 7.9 附近的薪酬最高
音乐之声
数据包含 36 个曲目,其中有古典音乐如莫扎特和维瓦尔第的作品,也有摇滚乐如 Abba 和 Eels 乐队的曲目。这里除了曲目类型(古典或摇滚)之外,我们仅仅使用三个连续变量:左声道频率的均值、最大值和方差。
对这样一批数据,我们关心的问题可能是古典乐和摇滚乐在音频变量上是否有差异;对于这个三维的数据 我们最直观的想法是三维散点图
我们以后会介绍到的平行坐标图和调和曲线图也对于这个高维的数据有很好的帮助

三个图形都展现出了不同音乐类型的差异 特别的 高维图形往往不是一个好主意,无论是高维的饼图或者是点图
词频聚类
每一位作者都有自己独特的风格,比如句子段落的长短、用词用语的习惯性等。在文学界,利用统计方法研究作者的文风,并对作品、作者进行分类、判别早就有了非常成功的案例
我们考虑用常规的分词手段对不同作者的作品中的词语进行划分 找到一些出现频率比较高的词 然后根据词频向量对作者进行聚类分析 得到了下图
我们的聚类结果和文学界的分析是吻合的
当然 我们也可以研究词之间的联系 看看谁更容易一起出现 关系网络图是一个不错的主意;与此同时 词云也是一个很常用的呈现方式;
作为传统非结构化数据的文本 我们的处理方式往往有很多不同
图库
作图经验
前面我们系统的介绍了各种统计图形 从技术上看 作这些图形并没有什么技术含量;但是一张好的图不仅仅是前面那些技术与代码能够实现的,对合适的数据选取合适的图形是很有难度的事情
我们首先从数据的角度入手 总结一下前面的叙述;然后介绍一些作图的原则 最后进行总结
图形选择
统计数据的最简单分类方法是分为定性数据和定量数据;就定量数据而言 我们研究的重心往往和分布有关 定类数据则往往是从频数入手的;下表是对前面介绍的图形的一个简单总结
| 一维 | 二维 | 高维 | 矩阵 | |
|---|---|---|---|---|
| 分类数据 | 条形图 | 马赛克图 | 马赛克图 | |
| 关联图、四瓣图 | ||||
| 连续数据 | 直方图 | 散点图 | 平行坐标图 | 颜色图 |
| 箱线图 | 散点图矩阵、三维散点图 | 热图 | ||
| Cleveland 点图 | 三维透视图、平滑散点图 | 等高图 | ||
| 一维散点图 | 星状图、符号图、脸谱图 | |||
| 混合数据 | 条件密度图 | 条件分割图 |
分类数据
对于分类数据,我们关心的往往是每个分类的频数或者比例是多少,这样的问题通常也都很简单,阅读图形仅仅是用眼睛排序的工作。
一维分类数据几乎没有别的选择,我们最常用的是条形图;多维数据情况下,马赛克图能清晰表达列联表中各个单元格的频数大小,同时也能观察表中的边际概率和条件概率。
除了描述性质的图形,我们还可以使用具有推断性质的关联图和四瓣图,前者可以让我们清楚看到如果列联表的行列变量不独立,那么哪些单元格对这个“不独立”的结论贡献大;后者可以让我们很快读出列联表的行列变量是否独立,即扇形环是否有重叠部分。
连续数据
相比之下连续数据的表达方式则要宽广得多:
一维情况下,我们可以用直方图和密度曲线展示数据的概率分布,用箱线图以刻画四分位数的方式展示数据的概要(这是粗略的分布表达方式),用 Cleveland 点图表达原始数值的大小,或者用一维散点图同时表达原始数值及其粗略的分布;
二维情况下最常用的是散点图,通常用来表达两个连续变量之间的线性或非线性关系,而散点图又常常和其它图形元素结合使用,例如回归直线等;三维情况下我们可以画三维的散点图,对于特殊的三维数据我们还可以画三元图
高维情况
把高维图形降低到低维可以表达的情况也很重要
寻找载体 在二维平面上寻找其它维度的“载体”,这些“载体”有很多可能性,但都是用图形元素的某些属性来附着高维数据,例如符号图中的符号长宽高等、脸谱图中的脸部特征
更改坐标系 笛卡尔坐标系理论上只能放二维变量,因此使用其它坐标系也是扩展到高维的自然选择,例如星状图使用的是星状的坐标系,从中心向外的每个分支都是一个坐标;平行坐标图也是常见的表达高维数据的工具,它将垂直的坐标系改为平行的,而平面上理论上可以容纳无穷多根平行线,所以平行坐标图理论上也可以放置任意多的变量
重复二维图形 二维的重复也可以达到表达高维数据的目的,例如散点图矩阵就是对所有变量两两重复画散点图,这样所有变量组合的散点图都可以表达在平面上了
降维 把高维数据降为二维数据也不失为一种办法,例如对数据做主成分分析,然后仅仅画前两个成分的散点图;实际上 GGobi 系统的巡游模式也是一种降维
混合数据
专门针对混合数据的图形并不多,前面介绍过的条件密度图是个少见的例子。在绝大多数情况下,我们都推荐使用“条件分割”的办法,利用分类变量的各个取值水平分别画二维图形,这样让我们很容易比较分类变量不同取值水平下的二维变量之间关系的差别
一定程度上,这种针对数据类型总结图形类型的做法有些死板,例如两个分类变量一般情况下是无法画散点图的,因为分类变量只取有限的几个值,所以两个分类变量之间的散点图通常只是若干个网格点,而这些点本身并不能反映出该位置上真正的频数;
分类变量并不是不能绘制散点图 它的问题是分类变量出现过多的聚集 那么向日葵散点图和jitter() 函数打散原始数据就是可行的方案 对于后者 我们需要更多的关注聚集情况
最后,画图不能墨守成规,大可在我们学过的图形中自由的寻找
作图原则
数据至上
数据是宝贵的,它们也许来自艰辛的问卷调查,或是繁琐的实验测量,因此我们应该尽量珍惜,但现实状况是我们经常有意或无意浪费数据,这样的情形包括:
- 表达数据的元素被次要图形元素遮挡
- 数据的特征无法在图中凸显
- 数据经过了不恰当的人工处理
分清主次
对于一幅图形而言,显然并非所有的图形元素都同等重要。例如,散点图中的点应该是最重要的元素,等高线图中的线更重要,等等。因此,我们不能让次要的图形元素干涉数据的表达,要让图形显得干净、清晰。
也就是 就是要让数据突出来(stand out)
R 基础图形系统中默认的点的样式是空心点,在很多情况下这并不是一个好的选择,因为空心点在图中看起来太不起眼,尤其是数据点较少的时候。
可以控制参数 pch 来调整我们的点的形状 有很多种形式可以选择
如果我们还想进一步从图中了解每个点代表的是谁,那么我们就需要往图中加文本标签,标签是有很强显示力的工具,它能直截了当告诉我们信息,然而由于它的体积相对较大,若处理不当,反而会让图中充满文本信息,从而失去了数据本身的意义
maptools 包中的 pointLabel() 函数提供了基于模拟退火算法和遗传算法的添加标签方案,它能尽量做到不让标签重叠;当然如果能增大一下绘图窗口就更好了
提到了标签 多维标度分析(Multidimensional Scaling,MDS)是一个非常适合以标签展示为主的统计学方法。 理论参考 机器学习进阶与无监督学习:多维缩放 (MDS)
因为我们关心的重点是个体与个体之间的距离,那么最好将个体的某种特征画在图中,最直接的想法当然就是个体的名称,此时图的重点就是这些名称标签
我们可以用MDS来观察一些聚类特征 毕竟它可以有效的降低维度 如下图

关于图形元素主次关系,还牵涉到一些细节设置问题,这也是我们在R基础作图系统 (base R) 介绍那么多图形细节的原因之一。
例如,坐标轴的刻度短线的方向默认朝外(tcl 参数),这是合理的设置,如果刻度线朝内伸去的话,就可能会干涉到作图区域的元素;
又如 xaxs 和 yaxs 参数,它们默认会先让作图区域的范围向外扩展 4%,这样坐标轴和作图数据的边界之间就留出了一片小空间,数据中的最小值和最大值都不会紧贴坐标轴,也能让主要图形元素充分显示出来,不受坐标轴线的干扰。
符号明确可分
我们在一幅图中会使用很多符号,为了保证图形的清晰可分 我们应该尽量选取差异比较大的符号;
谨慎处理数据
通常数据只有经过处理才能揭示我们想要知道的信息,例如给我们全国所有人的身高数据只会让我们被淹没在数字中,但一个均值或者中位数就能告诉我们身高的平均水平。人们可能因为这个原因形成了处理数据的习惯,但这对于统计图形来说往往是灾难,宝贵的原始信息被毁灭于人为处理。
在图形中,我们提倡尽量表达原始数据,而不要人为处理数据,包括
- 不要省略数据
- 不要离散化数据
图形相比起表格的优势之一就是它能以较小的空间展示很多信息,我们几乎没有必要刻意删减原始数据再画图,即使需要删减,通常也应该在看完全局数据之后再决定看局部数据。
离散化数据是人们更常用的数据处理手段,并且这种手段的缺点更不容易被发觉,这往往是因为以前行为的惯性 以及那些分类数据处理方法的诱惑; 实际上, 离散化数据丢失了原始信息 而且过于随意的划分区间往往会带来因为划分区间不当而导致的错误
同样我们也不能将“不处理数据”这条原则绝对化,有一种情况下处理数据会让图形表达更清楚,那就是从原始数据中不易直接观察的数据;例如两条折线的差异,或两组数据均值的差异,或观察增长率,此时作差能让我们更好的观察出差异
还有一种可能需要略微处理数据的情况,就是当数据中重叠的点很多时,我们要想办法让读者能够读出这些重叠的信息,随机略微打乱数据点的位置是一种处理办法,但是别忘了提醒读者我们的操作,否则他们可不会意识到我们进行了打乱
节约墨水
谈到墨水问题,我们不得不提及可视化大师级人物 Edward Tufte,他发明了一个有趣的词,叫图形垃圾(chartjunk),所谓的图形垃圾就是一幅图形中的多余元素,它们对表达数据毫无帮助,甚至掩盖或歪曲数据中的信息。
我们可以给出一个经典的chartjunk 他只展示了5个数字 五年里 25岁上下的美国大学录取比例

一幅图形可以用三种手段之一来装潢,一是让人眼花缭乱的颜色,二是 3D 效果,三是伪装得就像有丰富的内容一样,而这幅图动用了全部三种手段 —-Michael Friendly
设计布局
这里我们想介绍纵横比,它是一个对图形解释非常重要的概念,尤其是折线图。简单来说,纵横比影响的是图形元素宽高的比率。“瘦高”的图中,折线的斜率大,给人的感觉是升降趋势非常剧烈,而“矮胖”的图中,趋势变化则看起来平缓一些
R 基础图形系统中通常用 asp 参数设置纵横比 下面是一个调整了纵横比的例子
从下图中能看出 太阳黑子数量上升时的速度比下降的速度更快 ,这就是通过纵横比设置来欺骗读者的感官
Cleveland 对这个问题的建议是**调整纵横比让所有的折线的倾斜角度平均值接近 45∘**因为人眼对 45∘ 附近的角度感知最精确,而对太大或者太小的角度感知都很差
附带解释
尽管我们说“一图胜千言”,但图形本身对于不同读者来说可能会有不同的解读,甚至有些读者未必能理解一幅图的真正意思,这时候就很有必要提供附带文字解释
附带解释有两种方式,一种是向图中加上文本标注,这种方式有很大的局限性,因为图的空间毕竟有限,而且过多的文本标注可能会使图形本身失去重心
另外一种方式就是图的标题,在英语文献中似乎做得相对好一些,图形通常有明确的标题,而且标题就像一段完整的话,但大多数中文文献中的图都惜字如金,图的标题只有一句话,关于图的解释通常放在正文中,这种做法可能会让读者无法专注于图形的阅读,因为需要不断回到正文结合相应的解释文字来理解图形。
我们的建议是尽可能的让读者根据图形中的内容 结合脑内对文章的简单的理解,就能够完全理解图形的含义;这要求我们的标题是一个简短但是完整的故事。
考虑心理
这是一个经典的视觉欺骗 红线和黑线本质上是一样长的
类似的 我们还有一些已经被研究出的图形心理学有(基本都是Cleveland的成果)
- 红色为夸张色,所以红色区域可能看起来比实际大小更大
- 大区域中的填充颜色看起来比小区域更深一些
- 同一个角度在不同方向上放置可能会导致它看起来不一样,例如从水平线出发的角度和从 45∘ 角出发的同一个角看起来大小不同,这会影响饼图的解读
最后的总结
我们介绍了大量的统计图形 但是他们并不完全 或者说仅仅是冰山一角 原因如下
- 至今 R包已经超过了2w个 很多作者都会设计作图的函数,不可能完全介绍
- 很多统计包中的图形函数其实在用法上没有太大的变换 比如很多包都选择了扩展泛型函数
plot实现自己的效果 - 很多图形中的参数其实都是一样 或者说接近的
当然 R的图形系统也有着很多的不足
- 图形不可编辑 想要修改就要重画整幅图
- 作图功能自动化程度不够高 我们依旧需要慢慢的进行参数调节才能得到想要的效果
- 缺少交互图形功能
- 细节设置有不合理的地方 比如
plot默认的空心圆 数据很难凸显
关于图形的介绍在此告一段落,后面我们来介绍一些R中的作图系统
R基础作图系统
R基础作图系统的统计图形由函数生成,他的核心是R基本包中的 graphics 大量的开发者以此为基础扩展出了一系列衍生的包,他们都集成了基本系统中的语法规则
有时候 我们对统计图形有自己的个性化要求,此时就需要微调细节,这里介绍的就是这些细节上的设置。
两个作图函数
plot函数
R 中最普通的作图函数就是 plot() 函数,它是一个泛型函数,可以接受很多不同类的对象作为它的作图对象参数;我们这里要解释的只是其中的图形参数,而非作图对象参数
先介绍 plot() 的通用参数:
type
图形样式类型,有九种可能的取值,分别代表不同的样式:
'p'⇒ 画点;'l'⇒ 画线 ;'b'⇒同时画点和线,但点线不相交;'c'⇒ 将type = 'b'中的点去掉,只剩下相应的线条部分;'o'⇒ 同时画点和线, 且相互重叠,这是它与type = 'b'的区别;'h'⇒ 画铅垂线;'s'⇒ 画阶梯线,从一点到下一点时,先画水平线,再画垂直线;'S'⇒ 也是画阶梯线,但从一点到下一点是先画垂直线,再画水平线;'n'⇒ 作一幅空图,没有任何内容,但坐标轴、标题等其它元素都照样显示(除非用别的设置特意隐藏了)
main sub xlab ylab
主标题 副标题 x轴标签 y轴标签
asp
图形纵横比,即 y 轴上的 1 单位长度和 x 轴上 1 单位长度的比率;通常情况下这个比率不是 1,有些情况下需要设置以显示更好的图形效果,例如需要从角度表现直线的斜率:若 asp 不等于 1,那么 45∘ 的角可能看起来并不像真实的 45∘
x, y
欲作散点图的两个向量;如果 y 缺失,那么就用 x 对它的元素位置(1:n 的整数)作散点图
xlim, ylim
设置坐标系的界限,两个参数都取长度为 2 的向量,它们的作用类似 par() 中的 usr 参数但我们可以通过 par()$usr 获得一幅图的坐标系界限,而这里的两个参数就没有这个功能了,因为一般来说作图函数不会返回任何值(或者说返回值为空:NULL)
log
坐标是否取对数,取值 'x' 表示横坐标取对数,'y' 纵坐标取对数,'xy' 两个坐标轴都取对数
ann
一些默认的标记是否显示,如坐标轴标题和图标题
axes
是否画坐标轴;注意只会影响是否画出坐标轴线和刻度,不会影响坐标轴标题
frame.plot
是否给图形加框;可以查阅 box() 函数,作用类似但功能更详细
panel.first
在作图前要完成的工作;这个参数常常被用来在作图之前添加背景网格或者添加散点的平滑曲线,比如 panel.first = grid()
panel.last
作图之后要完成的工作;与上一个参数类似
初次以外 还有:
col, pch, cex, lty, lwd
这些参数的意思与 par() 中的参数基本相同,有所区别的是,par() 中这些参数只能设置一个单值,而这里可以对它们设置一个向量,这个向量的值将依次运用到各个元素上,若向量长度短于元素个数,那么向量会被循环使用,直到所有的元素都被画出来,事实上,向量的循环使用也是 R 图形参数的一大特点
bg
背景色;注意与 par() 不同的是,这里设置的只是可以画背景色的点的背景色,而不是设置整幅图形的背景色!
par函数
R 的图形参数既可以通过函数 par() 预先全局设置,也可以在具体作图函数(如 plot()、lines()等)中设置临时参数值;
二者的区别在于前者的设置会一直在当前图形设备中起作用,除非将图形设备关闭,而后者的设置只是临时性的,不会影响后面其它作图函数的图形效果。
函数 par() 中涵盖了大部分图形参数,因此专用一节讲述。
函数 par() 可以用来设置或者获取图形参数,par() 本身(括号中不写任何参数)返回当前的图形参数设置(一个 list)若要设置图形参数,则可用 par(tag = value) 的形式
目前 par() 函数涉及到的图形参数大约有 70 个,这里只是选取其中 常用且较易理解的参数进行解释
adj
调整图中字符的相对位置;取值为长度为 1 的数值向量,范围通常在 [0,1] 中,0 表示左对齐,1 表示右对齐;在 text() 函数中该参数的长度可以为 2,分别表示字符边界矩形框的左下角相对坐标点 (x, y) 位置的调整,向量的两个数值一般也在 [0,1] 范围中(有些图形设备中也可以超出此范围),表示字符串以左下角为基准、根据自身的宽度和高度分别向左和向下移动的比例,默认为 c(0.5, 0.5)。例如 c(0, 0) 表示整个字符(串)的左下角对准设定的坐标点,而 c(1, 0) 则表示字符串横向移动了自身宽度的距离,而纵向不受影响。
ask
切换到下一个新的作图设备(通常是作一幅新图)时是否需要用户输入(敲回车键或点鼠标);TRUE 表示是;FALSE 表示否。当有多幅图将逐一出现而需要按顺序一步步在图形设备上展示时很有用,这种情况下若设置 ask 为 TRUE,那么作图时每一副新图的出现都要先等待用户输入,否则所有的图将会一闪而过
bg
设置图形背景色;
bty
设置图形边框样式;取值为字符 o, l, 7, c, u, ] 之一; 这些字符本身的形状对应着边框样式,比如(默认值)o 表示四条边都显示,而 c 表示不显示右侧边
cex
图上元素(文本和符号等)的缩放倍数;取值为一个相对于 1 的数值(默认为 1)。具体的细节缩放可以通过如下参数设置(默认值均为 1):
cex.axis
坐标轴刻度标记的缩放倍数
cex.lab
坐标轴标题的缩放倍数
cex.main
图主标题的缩放倍数
cex.sub
图副标题的缩放倍数
col
图中符号(点、线等)的颜色;与 cex 参数类似
col.axis
坐标轴刻度标记的颜色
col.lab
坐标轴标题的颜色
col.main
图主标题的颜色
col.sub
图副标题的颜色
family
设置文本的字体族(衬线、无衬线、等宽、符号字体等);标准取值有:serif, sans, mono, symbol,
fg
设置前景色(若后面没有指定别的颜色设置,本参数会影响几乎所有的后续图形元素颜色,若后续图形元素有指定的颜色设置,那么只是影响图形边框和坐标轴刻度线的颜色);
font
设置文本字体样式;取值为一个整数;通常 1、2、3、4 分别表示正常、粗体、斜体和粗斜体;对于添加文本,text() 函数及其 vfont 参数可以设置更为详细的字体族和字体样式;参见这两个演示:demo(Hershey) 和 demo(Japanese),前者演示 Hershey 向量字体,后者演示日语的表示;
font.axis
坐标轴刻度标签的字体样式
font.lab
坐标轴标题的字体样式
font.main
图主标题的字体样式
font.sub
图副标题的字体样式
lab
设置坐标轴刻度数目(R 会尽量自动“取整”,即尽量向 0.5、1 或 10 的幂次靠近);取值形式 c(x, y, len):x 和 y 分别设置两轴的刻度数目,len 目前在 R 中尚未生效,因此设置任意值都不会有影响(但用到 lab 参数时必须写上这个参数)
las
坐标轴标签样式;取 0、1、2、3 四个整数之一,分别表示“总是平行于坐标轴”、“总是水平”、“总是垂直于坐标轴”和“总是竖直”。
lend
线条末端的样式(圆或方形);取值为整数 0、1、2 之一(或相应的字符串 'round', 'mitre', 'bevel'),注意后两者的细微区别
lheight
图中文本行高;取值为一个倍数,默认为 1
ljoin
线条相交处的样式;取值为整数 0、1、2 之一(或相应的字符串 'round', 'mitre', 'bevel'),分别表示画圆角、画方角和切掉顶角
lty
线条虚实样式:0⇒ 不画线,1⇒ 实线,2⇒ 虚线,3⇒ 点线,4⇒ 点划线,5⇒ 长划线,6⇒点长划线;或者相应设置如下字符串(分别对应前面的数字):'blank', 'solid', 'dashed', 'dotted', 'dotdash', 'longdash', 'twodash';还可以用由十六进制的数字组成的字符串表示线上实线和空白的相应长度,如 'F624'
lwd
线条宽度;默认为 1
mar
设置图形边界空白宽度;按照“下、左、上、右”的顺序,默认为 c(5, 4, 4, 2) + 0.1
mex
设置坐标轴的边界宽度缩放倍数;默认为 1,本参数会影响到 mgp 参数
mfrow, mfcol
设置一页多图;取值形式 c(nrow, ncol) 长度为 2 的向量,分别设置行数和列数
mgp
设置坐标轴的边界宽度;取值长度为 3 的数值向量,分别表示坐标轴标题、坐标轴刻度线标签和坐标轴线的边界宽度(受 mex 的影响),默认为 c(3, 1, 0),意思是坐标轴标题、坐标轴刻度线标签和坐标轴线离作图区域的距离分别为 3、1、0;
oma
设置外边界(Outer Margin)宽度;类似 mar,默认为 c(0, 0, 0, 0),当一页上只放一张图时,该参数与 mar 不好区分,但在一页多图的情况下就容易可以看出与 mar 的区别
pch
点的符号;pch = 19⇒ 实圆点、pch = 20⇒ 小实圆点、pch = 21⇒ 圆圈、pch = 22⇒ 正方形、pch = 23⇒ 菱形、pch = 24⇒ 正三角尖、pch = 25⇒ 倒三角尖,其中,21-25 可以填充颜色(用 bg 参数)
pty
设置作图区域的形状;默认为 'm':尽可能最大化作图区域;另外一种取值 's' 表示设置作图区域为正方形
srt
字符串的旋转角度;取一个角度数值
tck
坐标轴刻度线的高度;取值为与图形宽高的比例值(0 到 1 之间);正值表示向内画刻度线,负值表示向外;默认为不使用它(设为 NA),而使用 tcl 参数
tcl
坐标轴刻度线的高度;取一个与文本行高的比例值;正负值意义类似 tck,默认值为 -0.5,即向外画线,高度为半行文本高;
usr
作图区域的范围限制,取值长度为 4 的数值向量 c(x1, x2, y1, y2),分别表示作图区域内 x 轴的左右极限和 y 轴的下上极限;注意,若坐标取了对数(参见 xlog, ylog 两个参数),那么实际上设置的极限都是 10 的相应幂次
xaxs, yaxs
坐标轴范围的计算方式;默认 'r':先把原始数据的范围向外扩大 4%,然后用这个范围画坐标轴;另外一种取值 ‘i’ 表示直接使用原始数据范围;实际上还有其它的坐标轴范围计算方式,但是鉴于它们目前在 R 中都尚未生效,所以暂不加介绍
xaxt, yaxt
坐标轴样式;默认 's' 为标准样式;另外一种取值 'n' 意思是不画坐标轴
xlog, ylog
坐标是否取对数;默认 FALSE
xpd
对超出边界的图形的处理方式;取值 FALSE:把图形限制在作图区域内,出界的图形截去;取值 TRUE:把图形限制在图形区域内,出界的图形截去;取值 NA:把图形限制在设备区域内
这些参数的作用没有必要全都烂熟于心;本章可以仅作为参考资料,需要时查阅即可
介绍完上面的参数之后,我们顺便提一下关于 par() 的常用技巧。本节开头提到过,这个函数会“永久性”改变作图设置,我们有时并不想要这种功能,特别是在一幅图作完之后到准备下一幅图时,我们可能希望之前的参数可以被“还原”回来
此时,我们就需要在一幅图开始之前先把作图参数保存到一个对象中,比如 op = par(),然后我们可以 在作这幅图的过程中用 par() 函数任意更改设置以适合需要,作完这一幅图之后,我们再用 par(op) 语句把之前保存的参数设置“释放”出来,这样,中间过程对图形参数的更改就不再会影响到下一幅图。
当然,也可以每作完一幅图都把图形设备关掉,然后再作下一幅图,这样也能达到目的,只是稍显麻烦而已,尤其是有时候对一幅图形反复重作、调整、比较,那时不断关闭、打开图形设备就显得更繁琐了。
颜色
颜色可以说是图形中最重要的一个元素了
默认情况下,R 中颜色的设置主要需要依靠 grDevices 包的支持,其中提供了大量的颜色选择函数和生成函数,以及几种预先设置好的调色板(Palette),用以表现不同的主题。 我们下面来详细介绍
graphics包所支持的绘图颜色参数有三个 分别是 col bg fg 分别表示元素颜色,背景颜色,前景颜色;这个规则也被其他的绘图包吸收了过去。
固定颜色选择函数
固定颜色选择函数也就是 R 提供的它自带固定种类的颜色,主要是函数 colors()
colors(), colours()这两个函数完全一样,只是英文的两种不同拼写而已,它们不需要任何参数,会生成 657 种颜色名称
我们可以使用名称调取这些颜色,当然R也给常见的颜色分配了数字,分别是1-8,颜色向量就可以作为col bg fg参数的取值
颜色主题调色板
前面介绍的颜色生成过程对于一般人来说也许显得太复杂。此时,R 提供了第三种选择,那就是特定颜色主题的调色板。这些调色板都用一系列渐变的颜色表现了特定的主题,例如彩虹颜色系列、白热化颜色系列、地形颜色系列等等。
rainbow()顾名思义,就是用彩虹的颜色(“红橙黄绿青蓝紫”)来产生一系列颜色
heat.colors()从红色渐变到黄色再变到白色(以体现“高温”、“白热化”)
terrain.colors()从绿色渐变到黄色再到棕色最后到白色(这些颜色适合表示地理地形)
topo.colors()从蓝色渐变到青色再到黄色最后到棕色
cm.colors()从青色渐变到白色再到粉红色
这些调色板函数自动帮助我们生成一些颜色集合,我们可以直接调用
类型调色板
当然我们也可以更加缺乏耐心 附加包 RColorBrewer提供了三类调色板,用户只需要指定调色板名称,就可以用包中的 brewer.pal() 函数生成颜色。这三类调色板包括:
- 连续型调色板 Sequential palettes 生成一系列连续渐变的颜色,通常用来标记连续型数值的大小
- 极端化调色板 Diverging palettes 生成用深色强调两端、浅色标示中部的系列颜色,可用来标记数据中的离群点
- 离散型调色板 Qualitative palettes 生成一系列彼此差异比较明显的颜色,通常用来标记分类数据
brewer.pal()会返回颜色向量
RColorBrewer 包还提供了 display.brewer.pal() 和 display.brewer.all() 函数,用于在图形窗口中展示选定的调色板或所有调色板。
对于更多详细的解释参考帮助,RColorBrewer是非常易用的。
颜色生成和转换函数
R 提供了一系列利用颜色生成模型如 RGB 模型(红绿蓝三原色混合)、HSV 色彩模型(色调、饱和度和纯度)、HCL 色彩模型(色调、色度和亮度)和灰色生成模型等。颜色的构造原理比较复杂,超出了本书讨论范围,因此这里仅对相关函数的用法作介绍。
rgb()红绿蓝三原色混合,用法 rgb(red, green, blue, alpha, names = NULL, maxColorValue = 1)
hsv()用色调(Hue)、饱和度(Saturation)和纯度(Value)来构造颜色,用法 hsv(h = 1, s = 1, v = 1, alpha);
hcl()用色调(Hue)、色度(Chroma)和亮度(Luminance)构造颜色,用法为 hcl(h = 0, c = 35, l = 85, alpha, fixup = TRUE);
gray(), grey()生成灰色系列;只有一个参数 level,表示灰度水平,取值在 0 到 1 之间
rgb2hsv()将 RGB 颜色转换为 HSV 颜色,用法 rgb2hsv(r, g = NULL, b = NULL, maxColorValue = 255)
col2rgb()将任意一种 R 颜色值转换为 RGB 表示,用法 col2rgb(col, alpha = FALSE)
作图元素
统计图形是用元素构成的 这里我们介绍最底层的元素,我们所使用的高级作图函数本质上就是把这些元素按照一定规律生成再打包成一个函数供我们使用 这对于希望接触R底层修改的人有帮助
点
关于点的设置,我们既可以在很多作图函数中用 pch 等参数实现,也可以在用低层函数 points() 向已有图形中添加点来实现
我们这里着重强调
lwd参数,我们知道这是设定线条宽度的,对于点来说,这个参数同样可以设置点的边缘“线条”宽度;pch参数同样可以接受字符作为参数值,而不仅仅是数字;- 最后,参数
pch取值从 21~25 的点可以填充背景颜色
线
我们可以用函数 lines() 来向图中添加曲线(这里所说的曲线本质上是一些线段的连接,并非光滑的曲线);下面主要补充说明一下关于线条样式 lty 的设定
R 中可以实现几乎无数种线条样式,因为它的 lty 参数相当灵活,除了取值 0~6 之外,可以根据一个十六进制的数字串(位数必须是偶数位,且非零)来设定线条的虚实
关于直线,我们在平面坐标系中只需要确定两个因素就可以确定它的位置:即斜率和截距。函数 abline() 就是用来添加直线的
线段可以用函数 segments() 生成
样条是用光滑曲线连接若干数据点的曲线 xspline 是生成的方法
箭头可以用函数 arrows()生成
矩形、多边形
R 中绘制多边形也是很方便的,主要使用 polygon() 函数,矩形是多边形的特例,不过 R 也提供了专门的函数 rect() 来绘制它
其实还有一个特殊的“矩形”,那就是整幅图形的边框,它可以用 box() 函数来完成
网格线
有时为了方便图形阅读者知道图中元素的更精确的位置,我们可以用添加背景网格线的办法来辅助读者的视线对齐坐标轴。函数 grid() 所实现的就是这一个功能
标题 任意文本 周边文本
图形中的所有文本可以分为三类:标题(主副标题和坐标轴标题)、任意文本和图形周边文本。title() 函数用来添加标题,text() 函数用来向图形中任意位置添加文本,mtext() 函数用来向图的四条边上添加文本
图例
函数 legend() 的作用是添加图例
坐标轴
有时候我们需要对坐标轴做一定的特殊设置,比如作一幅双坐标轴的图形,或者在坐标轴标记中使用特殊的文本,那么就必须使用 axis() 函数来辅助完成对坐标轴的设置和调整
梯度下降算法
我们应该可以理解 R 作图的自由——几乎所有图形的细节都可以被我们控制 那么考虑用他们实现梯度下降算法的可视化

具体的函数实现可以参考 MSG包中的 msg("9.22")
一页多图
有时候我们需要将多幅图形放在同一页图中,以便对这些图形作出对比,或者使图形的排列更加美观。这种情况下,我们至少可以有三种选择:
设置图形参数
我们曾经讲到过 mfrow 和 mfcol 两个参数,如果我们在 par() 函数中给这两个参数中的一者提供一个长度为 2 的向量,那么接下来的图形就会按照这两个参数所设定的行数和列数依次生成图形 这是最常用的图形排版方法
这两个参数的限制在于它们只能将图形区域拆分为网格状,每一格的长和宽都分别必须相等,而且每一格中必须有一幅图形,不能实现一幅图形占据多格的功能。
设置图形版面
R 提供了 layout()函数作为设置图形版面拆分的工具
mat参数为一个矩阵,提供了作图的顺序以及图形版面的安排widths和heights提供了各个矩形作图区域的长和宽的比例respect控制着各图形内的横纵轴刻度长度的比例尺是否一样n为欲显示的区域的序号
图形设备
利用 grDevices 包中的若干图形设备,我们可以将 R 的图形输出为各种格式的文件,包括位图文件(BMP、JPEG、PNG、TIFF)和矢量图文件(PDF、EPS)以及 TeX 或 LaTeX 文件
基本的图形设备函数有位图设备 bmp()、jpeg()、png() 和 tiff(),以及矢量图设备 svg()、postscript() 和 pdf(),打开图形设备之后,所有的 R 图形都会被生成在该图形设备中,而不会再在窗口中显示,直到图形设备被关闭。
tikzDevice 包对图形的输出是更加的友好的 最好使用它来控制我们图形的输出
图设备可以支持在图形中使用中文或其它 CJK 字符,但是在矢量图设备中使用中文字符时则需要设定字体族参数 family,否则中文不会被显示出来(例如简体中文应该用 pdf(family = 'GB1') 导出EPS格式也会出现这个问题
数学公式
由于统计理论中经常需要用到数学符号,所以向统计图形中添加一些数学说明不仅会使得图形看起来更专业,对图形背后的理论也是一种重要补充。
R 的 grDevices 包 中提供了一系列数学公式的表达符号,他可以帮助我们在图形中插入数学公式 需要的时候可以去学习 ?plotmath 就可以查看帮助
如果想向图中添加数学表达式的文本标签,只需要将文本设置为表达式(expression)的类型即可
tikzDevice 包也可以帮助我们生成质量更高的数学公式内容 这个扩展包在2020年被发行 对Latex语法更加的友好了
ggplot2作图系统简介
基础图形系统虽然灵活,但它无穷无尽的选项往往让用户感到迷茫
ggplot2 包从易用性出发,以“The Grammar of Graphics”一书 的理论为支撑,构建了一套易用、实用而且美观的图形系统。
ggplot2 的核心概念是“层”,所有的图形都是由层的叠加构成,这是对统计图形的一个非常形象的抽象;另外,它在程序实现上也很巧妙:它扩展了泛型函数 + 用多个图层叠加得到我们所需要的图形
ggplot2相对独立的系统已经称为了一种单独的程序设计语言 因此我们在基本了解他的工作逻辑后,单独的介绍其各种语言细节 R ggplot2
- Title: R Statistical Graphics: Base Graphics, lattice, and ggplot2
- Author: Hyacehila
- Created at : 2024-09-16 14:32:48
- Link: https://hyacehila.github.io//blog/2024/09/16/r-graph-learning-notes/
- License: This work is licensed under CC BY-NC-SA 4.0.
