首先介绍 R 语言绘图的基本方法,随后讲解如何定制图表的各个元素(标题、轴、标签、刻度线、辅助线、图例等),最后关注如何定制一组图和混合图。
本章包含了几乎所有 R 绘图所需的一般知识,但不包含对 ggplot2 (一个专业于绘图的 R 包)绘图的介绍。
使用的 R 版本是 3.5.2
研究病人对两种药物 A and B 的不同剂量的反应,首先生成数据:
# 药物剂量
dose <- c(20, 30, 40, 50, 60)
drugA <- c(16, 20, 27, 40, 60)
drugB <- c(15, 18, 25, 31, 40)
dose_table <- data.frame(dose, drugA, drugB)
| dose | drugA | drugB |
|---|---|---|
| 20 | 16 | 15 |
| 30 | 20 | 18 |
| 40 | 27 | 25 |
| 50 | 40 | 31 |
| 60 | 60 | 40 |
绘制散点图并连线:
plot() 方法type="b" 意思是同时绘制点和线。plot(dose, drugA, type="b")
Use command help(plot) to learn more about plot()。
可以将图表保存为 PNG, JPEG, PDF, PSF 等格式。
png(filename = "my_plot.png")
jpeg(filename = "my_plot.jpg")
pdf(file="my_plot.pdf")
postscript(file = "my_plot.ps")
par() 函数使用 par() 查看和配置图表参数。
no.readonly = TRUE 查看可编辑的图标参数opar: Original params 来备份初始配置opar <- par(no.readonly = TRUE)
opar[1:2]
## $xlog
## [1] FALSE
##
## $ylog
## [1] FALSE
# lty: change line type to dashed (=2), pch: change symbol to solid triangle (=17)
par(lty=2, pch=17)
plot(dose, drugA, type="b")
# 恢复初始配置
par(opar)
plot(dose, drugA, type = "b", lty=2, pch=17)
| Parameter | Description |
|---|---|
| pch | 点的样式 |
| cex | 点的大小倍数 |
| lty | 线的样式 |
| lwd | 线的宽度倍数 |
col 用于线图或饼图,可以传入向量,R 将循环使用其中的颜色col.axis 轴文本col.lab 轴标签col.main 主标题col.sub 副标题fg 前景色bg 背景色支持各种颜色格式:col=1, col="white", col="#FFFFFF", col=rgb(1,1,1) or col=hsv(0,0,1) is OK.
colors() 返回所有可用颜色名rainbow(), heat.colors(), terrain.colors, topo.colors() and cm.colors() 可以生成系列色RColorBrewer 包可以生成颜色raindow() 函数n <- 10
mycolors <- rainbow(10)
pie(rep(1, n), labels = mycolors, col = mycolors)
gray() 函数n <- 10
mygrays <- gray(0:n/n)
pie(rep(1, n), labels = mygrays, col = mygrays)
library(RColorBrewer)
display.brewer.all()
n <- 7
mycolors <- brewer.pal(n, "RdYlGn")
barplot(rep(1,n), col=mycolors)
图表中的文字样式也可以进行类似配置。
在 par() 中传入以下参数和值,或直接传入绘图方法中。
cex 基础文字大小倍数cex.axis 轴文字字号倍数,相对 cex,下同cex.lab 轴标签字号倍数cex.main 主标题字号倍数cex.sub 副标题字号倍数font 基础文字粗细,=1 正常,=2 加粗,=3 意大利斜体,=4 粗斜体,=5点阵字体 (Adobe)font.axis 轴文字font.lab 轴标签font.main 主标题font.sub 副标题ps Font point sizefamily 字体Windows 中字体名和具体名称之间有一个 map 的对应关系。
使用已知对应字体,可以直接将 family 值设置为字体名:
par(family="serif")
使用新字体,需要用 windowsFont() 方法构建 map 关系:
windowsFonts(
A=windowsFont("Arial Black"),
B=windowsFont("Bookman Old Style"),
C=windowsFont("Comic Sans MS")
)
# 将图表字体设置为 Arial Black
par(family = "A")
可以使用 names() 方法查看可用字体。
# PDF 字体
names(pdfFonts())
# 生成 pdf
pdf(file="myplot.pdf", family = "fontname")
# PostScript Format 字体
names(postscriptFonts())
# 生成 PSF
postscript(file = "myplot.ps", family = "fontname")
pin 传入向量,分别为宽和高mai margin,图表的外边距,单位是 inches,顺序是 c(bottom, left, top, right)mar margin,图表的外边距,单位是行,顺序同上# 4 inch 宽,3 inch 高,上下边距为 1 inch,0.2 inch 右边距,0.5 inch 左边距
par(pin = c(4,3), mai = c(1, .5, 1, .2))
配置:
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)
# 1
par(pin=c(2,3))
# 2
par(lwd=2, cex=1.5)
# 3
par(cex.axis=.75, font.axis=3)
# 4-1
plot(dose, drugA, type="b", pch=19, lty=2, col="red")
# 4-2
plot(dose, drugB, type="b", pch=23, lty=6, col="blue", bg="green")
par(opar)
往 plot() 中传入更多参数,可以更好地定制图表。
绘制药物 A 的剂量与病人反应关系的图像:
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))
frame.plot=FALSE:不绘制全部坐标轴,= TRUE 则绘制所有轴,形成箱状如上图。ann=FALSE :使用默认标题和轴标签样式。axes=FALSE :绘制默认轴。yaxt="n" 和 xaxt="n" 表示不显示轴刻度,但是显示轴。并不是所有绘图函数都支持这些参数,需要参考 help()。
使用 title() 定制标题,基本语法是:
plot.new()
title(main="main title", sub="subtitle",
xlab="x-axis label", ylab="y-axis label")
它也可被传入图表的配置参数.
plot.new()
title(main="My Title", col.main="red",
sub="My Subtitle", col.sub="blue",
xlab="My X label", ylab="My Y label",
col.lab="green", cex.lab=0.75)
使用 axis() 方法定制坐标轴,基本语法是:
axis(side, at=, labels=, pos=, lty=, col=, las=, tck=, ...)
side 指定配置的目标轴(根据轴在图表的哪一侧),1 底部,2 左侧,3 顶部,4 右侧at 在哪里画刻度线,传入数字型向量labels 刻度线处的标记文字,传入字符型向量。如果是 NULL,将使用刻度线处的数值(也即 at= 的值)。pos 与另一条轴的哪个值处相交lty 线样式col 线和刻度线颜色las label和轴平行(=0)或和轴垂直(=2)tck 刻度线的长度比例,为负在轴外,为正在轴内,=0 隐藏,=1 即为网格线。繁琐但全面 cover 的示例:
lines() 方法绘制线图。mtext() 方法添加文字。# Specifies data
x <- c(1:10)
y <- x
z <- 10/x
opar <- par(no.readonly=TRUE)
# Increases margins
par(mar=c(5, 4, 4, 8) + 0.1)
# Plots x vs. y, suppressing annotations
plot(x, y, type="b",
pch=21, col="red",
yaxt="n", lty=3, ann=FALSE)
# Adds an x versus 1/x line
lines(x, z, type="b", pch=22, col="blue", lty=2)
# Draws the axes
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=-.01)
# Adds titles and text
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)
添加无标签的“小刻度”需要 Hmisc 包的 minor.tick() 方法,例子见下一小节的示例图。
使用 abline(h=yvalues, v=xvalues) 添加辅助线.
例如如下代码:
# 1
abline(h=c(1,5,7))
# 2
abline(v=seq(1, 10, 2), lty=2, col="blue")
使用 legend() 方法配置图例和其样式。
legend(location, title, legend, ...)
location 图例位置,语法可以是以下任意一种
x,y 上左侧为原点的距离坐标系locator(1) 鼠标位置bottom, bottomleft, left, topleft, top, topright, right, bottomright, center 在图内的某个方位
inset= 参数在方位基础上位移一段距离title 图例标题,字符串 (optional)legend 图例标签,字符串向量... 其他图表参数,比如col=颜色,pch=点样式,lwd=,lty=线样式,fill=图例盒子的颜色,都传入向量horiz=TRUE 将图例设置成水平排列而不是垂直排列bty 图例盒子类型,bg背景色,cex字号,text.color文字颜色See help(legend) for more details.
对比药物 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)
# Increases line, text, symbol, and label font size
par(lwd=2, cex=1.5, font.lab=2)
# Generates the graph
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")
# Adds minor tick marks
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)
使用 text() 或 mtext() 为图表添加文字。
text() 在图中添加文字,尤其用于标识某个特殊点
text(location, "text to place", pos, ...)mtext() 在外边距的空白添加文字
mtext("text to place", side, line=n, ...)二者共同的参数:
location 位置。值为 x,y 表示坐标位置,或 locator(1) 表示鼠标位置pos 相对于 location 参数值的位置. 1 = below, 2 = left, 3 = above, 4 = right.side 放置在外边距的哪一侧,1 = bottom, 2 = left, 3 = top, 4 = right。
line 参数还可以配置文字与坐标轴的距离adj=0 左下角对齐,adj=1右上角对齐cex,颜色col和粗细font例子:
attach(datasets::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(datasets::mtcars)
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)
可以往图表中添加数学表达式,规则见 help(plotmath).
使用 plotmath() 方法可以向图表的组件或在图中添加数学公式。
使用 par() 或 layout() 方法可以混合图表。
par() 里的参数
mfrow=c(nrows, ncols) 按行排列,生成 nrow 行 nrow 列的图表阵列mfcol=c(nrows, ncols) 按列排列par() 函数例子:
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)
注意上述代码中 hist() 方法,即使不传入 main 参数,图的默认标题也会是 “Histagram of xxx”.
layout() 函数layout 接收一个矩阵 (matrix),根据矩阵规模和矩阵内的数字来排列图表。
可选参数: * widths 列宽,传入向量 * heights 行高,传入向量 * 相对长度使用数字型向量,绝对长度使用 lcm() 值向量
例子 1:不设置列宽和行高的基本图组
attach(mtcars)
layout(
matrix(c(1,1,2,3), 2, 2, byrow=TRUE)
)
hist(wt)
hist(mpg)
hist(disp)
detach(mtcars)
例子 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)
See help(layout) for more details.
使用图表配置参数 fig 将多个图合并到同一张图里,定制更高级的图表。
fig 的参数:
* 规定一个坐标系 `(x,y)`,左下角 `(0,0)`,右上角 `(1,1)`
* 第一个参数是向量 `c(x1, x2, y1, y2)`,意为图形的横坐标从 x1 到 x2,纵坐标从 y1 到 y2
* 参数 `new=TRUE` ,表示在旧图上应用一个新图。
例子:在点阵图的上方和右侧增加箱线图
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")
# Adds a box plot above
par(fig=c(0, 0.8, 0.55, 1), new=TRUE)
boxplot(mtcars$wt, horizontal=TRUE, axes=FALSE)
# Adds a box plot to the right
par(fig=c(0.6, 1, 0, 0.8), new=TRUE)
boxplot(mtcars$mpg, axes=FALSE)
mtext("Enhanced Scatterplot", side=3, outer=TRUE, line=-3)
par(opar)
为什么箱线图和点阵图fig参数里向量的横纵坐标参数加起来超过了 1 ?
因为向量参数 c(x1,x2,y1,y2) 是指示一个绘图范围,所以允许重合。
报错 Error in plot.new(): figure margins too large 的解决办法也是调整向量参数。
示例代码的向量参数可以让箱线图更靠近点阵图,需要经过不断尝试,找到最好的配置。