R 数据可视化 —— ggplot 主题

前言

主题系统控制图形中所有非数据元素的显示,如标题、坐标轴标签、图例标签等文本字体的调整,以及网格线、背景、刻度的颜色等。

ggplot2 采用数据与非数据分离的方式,在绘图时,首先确定数据的展示,然后在通过主题系统对细节进行调整。

ggplot2 内置了一些主题可供使用,也可以使用 theme() 函数来更改现有主题的图形元素

1. 内置主题

默认的主题有:

theme_grey(
  base_size = 11,
  base_family = "",
  base_line_size = base_size/22,
  base_rect_size = base_size/22
)

theme_gray(...)
theme_bw(...)
theme_linedraw(...)
theme_light(...)
theme_dark(...)
theme_minimal(...)
theme_classic(...)
theme_void(...)
theme_test(...)

这些默认主题都包含 4 个参数:

  • base_size:轴标题字体大小,以 pts 为单位。图形标题比它大 20%,刻度标签比它小 20%
  • base_family:字体
  • base_line_size:线条元素的大小
  • base_rect_size:矩形元素的大小

示例

对于如下图形

mtcars2 <- within(mtcars, {
  vs <- factor(vs, labels = c("V-shaped", "Straight"))
  am <- factor(am, labels = c("Automatic", "Manual"))
  cyl  <- factor(cyl)
  gear <- factor(gear)
})

p1 <- ggplot(mtcars2) +
  geom_point(aes(x = wt, y = mpg, colour = gear)) +
  labs(title = "Fuel economy declines as weight increases",
       subtitle = "(1973-74)",
       caption = "Data from the 1974 Motor Trend US magazine.",
       tag = "Figure 1",
       x = "Weight (1000 lbs)",
       y = "Fuel economy (mpg)",
       colour = "Gears")

我们可以更改不同的主题

  1. theme_gray
p1 + theme_gray()

这个是默认的主题,浅灰色背景,白色网格线

  1. theme_bw
p1 + theme_bw()

这个主题是白色背景,深灰色网格线。

  1. 其他主题
p3 <- p1 + theme_linedraw()
p4 <- p1 + theme_light()
p5 <- p1 + theme_dark()
p6 <- p1 + theme_minimal()
p7 <- p1 + theme_classic()
p8 <- p1 + theme_void()

plot_grid(p3, p4, p5, p6, p7, p8, labels = LETTERS[1:6], nrow = 3)

对于分面图形,也是一样的

p2 <- p1 + facet_grid(vs ~ am)

p3 <- p2 + theme_linedraw()
p4 <- p2 + theme_light()
p5 <- p2 + theme_dark()
p6 <- p2 + theme_minimal()
p7 <- p2 + theme_classic()
p8 <- p2 + theme_void()

plot_grid(p2, p2 + theme_bw(), p3, p4, p5, p6, p7, p8, nrow = 4)

2. 修改主题

修改全局主题之后,该主题会应用于之后绘制的所有图形中,全局主题设置主要包含以下几个函数

theme_get()

theme_set(new)

theme_update(...)

theme_replace(...)

其中,theme_get() 用于获取当前主题,theme_set(new) 使用新主题完全覆盖当前主题。

theme_updatetheme_replace 用于修改某一图形元素

示例

对于

p <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point()
p

设置主题为 theme_bw()theme_set 会返回之前的主题

old <- theme_set(theme_bw())
p

使用 theme_update 设置主题中某一图形元素,只会修改设置的元素,未显式设置的元素不会修改

theme_update(panel.grid.minor = element_line(colour = "red"))
p

不同于 theme_update,使用 theme_replace 函数来修改某一元素的值时,未显式设置的元素值都会赋值为 NULL

theme_replace(panel.grid.minor = element_line(colour = "red"))
p

设置回默认主题

theme_set(old)
p
注意

theme_updatetheme_replace 两个函数分别通过调用 +%+replace% 来实现的。

我们可以打印主题对象来感受它们之间的区别

> add_el <- theme_grey() +
+   theme(text = element_text(family = "Times"))
> add_el$text
List of 11
 $ family       : chr "Times"
 $ face         : chr "plain"
 $ colour       : chr "black"
 $ size         : num 11
 $ hjust        : num 0.5
 $ vjust        : num 0.5
 $ angle        : num 0
 $ lineheight   : num 0.9
 $ margin       : 'margin' num [1:4] 0pt 0pt 0pt 0pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ debug        : logi FALSE
 $ inherit.blank: logi FALSE
 - attr(*, "class")= chr [1:2] "element_text" "element"
> 
> rep_el <- theme_grey() %+replace%
+   theme(text = element_text(family = "Times"))
> rep_el$text
List of 11
 $ family       : chr "Times"
 $ face         : NULL
 $ colour       : NULL
 $ size         : NULL
 $ hjust        : NULL
 $ vjust        : NULL
 $ angle        : NULL
 $ lineheight   : NULL
 $ margin       : NULL
 $ debug        : NULL
 $ inherit.blank: logi FALSE
 - attr(*, "class")= chr [1:2] "element_text" "element"

我们可以看到,在使用 + 来更新主题元素时,只修改了 family 属性的值,其他值并未改动。

而在使用 %+replace% 修改主题时,只有设置的 family 属性有值,而其他所有属性值都被设置为 NULL

3. 修改主题元素

在主题系统中,使用 element_* 函数来指定如何显示或绘图非数据组件

  • element_blank:什么也不画,也不分配空间
  • element_rect:设置边框和背景
  • element_line:设置线条
  • element_text:设置文本

还有 rel() 用于指定相对于父节点的大小,margin() 用于指定元素的边距

margin(
  t = 0,       # top
  r = 0,       # right
  b = 0,       # bottom
  l = 0,       # left
  unit = "pt"  # 默认的尺寸单位,默认为 "pt"。
)

element_blank()

element_rect(
  fill = NULL,           # 填充色
  colour = NULL,         # 边框颜色
  size = NULL,           # 边框大小,单位 mm
  linetype = NULL,       # 边框线条类型
  color = NULL,          # colour 的别名
  inherit.blank = FALSE  # 是否从父元素中继承 element_blank 空白元素
)

element_line(
  colour = NULL,         # 线条颜色
  size = NULL,           # 线条大小,单位 mm
  linetype = NULL,       # 线条类型
  lineend = NULL,        # 线条末端样式(ound, butt, square)
  color = NULL,          # 同上
  arrow = NULL,          # 箭头样式
  inherit.blank = FALSE  # 同上
)

element_text(
  family = NULL,         # 字体家族
  face = NULL,           # 粗斜体等"plain", "italic", "bold", "bold.italic"
  colour = NULL,         # 字体颜色
  size = NULL,           # 字体大小,单位 pts
  hjust = NULL,          # 水平对齐([0,1])
  vjust = NULL,          # 竖直对齐([0,1])
  angle = NULL,          # 旋转角度([0,360])
  lineheight = NULL,     # 行高
  color = NULL,          # 同上
  margin = NULL,         # 文本边距
  debug = NULL,          # 在文本区域后面添加实心矩形
  inherit.blank = FALSE  # 同上
)

rel(
  x  # 指定相对于父元素大小的数值
)

4. 主题元素

通过上面的介绍,我们对如何设置主题应该有了较全面的了解了。

但是光知道如何设置主题元素是不行的,我们还要知道能够设置哪些主题元素。

我们可以使用 theme() 函数来设置图中非数据元素,例如标题、标签、字体、背景、网格线和图例等,具体的参数如下

主题元素按层次结构从其他主题元素中继承属性,例如 axis.title.x.bottom 继承自 axis.title.x,而其又是继承自 axis.title,又继承自最顶层的 text。

也就是说,所有的文本元素继承自 text,所有的线条继承自 line,所有的矩形对象继承自 rect。因此,您可以通过设置一个顶层元素来修改多个子元素的的属性

1. 简单示例

p <- ggplot(mpg, aes(displ, hwy)) + geom_point()

p1 <- p + theme(
  panel.background = element_blank(),
  axis.text = element_blank()
)

p2 <- p + theme(
  axis.text = element_text(colour = "red", size = rel(1.5))
)

p3 <- p + theme(
  axis.line = element_line(arrow = arrow())
)

p4 <- p + theme(
  panel.background = element_rect(fill = "white"),
  plot.margin = margin(2, 2, 2, 2, "cm"),
  plot.background = element_rect(
    fill = "grey90",
    colour = "black",
    size = 1
  )
)

plot_grid(p1, p2, p3, p4, labels = LETTERS[1:4], nrow = 2)

2. plot 元素设置

p1 <- ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  labs(title = "Fuel economy declines as weight increases")

p2 <- p1 + theme(plot.title = element_text(size = rel(2)))

p3 <- p1 + theme(plot.background = element_rect(fill = "green"))

plot_grid(p2, p3, labels = LETTERS[1:2], nrow = 2)

3. panel 元素设置

p2 <- p1 + theme(panel.background = element_rect(fill = "white", colour = "grey50"))

p3 <- p1 + theme(panel.border = element_rect(linetype = "dashed", fill = NA))

p4 <- p1 + theme(panel.grid.major = element_line(colour = "black"))

p5 <- p1 + theme(
  panel.grid.major.y = element_blank(),
  panel.grid.minor.y = element_blank()
)

plot_grid(p2, p3, p4, p5, labels = LETTERS[1:4], nrow = 2)

将网格放置在数据之上

p1 + theme(
  panel.background = element_rect(fill = NA),
  panel.grid.major = element_line(colour = "grey50"),
  panel.ontop = TRUE
)

4. 更改轴文本和线条的样式

p2 <- p1 + theme(axis.line = element_line(size = 3, colour = "grey80"))

p3 <- p1 + theme(axis.text = element_text(colour = "blue"))

p4 <- p1 + theme(axis.ticks = element_line(size = 2))

# 更改 y 轴的外观
p5 <- p1 + theme(axis.title.y = element_text(size = rel(1.5), angle = 90))

plot_grid(p2, p3, p4, p5, labels = LETTERS[1:4], nrow = 2)

设置 x 轴的刻度向内,y 轴的刻度向外

p1 + theme(
  axis.ticks.length.y = unit(.25, "cm"),
  axis.ticks.length.x = unit(-.25, "cm"),
  axis.text.x = element_text(margin = margin(t = .3, unit = "cm"))
)

5. 图例

p2 <- ggplot(mtcars, aes(wt, mpg)) +
  geom_point(aes(colour = factor(cyl), shape = factor(vs))) +
  labs(
    x = "Weight (1000 lbs)",
    y = "Fuel economy (mpg)",
    colour = "Cylinders",
    shape = "Transmission"
  )
p2

图例位置

p3 <- p2 + theme(legend.position = "none")

p4 <- p2 + theme(legend.justification = "top")

p5 <- p2 + theme(legend.position = "bottom")

# 使用 0-1 之间的相对坐标值
p6 <- p2 + theme(
  legend.position = c(.95, .95),
  legend.justification = c("right", "top"),
  legend.box.just = "right",
  legend.margin = margin(6, 6, 6, 6)
)

plot_grid(p3, p4, p5, p6, labels = LETTERS[1:4], nrow = 2)

设置图例的框线、键、标签和标题

# 设置图例框线
p3 <- p2 + theme(
  legend.box.background = element_rect(),
  legend.box.margin = margin(6, 6, 6, 6)
)
# 设置图例的键
p4 <- p2 + theme(legend.key = element_rect(fill = "white", colour = "black"))
# 设置图例标签
p5 <- p2 + theme(legend.text = element_text(size = 8, colour = "red"))
# 设置图例标题
p6 <- p2 + theme(legend.title = element_text(face = "bold"))

plot_grid(p3, p4, p5, p6, labels = LETTERS[1:4], nrow = 2)

6. 条带(Strips)

p3 <- ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  facet_wrap(~ cyl)

p4 <- p3 + theme(strip.background = element_rect(colour = "black", fill = "white"))

p5 <- p3 + theme(strip.text.x = element_text(colour = "white", face = "bold"))

p6 <- p3 + theme(panel.spacing = unit(1, "lines"))

plot_grid(p3, p4, p5, p6, labels = LETTERS[1:4], nrow = 2)

你可能感兴趣的:(R 数据可视化 —— ggplot 主题)