图形初阶
本章内容
图形的创建和保存
自定义符号、线条、颜色和坐标轴
标注文本和标题
控制图形维度
组合多个图形
我曾经多次向客户展示以数字和文字表示的、精心整理的统计分析结果,得到的只是客户呆
滞的眼神,尴尬得房间里只能听到鸟语虫鸣。然而,当我使用图形向相同的用户展示相同的信息
时,他们往往会兴致盎然,甚至豁然开朗。还有很多次,我都是通过看图才得以发现了数据中的
模式,或是检查出了数据中的异常值——这些模式和异常都是在我进行更为正式的统计分析时彻
底遗漏的。
人类非常善于从视觉呈现中洞察关系。一幅精心绘制的图形能够帮助你在数以千计的零散信
息中做出有意义的比较,提炼出使用其他方法时不那么容易发现的模式。这也是统计图形领域的
进展能够对数据分析产生重大影响的原因之一。数据分析师需要观察他们的数据,而R在该领域
表现出众。
在本章中,我们将讨论处理图形的一般方法。我们首先探讨如何创建和保存图形,然后关注
如何修改那些存在于所有图形中的特征,包括图形的标题、坐标轴、标签、颜色、线条、符号和
文本标注。我们的焦点是那些可以应用于所有图形的通用方法。(在后续各章,我们将关注特定
类型的图形。)最后,我们将研究组合多幅图形为单幅图形的各种方法。
3.1 使用图形
R是一个惊艳的图形构建平台。这里我特意使用了“构建”一词。在通常的交互式会话中,
你可以通过逐条输入语句构建图形,逐渐完善图形特征,直至得到想要的效果。
考虑以下五行代码:
attach(mtcars)
plot(wt, mpg)
abline(lm(mpg~wt))
title("Regression of MPG on weight")
首句绑定了数据框mtcars。第二条语句打开了一个图形窗口并生成了一幅散点图,横轴表示车
身重量,纵轴为每加仑汽油行驶的英里数。第三句向图形添加了一条最优拟合曲线。第四句添加
了标题。最后一句为数据框解除了绑定。在R中,图形通常都是以这种交互式的风格绘制的(参
见图3-1)。
可以通过代码或图形用户界面来保存图形。要通过代码保存图形,将绘图语句夹在开启目标
图形设备的语句和关闭目标图形设备的语句之间即可。例如,以下代码会将图形保存到当前工作
目录中名为mygraph.pdf的PDF文件中
pdf("mygraph.pdf")
attach(wt, mpg)
plot(wt, mpg)
abline(lm(mpg~wt))
title("Regression of MPG on weight")
detach(mtcars)
dev.off()
除了pdf(),还可以使用函数win.metafile()、png()、jpeg()、bmp()、tiff()、xfig()
和postscript()将图形保存为其他格式。(注意,Windows图元文件格式仅在Windows系统中可
用。)关于保存图形输出到文件的更多细节,可以参考1.3.4节。
通过图形用户界面保存图形的方法因系统而异。对于Windows,在图形窗口中选择“文件”→
“另存为”,然后在弹出的对话框中选择想要的格式和保存位置即可。在Mac上,当Quartz图形窗
口处于高亮状态时,点选菜单栏中的“文件”→“另存为”即可。其提供的输出格式仅有PDF。
在UNIX系统中,图形必须使用代码来保存。在附录A中,我们将考虑每个系统中可用的备选图
形用户界面,这将给予你更多选择。
通过执行如plot()、hist()(绘制直方图)或boxplot()这样的高级绘图命令来创建一幅
新图形时,通常会覆盖掉先前的图形。如何才能创建多个图形并随时查看每一个呢?方法有若干。
第一种方法,你可以在创建一幅新图形之前打开一个新的图形窗口:
dev.new()
statements to create graph 1
dev.new()
statements to create a graph 2
etc.
每一幅新图形将出现在最近一次打开的窗口中。
第二种方法,你可以通过图形用户界面来查看多个图形。在Mac上,你可以使用Quartz菜单
中的“后退”(Back)和“前进”(Forward)来逐个浏览图形。在Windows上,这个过程分为两
步。在打开第一个图形窗口以后,勾选“历史”(History)→“记录”(Recording)。然后使用菜
单中的“上一个”(Previous)和“下一个”(Next)来逐个查看已经绘制的图形。
第三种也是最后一种方法,你可以使用函数dev.new()、dev.next()、dev.prev()、
dev.set()和dev.off()同时打开多个图形窗口,并选择将哪个输出发送到哪个窗口中。这种
方法全平台适用。关于这种方法的更多细节,请参考help(dev.cur)。
R将在保证用户输入最小化的前提下创建尽可能美观的图形。不过你依然可以使用图形参数
来指定字体、颜色、线条类型、坐标轴、参考线和标注。其灵活度足以让我们实现对图形的高度
定制。
我们将以一个简单的图形作为本章的开始,接着进一步探索按需修改和强化图形的方式。然
后,我们将着眼于一些更复杂的示例,以阐明其他的图形定制方法。我们关注的焦点是那些可以
应用于多种R图形的技术。对于本书中描述的所有图形,本章讨论的方法均有效,不过第16章中
使用lattice包创建的图形是例外。(lattice包拥有自己的图形外观定制方法。)在其他各章
中,我们将探索各种特定的图形,并探讨它们在何时何地最有用。
3.2 一个简单的例子
让我们从表3-1中给出的假想数据集开始。它描述了病人对两种药物五个剂量水平上的响应
情况。
表3-1 病人对两种药物五个剂量水平上的响应情况
剂 量 对药物A的响应 对药物B的响应
20 16 15
30 20 18
40 27 25
45 40 31
60 60 40
可以使用以下代码输入数据:
> dose <- c(20, 30, 40, 45, 60)
> drugA <- c(16, 20, 27, 40, 60)
> drugB <- c(15, 18, 25, 31, 40)
使用以下代码可以创建一幅描述药物A的剂量和响应关系的图形:
> plot(dose, drugA, type="b")
plot()是R中为对象作图的一个泛型函数(它的输出将根据所绘制对象类型的不同而变化)。
本例中,plot(x, y, type="b")将x置于横轴,将y置于纵轴,绘制点集(x, y),然后使用线段
将其连接。选项type="b"表示同时绘制点和线。使用help(plot)可以查看其他选项。结果如
图3-2所示。
3.3 图形参数
我们可以通过修改称为图形参数的选项来自定义一幅图形的多个特征(字体、颜色、坐标轴、
标题)。
(修改图形参数的)一种方法是通过函数par()来指定这些选项。以这种方式设定的参数值
除非被再次修改,否则将在会话结束前一直有效。其调用格式为par(optionname=value,
optionname=name,…)。不加参数地执行par()将生成一个含有当前图形参数设置的列表。添加
参数no.readonly=TRUE可以生成一个可以修改的当前图形参数列表。
继续我们的例子,假设你想使用实心三角而不是空心圆圈作为点的符号,并且想用虚线代替
实线连接这些点。你可以使用以下代码完成修改:
> opar <- par(no.readonly=TRUE)
> par(lty=2, pch=17)
> plot(dose, drugA, type="b")
> par(opar)
首个语句复制了一份当前的图形参数设置。第二句将默认的线条类型修改为虚线(lty=2)
并将默认的点符号改为了实心三角(pch=17)。然后我们绘制了图形并还原了原始设置。线条类
型和符号将在3.3.1节中详述。
你可以随心所欲地多次使用par()函数,即par(lty=2, pch=17)也可以写成:
par(lty=2)
par(pch=17)
指定图形参数的第二种方法是为高级绘图函数直接提供optionname=value的键值对。这种
情况下,指定的选项仅对这幅图形本身有效。你可以通过代码:
plot(dose, drugA, type="b", lty=2, pch=17)
来生成与上图相同的图形。
并不是所有的高级绘图函数都允许指定全部可能的图形参数。你需要参考每个特定绘图函数
的帮助(如?plot、?hist或?boxplot)以确定哪些参数可以以这种方式设置。下面介绍可以
设定的许多重要图形参数。
3.3.1 符号和线条
如你所见,可以使用图形参数来指定绘图时使用的符号和线条类型。相关参数如表3-2所示。
表3-2 用于指定符号和线条类型的参数
参 数 描 述
pch 指定绘制点时使用的符号(见图3-4)
cex 指定符号的大小。cex是一个数值,表示绘图符号相对于默认大小的缩放倍数。默认大小
为1,1.5表示放大为默认值的1.5倍,0.5表示缩小为默认值的50%,等等
lty 指定线条类型(参见图3-5)
lwd 指定线条宽度。lwd是以默认值的相对大小来表示的(默认值为1)。例如,lwd=2将生
成一条两倍于默认宽度的线条
选项pch=用于指定绘制点时使用的符号。可能的值如图3-4所示。
对于符号21~25,你还可以指定边界颜色(col=)和填充色(bg=)。
选项lty=用于指定想要的线条类型。可用的值如图3-5所示。
综合以上选项,以下代码:
plot(dose, drugA, type="b", lty=3, lwd=3, pch=15, cex=2)
将绘制一幅图形,其线条类型为点线,宽度为默认宽度的3倍,点的符号为实心正方形,大
小为默认符号大小的2倍。结果如图3-6所示。
接下来我们将讨论颜色的指定方法。
3.3.2 颜色
R中有若干和颜色相关的参数。表3-3列出了一些常用参数。
表3-3 用于指定颜色的参数
参 数 描 述
col 默认的绘图颜色。某些函数(如lines和pie)可以接受一个含有颜色值的向量
并自动循环使用。例如,如果设定col=c("red", "blue")并需要绘制三条线,
则第一条线将为红色,第二条线为蓝色,第三条线又将为红色
col.axis 坐标轴刻度文字的颜色
col.lab 坐标轴标签(名称)的颜色
col.main 标题颜色
col.sub 副标题颜色
fg 图形的前景色
bg 图形的背景色
在R中,可以通过颜色下标、颜色名称、十六进制的颜色值、RGB值或HSV值来指定颜色。
举例来说,col=1、col="white"、col="#FFFFFF"、col=rgb(1,1,1)和col=hsv(0,0,1)
都是表示白色的等价方式。函数rgb()可基于红—绿—蓝三色值生成颜色,而hsv()则基于色相—
饱和度—亮度值来生成颜色。请参考这些函数的帮助以了解更多细节。
函数colors()可以返回所有可用颜色的名称。Earl F. Glynn为R中的色彩创建了一个优秀的
在线图表,参见http://research.stowers-institute.org/efg/R/Color/Chart。R中也有多种用于创建连续
型颜色向量的函数,包括rainbow()、heat.colors()、terrain.colors()、topo.colors()
以及cm.colors()。举例来说,rainbow(10)可以生成10种连续的“彩虹型”颜色。多阶灰度
色可使用gray()函数生成。这时要通过一个元素值为0和1之间的向量来指定各颜色的灰度。
gray(0:10/10)将生成10阶灰度色。试着使用以下代码:
> n <- 10
> mycolors <- rainbow(n)
> pie(rep(1, n), labels=mycolors, col=mycolors)
> mygrays <- gray(0:n/n)
> pie(rep(1, n), labels=mygrays, col=mygrays)
来观察这些函数的工作方式。本章始终会有使用颜色参数的示例。
3.3.3 文本属性
图形参数同样可以用来指定字号、字体和字样。表3-4阐释了用于控制文本大小的参数。字
体族和字样可以通过字体选项进行控制(见表3-5)。
表3-4 用于指定文本大小的参数
参 数 描 述
cex 表示相对于默认大小缩放倍数的数值。默认大小为1,1.5表示放大为默认值的1.5
倍,0.5表示缩小为默认值的50%,等等
cex.axis 坐标轴刻度文字的缩放倍数。类似于cex
参 数 描 述
cex.lab 坐标轴标签(名称)的缩放倍数。类似于cex
cex.main 标题的缩放倍数。类似于cex
cex.sub 副标题的缩放倍数。类似于cex
表3-5 用于指定字体族、字号和字样的参数
参 数 描 述
font 整数。用于指定绘图使用的字体样式。1=常规,2=粗体,3=斜体,4=粗斜体,5=
符号字体(以Adobe符号编码表示)
font.axis 坐标轴刻度文字的字体样式
font.lab 坐标轴标签(名称)的字体样式
font.main 标题的字体样式
font.sub 副标题的字体样式
ps 字体磅值(1磅约为1/72英寸)。文本的最终大小为 ps*cex
family 绘制文本时使用的字体族。标准的取值为serif(衬线)、sans(无衬线)和mono
(等宽)
举例来说,在执行语句:
par(font.lab=3, cex.lab=1.5, font.main=4, cex.main=2)
之后创建的所有图形都将拥有斜体、1.5倍于默认文本大小的坐标轴标签(名称),以及粗斜体、
2倍于默认文本大小的标题。
我们可以轻松设置字号和字体样式,然而字体族的设置却稍显复杂。这是因为衬线、无衬线
和等宽字体的具体映射是与图形设备相关的。举例来说,在Windows系统中,等宽字体映射为TT
Courier New,衬线字体映射为TT Times New Roman,无衬线字体则映射为TT Arial(TT代表True
Type)。如果你对以上映射表示满意,就可以使用类似于family="serif"这样的参数获得想要
的结果。如果不满意,则需要创建新的映射。在Windows中,可以通过函数windowsFont()来
创建这类映射。例如,在执行语句:
windowsFonts(A=windowsFont("Arial Black"),
B=windowsFont("Bookman Old Style"),
C=windowsFont("Comic Sans MS"))
之后,即可使用A、B和C作为family的取值。在本例的情境下,par(family="A")将指定Arial
Black作为绘图字体。(3.4.2节中的代码清单3-2提供了一个修改文本参数的示例。)请注意,函数
windowsFont()仅在Windows中有效。在Mac上,请改用quartzFonts()。
如果以PDF或PostScript格式输出图形,则修改字体族会相对简单一些。①对于PDF格式,可
以使用names(pdfFonts())找出你的系统中有哪些字体是可用的,然后使用pdf(file=
"myplot.pdf", family="fontname")来生成图形。对于以PostScript格式输出的图形,则可
以对应地使用names(postscriptFonts())和postscript(file="myplot.ps", family=
"fontname")。请参阅在线帮助以了解更多信息。
3.3.4 图形尺寸与边界尺寸
最后,可以使用表3-6列出的参数来控制图形尺寸和边界大小。
表3-6 用于控制图形尺寸和边界大小的参数
参 数 描 述
pin 以英寸表示的图形尺寸(宽和高)
mai 以数值向量表示的边界大小,顺序为“下、左、上、右”,单位为英寸
mar 以数值向量表示的边界大小,顺序为“下、左、上、右”,单位为英分*。默认值为c(5, 4, 4, 2) + 0.1
*一英分等于十二分之一英寸。——译者注
代码:
par(pin=c(4,3), mai=c(1, .5, 1, .2))
可生成一幅4英寸宽、3英寸高、上下边界为1英寸、左边界为0.5英寸、右边界为0.2英寸的图形。
关于边界参数的完整指南,不妨参阅Earl F. Glynn编写的一份全面的在线教程(http://research.
stowers-institute.org/efg/R/Graphics/Basics/mar-oma/)。
让我们使用最近学到的选项来强化之前的简单图形示例。代码清单3-1中的代码生成的图形
如图3-7所示。
代码清单3-1 使用图形参数控制图形外观
dose <- c(20, 30, 40, 45, 60)
> drugA <- c(16, 20, 27, 40, 60)
> drugB <- c(15, 18, 25, 31, 40)
> opar <- par(no.readonly=TRUE)
> par(pin=c(2,3))
> par(lwd=2, cex=1.5)
> par(cex.axis=.75, font.axis=3)
> plot(dose, drugA, type="b", pch=19, lty=2, col="red")
> plot(dose, drugB, type="b", pch=23, lty=6, col="blue", bg="green")
首先,你以向量的形式输入了数据,然后保存了当前的图形参数设置(这样就可以在稍后恢
复设置)。接着,你修改了默认的图形参数,这样,得到的图形将为2英寸宽、3英寸高。除此之
外,线条的宽度将为默认宽度的两倍,符号将为默认大小的1.5倍。坐标轴刻度文本被设置为斜
——————————
① PDF中文字体的使用比较麻烦,同时在Linux系统中可能会遇到中文字体无法嵌入的问题。Windows上的解决方案之
一是使用Cairo包中的CairoPDF()函数。此话题的详细讨论请参考http://cos.name/cn/topic/101521。——译者注
体、缩小为默认大小的75%。之后,我们使用红色实心圆圈和虚线创建了第一幅图形,并使用绿
色填充的绿色菱形加蓝色边框和蓝色虚线创建了第二幅图形。最后,我们还原了初始的图形参数
设置。
值得注意的是,通过par()设定的参数对两幅图都有效,而在绘图函数中指定的参数仅对那
个特定图形有效。观察图3-7可以发现,图形的呈现上还有一定缺陷。这两幅图都缺少标题,并
且纵轴的刻度单位不同,这无疑限制了我们直接比较两种药物的能力。同时,坐标轴的标签(名
称)也应当提供更多的信息。
下一节中,我们将转而探讨如何自定义文本标注(如标题和标签)和坐标轴。要了解可用图
形参数的更多信息,请参阅help(par)。
3.4 添加文本、自定义坐标轴和图例
除了图形参数,许多高级绘图函数(例如plot、hist、boxplot)也允许自行设定坐标轴
和文本标注选项。举例来说,以下代码在图形上添加了标题(main)、副标题(sub)、坐标轴标
签(xlab、ylab)并指定了坐标轴范围(xlim、ylim)。结果如图3-8所示。
> plot(dose, drugA, type="b", col="red", lty=2, pch=2, lwd=2, main="Clinical Trials for Drug A", sub="This is hypothetical data", xlab="Dosage", ylab="Drug Response", xlim=c(0, 60), ylim=c(0, 70))
再次提醒,并非所有函数都支持这些选项。请参考相应函数的帮助以了解其可以接受哪些选
项。从更精细的控制和模块化的角度考虑,你可以使用本节余下部分描述的函数来控制标题、坐
标轴、图例和文本标注的外观。
注意 某些高级绘图函数已经包含了默认的标题和标签。你可以通过在plot()语句或单独
的par()语句中添加ann=FALSE来移除它们。
3.4.1 标题
可以使用title()函数为图形添加标题和坐标轴标签。调用格式为:
title(main="main title", sub="sub-title", xlab="x-axis label", ylab="y-axis label")
函数title()中亦可指定其他图形参数(如文本大小、字体、旋转角度和颜色)。举例来说,
以下代码将生成红色的标题和蓝色的副标题,以及较默认大小小25%的绿色x轴、y轴标签:
title(main="My Title", col.main="red", sub="My Sub-title", col.sub="blue",
xlab="My X label", ylab="My Y label", col.lab="green", cex.lab=0.75)
3.4.2 坐标轴
你可以使用函数axis()来创建自定义的坐标轴,而非使用R中的默认坐标轴。其格式为:
axis(side, at=, labels=, pos=, lty=, col=, las=, tck=, ...)
各参数已详述于表3-7中。
表3-7 坐标轴选项
选 项 描 述
side 一个整数,表示在图形的哪边绘制坐标轴(1=下,2=左,3=上,4=右)
at 一个数值型向量,表示需要绘制刻度线的位置
labels 一个字符型向量,表示置于刻度线旁边的文字标签(如果为NULL,则将直接使用at中的值)
pos 坐标轴线绘制位置的坐标(即与另一条坐标轴相交位置的值)
lty 线条类型
col 线条和刻度线颜色
las 标签是否平行于(=0)或垂直于(=2)坐标轴
tck 刻度线的长度,以相对于绘图区域大小的分数表示(负值表示在图形外侧,正值表示在图形内侧,0
表示禁用刻度,1表示绘制网格线);默认值为0.01
(…) 其他图形参数
创建自定义坐标轴时,你应当禁用高级绘图函数自动生成的坐标轴。参数axes=FALSE将禁
用全部坐标轴(包括坐标轴框架线,除非你添加了参数frame.plot=TRUE)。参数xaxt="n"和
yaxt="n"将分别禁用X轴或Y轴(会留下框架线,只是去除了刻度)。代码清单3-2中是一个稍显
笨拙和夸张的例子,它演示了我们到目前为止讨论过的各种图形特征。结果如图3-9所示。
代码清单3-2 自定义坐标轴的示例
> x <- c(1:10)
> y <- x
> z <- 10/x
> opar <- par(no.readonly=TRUE)
> par(mar=c(5, 4, 4, 8) + 0.1)
> plot(x, y, type="b", pch=21, col="red", yaxt="n", lty=3, ann=FALSE)
> lines(x, z, type="b", pch=22, col="red", lty=2)
> axis(2, at=x, labels=x, col.axis="red", las=2)
> axis(4, at=z, labels=round(z, digits=2), col.axis="blue", las=2, cex.axis=0.7, tck=-0.1)
> mtext("y=1/x", side=4, line=3, cex.lab=1, las=2, col="blue")
> title("An Example of Creative Axes", xlab="X values", ylab="Y=X")
> par(opar)
到目前为止,我们已经讨论过代码清单3-2中除lines()和mtext()以外的所有函数。使用
plot()语句可以新建一幅图形。而使用lines()语句,你可以为一幅现有图形添加新的图形元
素。在3.4.4节中,你会再次用到它,在同一幅图中绘制药物A和药物B的响应情况。函数mtext()
用于在图形的边界添加文本。我们将在3.4.5节中讲到函数mtext(),同时会在第11章中更充分地
讨论lines()函数。
次要刻度线
注意,我们最近创建的图形都只拥有主刻度线,却没有次要刻度线。要创建次要刻度线,你
需要使用Hmisc包中的minor.tick()函数。如果你尚未安装Hmisc包,请先安装它(参考1.4.2
节)。你可以使用代码:
> library(Hmisc)
> minor.tick(nx=n, ny=n, tick.ratio=n)
来添加次要刻度线。其中nx和ny分别指定了X轴和Y轴每两条主刻度线之间通过次要刻度线划分
得到的区间个数。tick.ratio表示次要刻度线相对于主刻度线的大小比例。当前的主刻度线长
度可以使用par("tck")获取。举例来说,下列语句将在X轴的每两条主刻度线之间添加1条次要
刻度线,并在Y轴的每两条主刻度线之间添加2条次要刻度线:
minor.tick(nx=2, ny=3, tick.ratio=0.5)
次要刻度线的长度将是主刻度线的一半。3.4.4节中给出了添加次要刻度线的一个例子(代码
清单3-3和图3-10)。
3.4.3 参考线
函数abline()可以用来为图形添加参考线。其使用格式为:
abline(h=yvalues, v=xvalues)
函数abline()中也可以指定其他图形参数(如线条类型、颜色和宽度)。举例来说:
abline(h=c(1, 5, 7))
在y为1、5、7的位置添加了水平实线,而代码:
abline(v=seq(1, 10, 2), lty=2, col="blue")
则在x为1、3、5、7、9的位置添加了垂直的蓝色虚线。代码清单3-3为我们的药物效果图在
y = 30的位置创建了一条参考线。结果如图3-10所示。
3.4.4 图例
当图形中包含的数据不止一组时,图例可以帮助你辨别出每个条形、扇形区域或折线各代表
哪一类数据。我们可以使用函数legend()来添加图例(果然不出所料)。其使用格式为:
legend(location, title, legend, ...)
常用选项详述于表3-8中。
表3-8 图例选项
选 项 描 述
location 有许多方式可以指定图例的位置。你可以直接给定图例左上角的x、y坐标,也可以执行
locator(1),然后通过鼠标单击给出图例的位置,还可以使用关键字bottom、bottomleft、
left、topleft、top、topright、right、bottomright或center放置图例。如果你使用
了以上某个关键字,那么可以同时使用参数inset=指定图例向图形内侧移动的大小(以绘图区域
大小的分数表示)
title 图例标题的字符串(可选)
legend 图例标签组成的字符型向量
… 其他选项。如果图例标示的是颜色不同的线条,需要指定col=加上颜色值组成的向量。如果图例
标示的是符号不同的点,则需指定pch=加上符号的代码组成的向量。如果图例标示的是不同的线
条宽度或线条类型,请使用lwd=或lty=加上宽度值或类型值组成的向量。要为图例创建颜色填
充的盒形(常见于条形图、箱线图或饼图),需要使用参数fill=加上颜色值组成的向量
其他常用的图例选项包括用于指定盒子样式的bty、指定背景色的bg、指定大小的cex,以
及指定文本颜色的text.col。指定horiz=TRUE将会水平放置图例,而不是垂直放置。关于图
例的更多细节,请参考help(legend)。这份帮助中给出的示例都特别有用。
让我们看看对药物数据作图的一个例子(代码清单3-3)。你将再次使用我们目前为止讲到的
许多图形功能。结果如图3-10所示。
代码清单3-3 依剂量对比药物A和药物B的响应情况
> dose <- c(20, 30, 40, 45, 60)
> drugA <- c(16, 20, 27, 40, 60)
> drugB <- c(15, 18, 25, 31, 40)
> opar <- par(no.readonly=TRUE)
> par(lwd=2, cex=1.5, font.lab=2)
> plot(dose, drugA, type="b", pch=15, lty=1, col="red", ylim=c(0, 60), main="Drug A vs. Drug B", xlab="Drug Dosage", ylab="Drug Response")
> lines(dose, drugB, type="b", pch=17, lty=2, col="blue")
> abline(h=c(30), lwd=1.5, lty=2, col="gray")
> library(Hmisc)
> minor.tick(nx=3, ny=3, tick.ratio=0.5)
> legend("topleft", inset=.05, title="Drug Type", c("A", "B"), lty=c(1,2), pch=c(15, 17), col=c("red", "blue"))
> par(opar)
图3-10的几乎所有外观元素都可以使用本章中讨论过的选项进行修改。除此之外,还有很多其他
方式可以指定想要的选项。最后一种需要研究的图形标注是向图形本身添加文本,请继续读下一节。
3.4.5 文本标注
我们可以通过函数text()和mtext()将文本添加到图形上。text()可向绘图区域内部添加
文本,而mtext()则向图形的四个边界之一添加文本。使用格式分别为:
text(location, "text to place", pos, ...)
mtext("text to place", side, line=n, ...)
常用选项列于表3-9中。
表3-9 函数text()和mtext()的选项
选 项 描 述
location 文本的位置参数。可为一对x,y坐标,也可通过指定location为locator(1)使用鼠标交互式地确
定摆放位置
pos 文本相对于位置参数的方位。1=下,2=左,3=上,4=右。如果指定了pos,就可以同时指定参数offset=
作为偏移量,以相对于单个字符宽度的比例表示
side 指定用来放置文本的边。1=下,2=左,3=上,4=右。你可以指定参数line=来内移或外移文本,随
着值的增加,文本将外移。也可使用adj=0将文本向左下对齐,或使用adj=1右上对齐
其他常用的选项有cex、col和font(分别用来调整字号、颜色和字体样式)。
除了用来添加文本标注以外,text()函数也通常用来标示图形中的点。我们只需指定一系
列的x, y坐标作为位置参数,同时以向量的形式指定要放置的文本。x、y和文本标签向量的长度
应当相同。下面给出了一个示例,结果如图3-11所示。
> attach(mtcars)
> plot(wt, mpg, main="Mileage vs. Car Weight", xlab="Weight", ylab="Mileage", pch=18, col="blue")
> text(wt, mpg, row.names(mtcars), cex=0.6, pos=4, col="red")
> detach(mtcars)
这里,我们针对数据框mtcars提供的32种车型的车重和每加仑汽油行驶英里数绘制了散点图。
函数text()被用来在各个数据点右侧添加车辆型号。各点的标签大小被缩小了40%,颜色为红色。
作为第二个示例,以下是一段展示不同字体族的代码:
opar <- par(no.readonly=TRUE)
par(cex=1.5)
plot(1:7, 1:7, type="n")
text(3, 3, "Example of default text")
text(4, 4, family="mono", "Example of mono-spaced text")
text(5, 5, family="serif", "Example of serif text")
par(opar)
在Windows系统中输出的结果如图3-12所示。这里为了获得更好的显示效果,我们使用par()
函数增大了字号。
本例所得结果因平台而异,因为不同系统中映射的常规字体、等宽字体和有衬线字体有所不
同。在你的系统上,结果看起来如何呢?
数学标注
最后,你可以使用类似于TeX中的写法为图形添加数学符号和公式。请参阅help(plotmath)
以获得更多细节和示例。要即时看效果,可以尝试执行demo(plotmath)。部分运行结果如图3-13
所示。函数plotmath()可以为图形主体或边界上的标题、坐标轴名称或文本标注添加数学符号。
同时比较多幅图形,我们通常可以更好地洞察数据的性质。所以,作为本章的结尾,下面讨
论将多幅图形组合为一幅图形的方法。
3.5 图形的组合
在R中使用函数par()或layout()可以容易地组合多幅图形为一幅总括图形。此时请不要担
心所要组合图形的具体类型,这里我们只关注组合它们的一般方法。后续各章将讨论每类图形的
绘制和解读问题。
你可以在par()函数中使用图形参数mfrow=c(nrows, ncols)来创建按行填充的、行数为
nrows、列数为ncols的图形矩阵。另外,可以使用nfcol=c(nrows, ncols)按列填充矩阵。
举例来说,以下代码创建了四幅图形并将其排布在两行两列中:
attach(mtcars)
opar <- par(no.readonly=TRUE)
par(mfrow=c(2, 2))
plot(wt, mpg, main="Scatterplot of wt vs. mpg")
plot(wt, disp, main="Scatterplot of wt vs disp")
hist(wt, main="Boxplot of wt")
boxplot(wt, main="Boxplot of wt")
par(opar)
detach(mtcars)
作为第二个示例,让我们依3行1列排布3幅图形。代码如下:
attach(mtcars)
opar <- par(no.readonly=TRUE)
par(mfrow=c(3,1))
hist(wt)
hist(mpg)
hist(disp)
par(opar)
detach(mtcars)
所得图形如图3-15所示。请注意,高级绘图函数hist()包含了一个默认的标题(使用main=""
可以禁用它,抑或使用ann=FALSE来禁用所有标题和标签)。
函数layout()的调用形式为layout(mat),其中的mat是一个矩阵,它指定了所要组合的
多个图形的所在位置。在以下代码中,一幅图被置于第1行,另两幅图则被置于第2行:
attach(mtcars)
layout(matrix(c(1,1,2,3), 2, 2, byrow=TRUE))
hist(wt)
hist(mpg)
hist(disp)
detach(mtcars)
结果如图3-16所示。
为了更精确地控制每幅图形的大小,可以有选择地在layout()函数中使用widths=和
heights=两个参数。其形式为:
widths = 各列宽度值组成的一个向量
heights = 各行高度值组成的一个向量
相对宽度可以直接通过数值指定,绝对宽度(以厘米为单位)可以通过函数lcm()来指定。
在以下代码中,我们再次将一幅图形置于第1行,两幅图形置于第2行。但第1行中图形的
高度是第2行中图形高度的三分之一。除此之外,右下角图形的宽度是左下角图形宽度的四分
之一:
attach(mtcars)
layout(matrix(c(1,1,2,3), 2, 2, byrow=TRUE), widths=c(3,1), heights=c(1,2))
hist(wt)
hist(mpg)
hist(disp)
detach(mtcars)
所得图形如图3-17所示。
如你所见,layout()函数能够让我们轻松地控制最终图形中的子图数量和摆放方式,以及
这些子图的相对大小。请参考help(layout)以了解更多细节。
图形布局的精细控制
可能有很多时候,你想通过排布或叠加若干图形来创建单幅的、有意义的图形,这需要有对
图形布局的精细控制能力。你可以使用图形参数fig=完成这个任务。代码清单3-4通过在散点图
上添加两幅箱线图,创建了单幅的增强型图形。结果如图3-18所示。
代码清单3-4 多幅图形布局的精细控制
opar <- par(no.readonly=TRUE)
par(fig=c(0, 0.8, 0, 0.8))
plot(mtcars$wt, mtcars$mpg, xlab="Miles Per Gallon", ylab="Car Weight")
par(fig=c(0, 0.8, 0.55, 1), new=TRUE)
boxplot(mtcars$wt, horizontal=TRUE, axes=FALSE)
par(fig=c(0.65, 1, 0, 0.8), new=TRUE)
boxplot(mtcars$mpg, axes=FALSE)
mtest("Enhanced Scatterplot", side=3, outer=TRRE, line=-3)
par(opar)
要理解这幅图的绘制原理,请试想完整的绘图区域:左下角坐标为(0,0),而右上角坐标为
(1,1)。图3-19是一幅示意图。参数fig=的取值是一个形如c(x1, x2, y1, y2)的数值向量。
图3-19 使用图形参数fig=指定位置
第一个fig=将散点图设定为占据横向范围0~0.8,纵向范围0~0.8。上方的箱线图横向占据
图灵社区会员 matrixvirus(matrixvirus@163.com) 专享 尊重版权
64 第3 章 图形初阶
0~0.8,纵向0.55~1。右侧的箱线图横向占据0.65~1,纵向0~0.8。fig=默认会新建一幅图形,所
以在添加一幅图到一幅现有图形上时,请设定参数new=TRUE。
我将参数选择为0.55而不是0.8,这样上方的图形就不会和散点图拉得太远。类似地,我选择
了参数0.65以拉近右侧箱线图和散点图的距离。你需要不断尝试找到合适的位置参数。
注意 各独立子图所需空间的大小可能与设备相关。如果你遇到了“Error in plot.new(): figure
margins too large”这样的错误,请尝试在整个图形的范围内修改各个子图占据的区域位
置和大小。
你可以使用图形参数fig=将若干图形以任意排布方式组合到单幅图形中。稍加练习,你就
可以通过这种方法极其灵活地创建复杂的视觉呈现。
3.6 小结
本章中,我们回顾了创建图形和以各种格式保存图形的方法。本章的主体则是关于如何修改
R绘制的默认图形,以得到更加有用或更吸引人的图形。你学习了如何修改一幅图形的坐标轴、
字体、绘图符号、线条和颜色,以及如何添加标题、副标题、标签、文本、图例和参考线,看到
了如何指定图形和边界的大小,以及将多幅图形组合为实用的单幅图形。
本章的焦点是那些可以应用于所有图形的通用方法(第16章的lattice图形是一个例外)。后续
各章将着眼于特定的图形类型。例如,第7章介绍了对单变量绘图的各种方法;对变量间关系绘
图的方法将于第11章讨论;在第16章中,我们则讨论高级的绘图方法,包括lattice图形(可以分
水平展示变量间的关系)和交互式图形。交互式图形能让你使用鼠标动态探索数据中的关系。
在其他各章中,我们将会讨论对于某些统计方法来说特别实用的数据可视化方法。图形是现
代数据分析的核心组成部分,所以我将尽力将它们整合到各类统计方法的讨论中。
在前一章中,我们讨论了一系列输入或导入数据到R中的方法。遗憾的是,现实数据极少以
直接可用的格式出现。下一章,我们将关注如何将数据转换或修改为更有助于分析的形式。