10.1 绘图基本要素

10.1.1 点线

点和线是最常见的画图元素,在 plot 函数中,分别用参数 pchlty 来设定类型,点的大小、线的宽度分别用参数 cexlwd 来指定,颜色由参数 col 设置。参数 type 不同的值设置如下,p 显示点,l 绘制线,b 同时绘制空心点,并用线连接,c 只有线,o 在线上绘制点,sS 点线连接绘制阶梯图,h 绘制类似直方图一样的垂线,最后 n 表示什么也不画。

点 points 、线 grid 背景线 abline lines rug 刻度线(线段segments、箭头arrows)、

## -------- Showing all the extra & some char graphics symbols ---------
pchShow <-
  function(extras = c("*", ".", "o", "O", "0", "+", "-", "|", "%", "#"),
             cex = 2, ## good for both .Device=="postscript" and "x11"
             col = "red3", bg = "gold", coltext = "brown", cextext = 1.2,
             main = paste(
               "plot symbols :  points (...  pch = *, cex =",
               cex, ")"
             )) {
    nex <- length(extras)
    np <- 26 + nex
    ipch <- 0:(np - 1)
    k <- floor(sqrt(np))
    dd <- c(-1, 1) / 2
    rx <- dd + range(ix <- ipch %/% k)
    ry <- dd + range(iy <- 3 + (k - 1) - ipch %% k)
    pch <- as.list(ipch) # list with integers & strings
    if (nex > 0) pch[26 + 1:nex] <- as.list(extras)
    plot(rx, ry, type = "n", axes = FALSE, xlab = "", ylab = "", main = main)
    abline(v = ix, h = iy, col = "lightgray", lty = "dotted")
    for (i in 1:np) {
      pc <- pch[[i]]
      ## 'col' symbols with a 'bg'-colored interior (where available) :
      points(ix[i], iy[i], pch = pc, col = col, bg = bg, cex = cex)
      if (cextext > 0) {
        text(ix[i] - 0.3, iy[i], pc, col = coltext, cex = cextext)
      }
    }
  }

pchShow()
不同的 pch 参数值

图 10.1: 不同的 pch 参数值

## ------------ test code for various pch specifications -------------
# Try this in various font families (including Hershey)
# and locales.  Use sign = -1 asserts we want Latin-1.
# Standard cases in a MBCS locale will not plot the top half.
TestChars <- function(sign = 1, font = 1, ...) {
  MB <- l10n_info()$MBCS
  r <- if (font == 5) {
    sign <- 1
    c(32:126, 160:254)
  } else if (MB) 32:126 else 32:255
  if (sign == -1) r <- c(32:126, 160:255)
  par(pty = "s")
  plot(c(-1, 16), c(-1, 16),
    type = "n", xlab = "", ylab = "",
    xaxs = "i", yaxs = "i",
    main = sprintf("sign = %d, font = %d", sign, font)
  )
  grid(17, 17, lty = 1)
  mtext(paste("MBCS:", MB))
  for (i in r) try(points(i %% 16, i %/% 16, pch = sign * i, font = font, ...))
}
TestChars()
pch 支持的字符

图 10.2: pch 支持的字符

try(TestChars(sign = -1))
pch 支持的字符

图 10.3: pch 支持的字符

TestChars(font = 5) # Euro might be at 160 (0+10*16).
pch 支持的字符

图 10.4: pch 支持的字符

# macOS has apple at 240 (0+15*16).
try(TestChars(-1, font = 2)) # bold
pch 支持的字符

图 10.5: pch 支持的字符

x <- 0:12
y <- sin(pi / 5 * x)
par(mfrow = c(3, 3), mar = .1 + c(2, 2, 3, 1))
for (tp in c("p", "l", "b", "c", "o", "h", "s", "S", "n")) {
  plot(y ~ x, type = tp, main = paste0("plot(*, type = \"", tp, "\")"))
  if (tp == "S") {
    lines(x, y, type = "s", col = "red", lty = 2)
    mtext("lines(*, type = \"s\", ...)", col = "red", cex = 0.8)
  }
}
不同的 type 参数值

图 10.6: 不同的 type 参数值

颜色 col 连续型和离散型

线帽/端和字体的样式

# 合并为一个图 三条粗横线 横线上三种字形
plot(c(1, 20), c(1, 20), type = "n", ann = FALSE)
lines(x = c(5, 15), y = c(5, 5), lwd = 15, lend = "round")
text(10, 5, "Hello, Helvetica", cex = 1.5, family = "sans", pos = 1, offset = 1.5)
text(5, 5, "sans", cex = 1.5, family = "sans", pos = 2, offset = .5)
text(15, 5, "lend = round", pos = 4, offset = .5)

lines(x = c(5, 15), y = c(10, 10), lwd = 15, lend = "butt")
text(10, 10, "Hello, Helvetica", cex = 1.5, family = "mono", pos = 1, offset = 1.5)
text(5, 10, "mono", cex = 1.5, family = "mono", pos = 2, offset = .5)
text(15, 10, "lend = butt", pos = 4, offset = .5)

lines(x = c(5, 15), y = c(15, 15), lwd = 15, lend = "square")
text(10, 15, "Hello, Helvetica", cex = 1.5, family = "serif", pos = 1, offset = 1.5)
text(5, 15, "serif", cex = 1.5, family = "serif", pos = 2, offset = .5)
text(15, 15, "lend = square", pos = 4, offset = .5)
不同的线端样式

图 10.7: 不同的线端样式

lend:线端的样式,可用一个整数或字符串指定:

  • 0 或 “round” 圆形(默认)
  • 1 或 “butt” 对接形
  • 2 或 “square” 方形

10.1.2 区域

矩形,多边形,曲线交汇出来的区域 面(矩形rect,多边形polygon)、路径 polypath 面/多边形 rect 颜色填充

# From the manual
ch.col <- c(
  "rainbow(n, start=.7, end=.1)",
  "heat.colors(n)",
  "terrain.colors(n)",
  "topo.colors(n)",
  "cm.colors(n)"
) # 选择颜色
n <- 16
nt <- length(ch.col)
i <- 1:n
j <- n / nt
d <- j / 6
dy <- 2 * d
plot(i, i + d,
  type = "n",
  yaxt = "n",
  ylab = "",
  xlab = "",
  main = paste("color palettes; n=", n)
)
for (k in 1:nt) {
  rect(i - .5, (k - 1) * j + dy, i + .4, k * j,
    col = eval(parse(text = ch.col[k]))
  ) # 咬人的函数/字符串解析为/转函数
  text(2 * j, k * j + dy / 4, ch.col[k])
}
rect 函数画长方形

图 10.8: rect 函数画长方形

clip(x1, x2, y1, y2) 在用户坐标中设置剪切区域

x <- rnorm(1000)
hist(x, xlim = c(-4, 4))
usr <- par("usr")
clip(usr[1], -2, usr[3], usr[4])
hist(x, col = "red", add = TRUE)
clip(2, usr[2], usr[3], usr[4])
hist(x, col = "blue", add = TRUE)

do.call("clip", as.list(usr)) # reset to plot region
my.col <- function(f, g, xmin, xmax, col, N = 200,
                   xlab = "", ylab = "", main = "") {
  x <- seq(xmin, xmax, length = N)
  fx <- f(x)
  gx <- g(x)
  plot(0, 0,
    type = "n",
    xlim = c(xmin, xmax),
    ylim = c(min(fx, gx), max(fx, gx)),
    xlab = xlab, ylab = ylab, main = main
  )
  polygon(c(x, rev(x)), c(fx, rev(gx)),
    col = "#EA4335", border = 0
  )
  lines(x, fx, lwd = 3, col = "#34A853")
  lines(x, gx, lwd = 3, col = "#4285f4")
}
my.col(function(x) x^2, function(x) x^2 + 10 * sin(x),
  -6, 6,
  main = "The \"polygon\" function"
)
区域重叠 polygon 函数

图 10.9: 区域重叠 polygon 函数

各种符号 10.10

plot(0, 0,
  xlim = c(1, 5), ylim = c(-.5, 4),
  axes = F,
  xlab = "", ylab = ""
)
for (i in 0:4) {
  for (j in 1:5) {
    n <- 5 * i + j
    points(j, i,
      pch = n,
      cex = 3
    )
    text(j, i - .3, as.character(n))
  }
}
cex 支持的符号

图 10.10: cex 支持的符号

点、线、多边形和圆聚集在图 10.11

# https://jeroen.github.io/uros2018/#23
plot.new()
plot.window(xlim = c(0, 100), ylim = c(0, 100))
polygon(c(10, 40, 80), c(10, 80, 40), col = "hotpink")
text(40, 90, labels = "My drawing", col = "navyblue", cex = 3)
symbols(c(70, 80, 90), c(20, 50, 80),
  circles = c(10, 20, 10),
  bg = c("#4285f4", "#EA4335", "red"), add = TRUE, lty = "dashed"
)
多边形和符号元素

图 10.11: 多边形和符号元素

在介绍各种统计图形之前,先介绍几个绘图函数 plottext 还有 par 参数设置, 作为最简单的开始,尽量依次介绍其中的每个参数的含义并附上图形对比。

y <- x <- 1:4
plot(x, y, ann = F, col = "blue", pch = 16)
text(x, y,
  labels = c("1st", "2nd", "3rd", "4th"),
  col = "red", pos = c(3, 4, 4, 1), offset = 0.6
)
ahat <- "sigma"
# title(substitute(hat(a) == ahat, list(ahat = ahat)))
title(bquote(hat(a) == .(ahat)))
pos 位置参数

图 10.12: pos 位置参数

其中 labels, pos 都是向量化的参数

10.1.3 参考线

矩形网格线是用做背景参考线的,常常是淡灰色的细密虚线,plot 函数的 panel.first 参数和 grid 函数常用来画这种参考线

# modified from https://yihui.name/cn/2018/02/cohen-s-d/
n <- 30 # 样本量(只是一个例子)
x <- seq(0, 12, 0.01)
par(mar = c(4, 4, 0.2, 0.1))
plot(x / sqrt(n), 2 * (1 - pt(x, n - 1)),
  xlab = expression(d = x / sqrt(n)),
  type = "l", panel.first = grid()
)
abline(v = c(0.01, 0.2, 0.5, 0.8, 1.2, 2), lty = 2)
添加背景参考线

图 10.13: 添加背景参考线

10.1.4 坐标轴

图形控制参数默认设置下 par 通常的一幅图形,改变坐标轴标签是很简单的

x <- 1:100
y <- runif(100, -2, 2)
plot(x, y)

plot(x, y, xlab = "Index", ylab = "Uniform draws")

改变坐标轴标签和标题

op <- par(no.readonly = TRUE) # 保存默认的 par 设置
par(cex.lab = 1.5, cex.axis = 1.3)
plot(x, y, xlab = "Index", ylab = "Uniform draws")

# 设置更大的坐标轴标签内容
par(mar = c(6, 6, 3, 3), cex.axis = 1.5, cex.lab = 2)
plot(x, y, xlab = "Index", ylab = "Uniform draws")

使用 axis 函数可以更加精细地控制坐标轴

par(op) # 恢复默认的 par 设置
plot(x, y, xaxt = "n") # 去掉 x 轴
axis(side = 1, at = c(5, 50, 100)) # 添加指定的刻度标签

指定刻度标签的内容

plot(x, y, yaxt = "n")
axis(side = 2, at = c(-2, 0, 2), labels = c("Small", "Medium", "Big"))

控制刻度线和轴线和刻度标签

plot(x, y)
axis(side = 3, at = c(5, 25, 75), lwd = 4, lwd.ticks = 2, col.ticks = "red")

还可以把 box 移除,绘图区域的边框去掉,只保留坐标轴

plot(x, y, bty = "n", xaxt = "n", yaxt = "n")
axis(side = 1, at = seq(0, 100, 20), lwd = 3)
axis(side = 2, at = seq(-2, 2, 2), lwd = 3)

# 双Y轴
N <- 200
x <- seq(-4, 4, length = N)
y1 <- sin(x)
y2 <- cos(x)
op <- par(mar = c(5, 4, 4, 4)) # Add some space in the right margin
# The default is c(5,4,4,2) + .1
xlim <- range(x)
ylim <- c(-1.1, 1.1)
plot(x, y1,
  col = "blue", type = "l",
  xlim = xlim, ylim = ylim,
  axes = F, xlab = "", ylab = "", main = "Title"
)
axis(1)
axis(2, col = "blue")
par(new = TRUE)
plot(x, y2,
  col = "red", type = "l",
  xlim = xlim, ylim = ylim,
  axes = F, xlab = "", ylab = "", main = ""
)
axis(4, col = "red")
mtext("First Y axis", 2, line = 2, col = "blue", cex = 1.2)
mtext("Second Y axis", 4, line = 2, col = "red", cex = 1.2)
两个 Y 轴

图 10.14: 两个 Y 轴

# 1,2,3,4 分别代表下左上右四个位置

调整坐标轴标签的距离

## Changing default gap between labels:
plot(c(0, 100), c(0, 50), type = "n", axes = FALSE, ann = FALSE)
title(quote("axis(1, .., gap.axis = f)," ~ ~ f >= 0))
axis(2, at = 5 * (0:10), las = 1, gap.axis = 1 / 4)
gaps <- c(4, 2, 1, 1 / 2, 1 / 4, 0.1, 0)
chG <- paste0(
  ifelse(gaps == 1, "default:  ", ""),
  "gap.axis=", formatC(gaps)
)
jj <- seq_along(gaps)
linG <- -2.5 * (jj - 1)
for (j in jj) {
  isD <- gaps[j] == 1 # is default
  axis(1,
    at = 5 * (0:20), gap.axis = gaps[j], padj = -1, line = linG[j],
    col.axis = if (isD) "forest green" else 1, font.axis = 1 + isD
  )
}
mtext(chG,
  side = 1, padj = -1, line = linG - 1 / 2, cex = 3 / 4,
  col = ifelse(gaps == 1, "forest green", "blue3")
)
gap.axis用法

图 10.15: gap.axis用法

## now shrink the window (in x- and y-direction) and observe the axis labels drawn

旋转坐标轴标签

# Rotated axis labels in R plots
# https://menugget.blogspot.com/2014/08/rotated-axis-labels-in-r-plots.html
# Example data
tmin <- as.Date("2000-01-01")
tmax <- as.Date("2001-01-01")
tlab <- seq(tmin, tmax, by = "month")
lab <- format(tlab, format = "%Y-%b")
set.seed(111)
x <- seq(tmin, tmax, length.out = 100)
y <- cumsum(rnorm(100))

# Plot
# png("plot_w_rotated_axis_labels.png", height = 3,
#     width = 6, units = "in", res = 300)
op <- par(mar = c(6, 4, 1, 1))
plot(x, y, t = "l", xaxt = "n", xlab = "")
axis(1, at = tlab, labels = FALSE)
text(
  x = tlab, y = par()$usr[3] - 0.1 * (par()$usr[4] - par()$usr[3]),
  labels = lab, srt = 45, adj = 1, xpd = TRUE
)

par(op)
# dev.off()

旋转坐标抽标签的例子来自手册《R FAQ》的第7章第27个问题 [12],在基础图形中,旋转坐标轴标签需要 text() 而不是 mtext(),因为后者不支持par("srt")

## Increase bottom margin to make room for rotated labels
par(mar = c(5, 4, .5, 2) + 0.1)
## Create plot with no x axis and no x axis label
plot(1:8, xaxt = "n", xlab = "")
## Set up x axis with tick marks alone
axis(1, labels = FALSE)
## Create some text labels
labels <- paste("Label", 1:8, sep = " ")
## Plot x axis labels at default tick marks
text(1:8, par("usr")[3] - 0.5,
  srt = 45, adj = 1,
  labels = labels, xpd = TRUE
)
## Plot x axis label at line 6 (of 7)
mtext(side = 1, text = "X Axis Label", line = 4)
旋转坐标轴标签

图 10.16: 旋转坐标轴标签

srt = 45 表示文本旋转角度, xpd = TRUE 允许文本越出绘图区域,adj = 1 to place the right end of text at the tick marks;You can adjust the value of the 0.5 offset as required to move the axis labels up or down relative to the x axis. 详细地参考 [13]

10.1.5 刻度线

通过 paraxis 函数实现刻度线的精细操作,tcl 控制刻度线的长度,正值让刻度画在绘图区域内,负值正好相反,画在外面,mgp 参数有三个值,第一个值控制绘图区域和坐标轴标题之间的行数,第二个是绘图区域与坐标轴标签的行数,第三个绘图区域与轴线的行数,行数表示间距

par(tcl = 0.4, mgp = c(1.5, 0, 0))
plot(x, y)

# 又一个例子
par(op)
plot(x, y, xaxt = "n", yaxt = "n", xlab = "", ylab = "")
axis(side = 1, at = seq(5, 95, 30), tcl = 0.4, lwd.ticks = 3, mgp = c(0, 0.5, 0))
mtext(side = 1, text = "X axis", line = 1.5) 
# mtext 设置坐标轴标签
axis(side = 2, at = seq(-2, 2, 2), tcl = 0.3, lwd.ticks = 3, col.ticks = "orange", mgp = c(0, 0, 2))
mtext(side = 2, text = "Numbers taken randomly", line = 2.2)

10.1.6 标题

添加多个标题

N <- 200
x <- runif(N, -4, 4)
y <- sin(x) + .5 * rnorm(N)
plot(x, y, xlab = "", ylab = "", main = "")
mtext("Subtitle", 3, line = .8)
mtext("Title", 3, line = 2, cex = 1.5)
mtext("X axis", 1, line = 2.5, cex = 1.5)
mtext("X axis subtitle", 1, line = 3.7)
图标题/子标题 x轴标题/子标题

图 10.17: 图标题/子标题 x轴标题/子标题

10.1.7 注释

数学符号注释,图10.18 自定义坐标轴 [14]

# 自定义坐标轴
plot(c(1, 1e6), c(-pi, pi),
  type = "n",
  axes = FALSE, ann = FALSE, log = "x"
)
axis(1,
  at = c(1, 1e2, 1e4, 1e6),
  labels = expression(1, 10^2, 10^4, 10^6)
)
axis(2,
  at = c(-pi, -pi / 2, 0, pi / 2, pi),
  labels = expression(-pi, -pi / 2, 0, pi / 2, pi)
)
text(1e3, 0, expression(italic("Customized Axes")))
box()
创建自定义的坐标轴和刻度标签

图 10.18: 创建自定义的坐标轴和刻度标签

在标题中添加数学公式

x <- seq(-5, 5, length = 200)
y <- sqrt(1 + x^2)
plot(y ~ x,
  type = "l",
  ylab = expression(sqrt(1 + x^2))
)
title(main = expression(
  "graph of the function f"(x) == sqrt(1 + x^2)
))
标题含有数学公式

图 10.19: 标题含有数学公式

修改参数使用 substitute 函数批量生成

x <- seq(-5, 5, length = 200)
for (i in 1:4) { # 画四个图
  y <- sqrt(i + x^2)
  plot(y ~ x,
    type = "l",
    ylim = c(0, 6),
    ylab = substitute(
      expression(sqrt(i + x^2)),
      list(i = i)
    )
  )
  title(main = substitute(
    "graph of the function f"(x) == sqrt(i + x^2),
    list(i = i)
  ))
}
批量生成函数图形

图 10.20: 批量生成函数图形

批量生成函数图形

图 10.21: 批量生成函数图形

批量生成函数图形

图 10.22: 批量生成函数图形

批量生成函数图形

图 10.23: 批量生成函数图形

基础绘图函数,如 plot 标签 xlab 支持 Unicode 代码表示的希腊字母,常用字母表备查,公式环境下,也可以用在绘图中

表 10.1: 希腊字母表
希腊字母 LaTeX 代码 Unicode 代码 希腊字母 LaTeX 代码 Unicode 代码
α \alpha \u03B1 μ \mu \u03BC
β \beta \u03B2 ν \nu \u03BD
γ \gamma \u03B3 ξ \xi \u03BE
δ \delta \u03B4 φ \varphi \u03C6
ϵ \epsilon \u03B5 π \pi \u03C0
ζ \zeta \u03B6 ρ \rho \u03C1
η \eta \u03B7 υ \upsilon \u03C5
θ \theta \u03B8 ϕ \phi \u03C6
ι \iota \u03B9 χ \chi \u03C7
κ \kappa \u03BA ψ \psi \u03C8
λ \lambda \u03BB ω \omega \u03C9
σ \sigma \u03C3 τ \tau \u03C4
表 10.2: 数字上下标
上标数字 LaTeX 代码 Unicode 代码 下标数字 LaTeX 代码 Unicode 代码
0 {}^0 \u2070 0 {}_0 \u2080
1 {}^1 \u00B9 1 {}_1 \u2081
2 {}^2 \u00B2 2 {}_2 \u2082
3 {}^3 \u00B2 3 {}_3 \u2083
4 {}^4 \u2074 4 {}_4 \u2084
5 {}^5 \u2075 5 {}_5 \u2085
6 {}^6 \u2076 6 {}_6 \u2086
7 {}^7 \u2077 7 {}_7 \u2087
8 {}^8 \u2078 8 {}_8 \u2088
9 {}^9 \u2079 9 {}_9 \u2089
n {}^n \u207F n {}_n -

其它字母,请查看 Unicode 字母表

10.1.8 图例

x <- seq(-6, 6, length = 200)
y <- sin(x)
z <- cos(x)
plot(y ~ x,
  type = "l", lwd = 3,
  ylab = "", xlab = "angle", main = "Trigonometric functions"
)
abline(h = 0, lty = 3)
abline(v = 0, lty = 3)
lines(z ~ x, type = "l", lwd = 3, col = "red")
legend(-6, -1,
  yjust = 0,
  c("Sine", "Cosine"),
  lwd = 3, lty = 1, col = c(par("fg"), "red")
)
三角函数添加图例

图 10.24: 三角函数添加图例

xmin <- par("usr")[1]
xmax <- par("usr")[2]
ymin <- par("usr")[3]
ymax <- par("usr")[4]

plot(y ~ x,
  type = "l", lwd = 3,
  ylab = "", xlab = "angle", main = "Trigonometric functions"
)
abline(h = 0, lty = 3)
abline(v = 0, lty = 3)
lines(z ~ x, type = "l", lwd = 3, col = "red")
legend("bottomleft",
  c("Sine", "Cosine"),
  lwd = 3, lty = 1, col = c(par("fg"), "red")
)
设置图例的位置

图 10.25: 设置图例的位置

plot(y ~ x,
  type = "l", lwd = 3,
  ylab = "", xlab = "angle", main = "Trigonometric functions"
)
abline(h = 0, lty = 3)
abline(v = 0, lty = 3)
lines(z ~ x, type = "l", lwd = 3, col = "red")
legend("bottomleft",
  c("Sine", "Cosine"),
  inset = c(.03, .03),
  lwd = 3, lty = 1, col = c(par("fg"), "red")
)
insert 函数微调图例位置

图 10.26: insert 函数微调图例位置

op <- par(no.readonly = TRUE)
plot(y ~ x,
  type = "l", lwd = 3,
  ylab = "", xlab = "angle", main = "Trigonometric functions"
)
abline(h = 0, lty = 3)
abline(v = 0, lty = 3)
lines(z ~ x, type = "l", lwd = 3, col = "red")
par(xpd = TRUE) # Do not clip to the drawing area 关键一行/允许出界
lambda <- .025
legend(par("usr")[1],
  (1 + lambda) * par("usr")[4] - lambda * par("usr")[3],
  c("Sine", "Cosine"),
  xjust = 0, yjust = 0,
  lwd = 3, lty = 1, col = c(par("fg"), "red")
)
将图例放在绘图区域外面

图 10.27: 将图例放在绘图区域外面

par(op)

Hmisc 包的 labcurve 函数可以在曲线上放置名称,而不是遥远的图例上

10.1.9 边空

边空分为内边空和外边空

边空边空

图 10.28: 边空

line 第一行

N <- 200
x <- runif(N, -4, 4)
y <- sin(x) + .5 * rnorm(N)
plot(x, y,
  xlab = "", ylab = "",
  main = paste(
    "The \"mtext\" function",
    paste(rep(" ", 60), collapse = "")
  )
)
for (i in seq(from = 0, to = 1, by = 1)) {
  mtext(paste("Line", i), 3, line = i)
}
外边空在图的边缘添加文字

图 10.29: 外边空在图的边缘添加文字

par

# 多图排列/分屏 page 47
# 最常用的是 par mfrow mfcol分别按行/列放置图形
op <- par(
  mfrow = c(2, 2),
  oma = c(0, 0, 4, 0) # Outer margins
)
for (i in 1:4) {
  plot(runif(20), runif(20),
    main = paste("random plot (", i, ")", sep = "")
  )
}
par(op)
mtext("Four plots, without enough room for this title",
  side = 3, font = 2, cex = 1.5, col = "red"
) # 总/大标题放不下
多图排列共享一个大标题

图 10.30: 多图排列共享一个大标题

par 的 oma 用来设置外边空的大小,默认情形下没有外边空的

par()$oma
## [1] 0 0 0 0

我们可以自己设置外边空

op <- par(
  mfrow = c(2, 2),
  oma = c(0, 0, 3, 0) # Outer margins
)
for (i in 1:4) {
  plot(runif(20), runif(20),
    main = paste("random plot (", i, ")", sep = "")
  )
}
par(op)
mtext("Four plots, with some room for this title",
  side = 3, line = 1.5, font = 1, cex = 1.5, col = "red"
)
设置外边空放置大标题

图 10.31: 设置外边空放置大标题

除了内边空还有外边空,内外边空用来放注释说明

op <- par(no.readonly = TRUE)
par(oma = c(2, 2, 2, 2))
plot(1, 1, type = "n", xlab = "", ylab = "", xaxt = "n", yaxt = "n")
for (side in 1:4) {
  inner <- round(par()$mar[side], 0) - 1
  for (line in 0:inner) {
    mtext(text = paste0("Inner line ", line), side = side, line = line)
  }
  outer <- round(par()$oma[side], 0) - 1
  for (line in 0:inner) {
    mtext(text = paste0("Outer line ", line), side = side, line = line, outer = TRUE)
  }
}

外边空可以用来放图例

set.seed(1234)
x <- runif(10)
y <- runif(10)
cols <- rep(hcl.colors(5), each = 2)
op <- par(oma = c(2, 2, 0, 4), mar = c(3, 3, 2, 0), mfrow = c(2, 2), pch = 16)
for (i in 1:4) {
  plot(x, y, col = cols, ylab = "", xlab = "")
}
mtext(text = "A common x-axis label", side = 1, line = 0, outer = TRUE)
mtext(text = "A common y-axis label", side = 2, line = 0, outer = TRUE)
legend(
  x = 1, y = 1.2, legend = LETTERS[1:5],
  col = unique(cols), pch = 16, bty = "n", xpd = NA
)

par(op)

坐标轴标签 xlabylab 的内容很长的时候需要内边空

par(cex.lab = 1.7)
plot(1, 1,
  ylab = "A very very long axis title\nthat need special care",
  xlab = "", type = "n"
)

# 增加内边空的大小
par(mar = c(5, 7, 4, 2))
plot(1, 1,
  ylab = "A very very long axis title\nthat need special care",
  xlab = "", type = "n"
)

有时候,仅仅增加内边空还不够,坐标轴标签内容甚至可以出现在绘图区域外面,设置 outer = TRUE

par(oma = c(0, 4, 0, 0))
plot(1, 1, ylab = "", xlab = "", type = "n")
mtext(
  text = "A very very long axis title\nthat need special care",
  side = 2, line = 0, outer = TRUE, cex = 1.7
)

op <- par(
  mfrow = c(2, 2),
  oma = c(0, 0, 3, 0),
  mar = c(3, 3, 4, 1) + .1 # Margins
)
for (i in 1:4) {
  plot(runif(20), runif(20),
    xlab = "", ylab = "",
    main = paste("random plot (", i, ")", sep = "")
  )
}
par(op)
mtext("Title",
  side = 3, line = 1.5, font = 2, cex = 2, col = "red"
)
设置每个子图的边空 mar

图 10.32: 设置每个子图的边空 mar

10.1.10 图层

覆盖图形 add = T or par(new=TRUE)

plot(runif(5), runif(5),
  xlim = c(0, 1), ylim = c(0, 1)
)
points(runif(5), runif(5),
  col = "#EA4335", pch = 16, cex = 3
)
lines(runif(5), runif(5), col = "red")
segments(runif(5), runif(5), runif(5), runif(5),
  col = "blue"
)
title(main = "Overlaying points, segments, lines...")
添加图层

图 10.33: 添加图层

10.1.11 布局

layout 函数布局, 绘制复杂组合图形

op <- par(oma = c(0, 0, 3, 0))
layout(matrix(c(
  1, 1, 1,
  2, 3, 4,
  2, 3, 4
), nr = 3, byrow = TRUE))
hist(rnorm(n), col = "light blue")
hist(rnorm(n), col = "light blue")
hist(rnorm(n), col = "light blue")
hist(rnorm(n), col = "light blue")
mtext("The \"layout\" function",
  side = 3, outer = TRUE,
  font = 2, cex = 1.2
)
更加复杂的组合图形

图 10.34: 更加复杂的组合图形

10.1.12 组合

parfig 参数很神奇,使得多个图可以叠加在一起,它接受一个数值向量c(x1, x2, y1, y2) ,是图形设备显示区域中的绘图区域的(NDC, normalized device coordinates)坐标。

plot(1:12,
  type = "b", main = "'fg' : axes, ticks and box in gray",
  fg = gray(0.7), bty = "7", sub = R.version.string
)
par(fig = c(1, 6, 5, 10) / 10, new = T)
plot(6:10,
  type = "b", main = "",
  fg = gray(0.7), bty = "7", xlab = R.version.string
)
多图叠加

图 10.35: 多图叠加

fig 参数控制图形的位置,用来绘制组合图形

n <- 1000
x <- rt(n, df = 10)
hist(x,
  col = "light blue",
  probability = "TRUE", main = "",
  ylim = c(0, 1.2 * max(density(x)$y))
)
lines(density(x),
  col = "red",
  lwd = 3
)
op <- par(
  fig = c(.02, .4, .5, .98),
  new = TRUE
)
qqnorm(x,
  xlab = "", ylab = "", main = "",
  axes = FALSE
)
qqline(x, col = "red", lwd = 2)
box(lwd = 2)
组合图形

图 10.36: 组合图形

par(op)

10.1.13 分屏

split.screen 分屏组合

random.plot <- function() {
  N <- 200
  f <- sample(
    list(
      rnorm,
      function(x) {
        rt(x, df = 2)
      },
      rlnorm,
      runif
    ),
    1
  ) [[1]]
  x <- f(N)
  hist(x, col = "lightblue", main = "", xlab = "", ylab = "", axes = F)
  axis(1)
}
op <- par(bg = "white", mar = c(2.5, 2, 1, 2))
split.screen(c(2, 1))
## [1] 1 2
split.screen(c(1, 3), screen = 2)
## [1] 3 4 5
screen(1)
random.plot()
# screen(2); random.plot() # Screen 2 was split into three screens: 3, 4, 5
screen(3)
random.plot()
screen(4)
random.plot()
screen(5)
random.plot()
分屏

图 10.37: 分屏

close.screen(all = TRUE)
par(op)

10.1.14 交互

辅助绘图 identify locator

参考文献

[12]
K. Hornik, R FAQ: Frequently asked questions on R.” 2020.Available: https://CRAN.R-project.org/doc/FAQ/R-FAQ.html
[13]
P. Murrell, “Integrating grid graphics output with base graphics output,” R News, vol. 3, no. 2, pp. 7–12, 2003.
[14]
P. Murrell and R. Ihaka, “An approach to providing mathematical annotation in plots,” Journal of Computational and Graphical Statistics, vol. 9, no. 3, pp. 582–599, 2000.