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")
我们可以更改不同的主题
-
theme_gray
:
p1 + theme_gray()
这个是默认的主题,浅灰色背景,白色网格线
-
theme_bw
:
p1 + theme_bw()
这个主题是白色背景,深灰色网格线。
- 其他主题
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_update
和 theme_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_update
和 theme_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)