使用图形
在本章中,我们将讨论处理图形的一般方法。我们首先探讨如何创建和保存图形,然后关注如何修改那些存在于所有图形中的特征,包括图形的标题、坐标轴、标签、颜色、线条、符号和文本标注。我们的焦点是那些可以应用于所有图形的通用方法。(在后续各章,我们将关注特定类型的图形。)最后,我们将研究组合多幅图形为单幅图形的各种方法。
R是一个惊艳的图形构建平台。这里我特意使用了“构建”一词。在通常的交互式会话中,你可以通过逐条输入语句构建图形,逐渐完善图形特征,直至得到想要的效果。
考虑以下五行代码:
attach(mtcars)
plot(wt, mpg)
abline(lm(mpg~wt))
title("Regression of MPG on Weight")
detach(mtcars)
首句绑定了数据框 mtcars 。第二条语句打开了一个图形窗口并生成了一幅散点图,横轴表示车身重量,纵轴为每加仑汽油行驶的英里数。第三句向图形添加了一条最优拟合曲线。第四句添加了标题。最后一句为数据框解除了绑定。在R中,图形通常都是以这种交互式的风格绘制的(参见图3-1)。
可以通过代码或图形用户界面来保存图形。要通过代码保存图形,将绘图语句夹在开启目标图形设备的语句和关闭目标图形设备的语句之间即可。例如,以下代码会将图形保存到当前工作目录中名为 mygraph.pdf 的PDF文中:
pdf("myfirstpdf.pdf")
attach(mtcars)
plot(wt,mpg)
abline(lm(mpg~wt))
title("Regression of ...")
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()
一个简单的例子
让我们从表3-1中给出的假想数据集开始。它描述了病人对两种药物五个剂量水平上的响应
情况。
使用以下代码可以创建一幅描述药物A的剂量和响应关系的图形:
pdf("pdf1.pdf")
dose = c(20,30,40,45,60)
drugA= c(16,20,27,40,60)
drugB= c(15,18,25,31,40)
plot(dose,drugA,type = "b")
dev.off()
plot() 是R中为对象作图的一个泛型函数(它的输出将根据所绘制对象类型的不同而变化)。本例中, plot(x, y, type="b") 将 x 置于横轴,将 y 置于纵轴,绘制点集(x, y),然后使用线段将其连接。选项 type="b" 表示同时绘制点和线。使用 help(plot) 可以查看其他选项。结果如图3-2所示。
图形参数
我们可以通过修改称为图形参数的选项来自定义一幅图形的多个特征(字体、颜色、坐标轴、标题)。
修改图形参数的一种方法是通过函数 par() 来指定这些选项。以这种方式设定的参数值除非被再次修改,否则将在会话结束前一直有效。其调用格式为 par(optionname=value,optionname=name,…) 。不加参数地执行 par() 将生成一个含有当前图形参数设置的列表。添加参数 no.readonly=TRUE 可以生成一个可以修改的当前图形参数列表。
继续我们的例子,假设你想使用实心三角而不是空心圆圈作为点的符号,并且想用虚线代替实线连接这些点。你可以使用以下代码完成修改:
opar <- par(no.readonly=TURE)# 先备份当前参数
par(lty=2, pch=17)
plot(dose ,drugA, type="b")
par(opar)# 恢复当前参数,使得par不对其他作图产生影响
结果如图3-3所示。
首个语句复制了一份当前的图形参数设置。第二句将默认的线条类型修改为虚线( lty=2 )并将默认的点符号改为了实心三角( pch=17 )。然后我们绘制了图形并还原了原始设置。线条类型和符号将在3.3.1节中详述。
指定图形参数的第二种方法是为高级绘图函数直接提供 optionname=value 的键值对。这种
情况下,指定的选项仅对这幅图形本身有效。你可以通过代码:
plot(dose ,drugA, type="b",lty=2, pch=17)
来生成与上图相同的图形。
符号和线条
如你所见,可以使用图形参数来指定绘图时使用的符号和线条类型。相关参数如表3-2所示。
选项 pch= 用于指定绘制点时使用的符号。可能的值如图3-4所示。
对于符号21~25,你还可以指定边界颜色( col= )和填充色( bg= )。
选项 lty= 用于指定想要的线条类型。可用的值如图3-5所示。
颜色
R中有若干和颜色相关的参数。表3-3列出了一些常用参数。
函数 colors() 可以返回所有可用颜色的名称。参见R Color Chart。R中也有多种用于创建连续型颜色向量的函数,包括 rainbow() 、 heat.colors() 、 terrain.colors() 、 topo.colors()以及 cm.colors() 。举例来说, rainbow(10) 可以生成10种连续的“彩虹型”颜色。多阶灰度色可使用 gray() 函数生成。这时要通过一个元素值为0和1之间的向量来指定各颜色的灰度。gray(0:10/10) 将生成10阶灰度色。
mycolors1=rainbow(10)
mycolors2=gray(0:10/10)
pdf("piechart1.pdf")
pie(rep(1,10),labels = mycolors1,col=mycolors1)
pie(rep(1,10),labels = mycolors2,col=mycolors2)
dev.off()
[图片上传失败...(image-84d70c-1577187273408)]
文本属性
图形参数同样可以用来指定字号、字体和字样。表3-4阐释了用于控制文本大小的参数。字体族和字样可以通过字体选项进行控制(见表3-5)。
让我们使用最近学到的选项来强化之前的简单图形示例。
pdf("test1.pdf")
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")
par(opar)
dev.off()
图形尺寸与边界尺寸
最后,可以使用表3-6列出的参数来控制图形尺寸和边界大小。
添加文本、自定义坐标轴和图例
除了图形参数,许多高级绘图函数(例如 plot 、 hist 、 boxplot )也允许自行设定坐标轴和文本标注选项。举例来说,以下代码在图形上添加了标题( main )、副标题( sub )、坐标轴标签( xlab 、 ylab )并指定了坐标轴范围( xlim 、 ylim )。结果如图3-8所示。
pdf("test2.pdf")
dose <- c(20, 30, 40, 45, 60)
drugA <- c(16, 20, 27, 40, 60)
drugB <- c(15, 18, 25, 31, 40)
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 = "Doseage", ylab = "Drug Response",
xlim = c(0, 60), ylim = c(0, 70))
dev.off()
药物A剂量和响应的折线图。添加了标题、副标题和自定义的坐标轴:
再次提醒,并非所有函数都支持这些选项。请参考相应函数的帮助以了解其可以接受哪些选项。从更精细的控制和模块化的角度考虑,你可以使用本节余下部分描述的函数来控制标题、坐标轴、图例和文本标注的外观。
标题
可以使用 title() 函数为图形添加标题和坐标轴标签。调用格式为:
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)
坐标轴
你可以使用函数 axis() 来创建自定义的坐标轴,而非使用R中的默认坐标轴。其格式为:
axis(side, at =, labels =, pos=, lty=, col=, las=, tck=, ...)
各参数已详述于表3-7中。
创建自定义坐标轴时,你应当禁用高级绘图函数自动生成的坐标轴。参数 axes=FALSE 将禁用全部坐标轴(包括坐标轴框架线,除非你添加了参数 frame.plot=TRUE )。参数 xaxt="n" 和yaxt="n" 将分别禁用X轴或Y轴(会留下框架线,只是去除了刻度)。代码清单3-2中是一个稍显笨拙和夸张的例子,它演示了我们到目前为止讨论过的各种图形特征。结果如图3-9所示。
# 生成数据
pdf("pdf.pdf")
x <- c(1: 10)
y <- x
z <- 10/x
opar <- par(no.readonly = TRUE)
# 修改边界大小
par(mar = c(5, 4, 4, 8) + 0.1)
# 绘制x对y的图形
plot(x, y, type = "b", pch = 21, col = "red", yaxt = "n", lty = 3, ann = FALSE)
# 添加x对1/x的直线
lines(x, z, type = "b", pch = 22, col = "blue", 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.01)
# 添加文本
mtext("y = 10/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)
dev.off()
各种坐标轴选项的演示:
到目前为止,我们已经讨论过代码清单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.ration=n)
来添加次要刻度线。其中 nx 和 ny 分别指定了X轴和Y轴每两条主刻度线之间通过次要刻度线划分得到的区间个数。 tick.ratio 表示次要刻度线相对于主刻度线的大小比例。当前的主刻度线长度可以使用 par("tck") 获取。举例来说,下列语句将在X轴的每两条主刻度线之间添加1条次要添加标题和文本刻度线,并在Y轴的每两条主刻度线之间添加2条次要刻度线:
library(Hmisc)
minor.tick(nx=2, ny=3, tick.ration=0.5)
次要刻度线的长度将是主刻度线的一半:
(然而并不是预想的那样,有点奇怪╥﹏╥)
参考线
函数 abline() 可以用来为图形添加参考线。
abline(h=yvalues, v=xvalues)
函数 abline() 中也可以指定其他图形参数(如线条类型、颜色和宽度)。举例来说:
abline(h=c(1,5,7), col="blue")
在y为1、5、7的位置添加了水平实线。
图例
当图形中包含的数据不止一组时,图例可以帮助你辨别出每个条形、扇形区域或折线各代表哪一类数据。我们可以使用函数 legend() 来添加图例(果然不出所料)。其使用格式为:
lengend(location, title, legend, ...)
常用选项详述于表3-8中。
其他常用的图例选项包括用于指定盒子样式的 bty 、指定背景色的 bg 、指定大小的 cex ,以及指定文本颜色的 text.col 。指定 horiz=TRUE 将会水平放置图例,而不是垂直放置。关于图例的更多细节,请参考 help(legend) 。这份帮助中给出的示例都特别有用。
让我们看看对药物数据作图的一个例子(代码清单3-3)。你将再次使用我们目前为止讲到的许多图形功能。结果如图3-10所示。
# 创建数据
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",
legend = c("A", "B"), lty = c(1, 2),
pch = c(15, 17), col = c("red", "blue"))
par(opar)
图3-10的几乎所有外观元素都可以使用本章中讨论过的选项进行修改。除此之外,还有很多其他方式可以指定想要的选项。最后一种需要研究的图形标注是向图形本身添加文本,请继续读下一节。
文本标注
我们可以通过函数 text() 和 mtext() 将文本添加到图形上。 text() 可向绘图区域内部添加文本,而 mtext() 则向图形的四个边界之一添加文本。使用格式分别为:
text(location, "text to place", pos, ...)
mtext("text to place", side, line=n, ...)
常用选项列于表3-9中。
除了用来添加文本标注以外, text() 函数也通常用来标示图形中的点。我们只需指定一系列的x, y坐标作为位置参数,同时以向量的形式指定要放置的文本。x、y和文本标签向量的长度应当相同。下面给出了一个示例,结果如图3-11所示。
这里,我们针对数据框 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() 可以为图形主体或边界上的标题、坐标轴名称或文本标注添加数学符号。
同时比较多幅图形,我们通常可以更好地洞察数据的性质。所以,作为本章的结尾,下面讨论将多幅图形组合为一幅图形的方法。
图形的组合
在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="Histogram 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行。但第1行中图形的高度是第2行中图形高度的三分之一。除此之外,右下角图形的宽度是左下角图形宽度的四分之一:
要理解这幅图的绘制原理,请试想完整的绘图区域:左下角坐标为(0,0),而右上角坐标为(1,1)。图3-19是一幅示意图。参数 fig= 的取值是一个形如 c(x1, x2, y1, y2) 的数值向量。
图3-19 使用图形参数 fig= 指定位置第一个 fig= 将散点图设定为占据横向范围0-0.8,纵向范围0-0.8。上方的箱线图横向占据0-0.8,纵向0.55-1。右侧的箱线图横向占据0.65-1,纵向0-0.8。 fig= 默认会新建一幅图形,所以在添加一幅图到一幅现有图形上时,请设定参数 new=TRUE 。
我将参数选择为0.55而不是0.8,这样上方的图形就不会和散点图拉得太远。类似地,我选择了参数0.65以拉近右侧箱线图和散点图的距离。你需要不断尝试找到合适的位置参数。