一点碎碎念:今天开始看第三章Toolbox, 主要讲的是图层的用法,在图像的基础上,图层可以让plot的信息更加丰富和完整,于是就有了怎样加标签,加注释等等。这些内容虽然不难但是很琐碎,由于R基础薄弱,有些代码理解起来需要时间。所以,在这里我想先以读书笔记和翻译的形式,记录为主,尽量去逐字逐句理解。除了添加注释、标签等之外,使用图层还可以完成箱线图、多边形等等多种群组几何对象类型的图,还可以绘制曲面图等。下面是第三章的主要内容:
使用图层的三个主要目的:展示数据:绘制原始数据时唯一的一层(数据层) 展示数据的统计摘要:在数据背景下展示模型的统计预测效果,模型层通常绘制在数据层之上 添加额外的元数据(metadata)、上下文信息和注释:也称背景层,了解数据的背景信息或强调数据中的某些特征,一般在最后绘制。
1. 基本图形类型几何对象是ggplot2的基本组成部分,可以独立构建图形。他们都是二维的,主要函数有 geom_area() , geom_bar() , geom_line , geom_point() , geom_polygon() , geom_tile() 等等。这些函数包括x,y两个主要属性,另外也可以接受 color 和 size 两个图形属性,他们构成了基本的数据层。 我们可以通过使用 + 来添加图层。 df <> data.frame(
x = c(3, 1, 5),
y = c(2, 4, 6),
label = c('a','b','c')
)
df
p <> ggplot(df, aes(x, y, label = label)) +
labs(x = NULL, y = NULL) + # Hide axis label
theme(plot.title = element_text(size = 12)) # Shrink plot title
p + geom_point() + ggtitle('point')
p + geom_text() + ggtitle('text')
p + geom_bar(stat = 'identity') + ggtitle('bar')
p + geom_tile() + ggtitle('raster')
p + geom_line() + ggtitle('line')
p + geom_area() + ggtitle('area')
p + geom_path() + ggtitle('path')
p + geom_polygon() + ggtitle('polygon')
以上命令运行后可依次生成散点图、含标签的散点图、条形图、色深图、线条图、面积图、路径图和多边形图等八个图,其中 ggtitle() 是给各个图片添加注释/命名
2. 添加标签(label)主要函数 geom_text() :和散点类似,就是将point换成了文字。它包括以下几种参数: df <> data.frame(x = 1, y = 3:1, family = c('sans', 'serif', 'mono'))
ggplot(df, aes(x, y)) +
geom_text(aes(label = family, family = family))
此外还有两个字体安装包 – showtext, https://github.com/yixuan/showtext, by Yixuan Qiu, makes GD-independent plots by rendering all text as polygons. – extrafont, https://github.com/wch/extrafont, by Winston Chang, converts fonts to a standard format that all devices can use.
df <> data.frame(x = 1, y = 3:1, face = c('plain', 'bold', 'italic'))
ggplot(df, aes(x, y)) +
geom_text(aes(label = face, fontface = face))
vjust 和 hjust 可以设置字体对齐方式。 vjust (“bottom”, “middle”, “top”, “inward”, “outward”); hjust (“left”, “center”, “right”, “inward”, “outward”)。最常用的路线之一是 “inward” :它将文本对齐到主画面的中间:
df <> data.frame(
x = c(1, 1, 2, 2, 1.5),
y = c(1, 2, 1, 2, 1.5),
text = c(
'bottom-left', 'bottom-right',
'top-left', 'top-right', 'center'
)
)
ggplot(df, aes(x, y)) +
geom_text(aes(label = text)) # 字母不能全部在画面中
ggplot(df, aes(x, y)) +
geom_text(aes(label = text), vjust = 'inward', hjust = 'inward') # 字母全部在画面中
df <> data.frame(trt = c('a', 'b', 'c'), resp = c(1.2, 3.4, 2.5))
ggplot(df, aes(resp, trt)) +
geom_point() +
geom_text(aes(label = paste0('(', resp, ')')), nudge_y = -0.25) + # y轴负方向下移0.25
xlim(1, 3.6) # 设定x轴取值区间
以耗油量数据为例: library(ggplot2)
mpg
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model)) +
xlim(1, 8)
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model), check_overlap = TRUE) +
xlim(1, 8)
另外,与 geom_text() 类似的是 geom_label() ,它与geom_text的区别自动在文字后方绘制一个圆角矩形标签,当需要在复杂的背景上标注文字时可以使用。 label <> data.frame(
waiting = c(55, 80),
eruptions = c(2, 4.3),
label = c('peak one', 'peak two')
)
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_tile(aes(fill = density)) +
geom_label(data = label, aes(label = label))
学会了在图中添加标签,可以替代图例
3. 注释(Annotations)注释可以在你的图上添加一些额外的元数据,可以使用以下函数: geom_text() :在指定点添加标签(见上文)
geom_rect() :可强调图形中感兴趣的矩形区域。包括 xmin , xmax , ymin , ymax
geom_line() ; geom_path() ; geom_segment() :在图形中添加线条; arrow() 可以用来添加箭头
geom_vline() ; geom_hline() :向图形添加垂直线或水平线
geom_abline() :向图形添加任意斜率和截距地直线
然后我们用“失业率数据集”来举例: ggplot(economics, aes(date, unemploy)) +
geom_line()
下面我们想在图中展现一下不同政党执政时期失业率的高低情况: presidential <> subset(presidential, start > economics$date[1]) ## 设置数据集,economics$date[1]是指定了数据集中data一列的第一行数据
ggplot(economics) +
geom_rect(
aes(xmin = start, xmax = end, fill = party),
ymin = -Inf, ymax = Inf, alpha = 0.2,
data = presidential
) +
geom_vline(
aes(xintercept = as.numeric(start)),
data = presidential,
colour = 'grey50', alpha = 0.5
) +
geom_text(
aes(x = start, y = 2500, label = name),data = presidential,
size = 3, vjust = 0, hjust = 0, nudge_x = 50
) +
geom_line(aes(date, unemploy)) + ## 数据集中的两列数据来源
scale_fill_manual(values = c('blue', 'red')) ## scale是标度函数
(疑问: party 这个对象的数据不知道从哪里来的) 生成图片: 如果我们想使用同样的方法在图片中添加一个单独的注释,方法有点复杂,因为首先要创建一个数据框: library(ggplot2)
economics
yrng <> range(economics$unemploy)
xrng <> range(economics$date) ## range 是取提取范围的子集,最大值和最小值
caption <> paste(strwrap('Unemployment rates in the US have
+ varied a lot over the years', 40), collapse = '\n') ## 设置题目内容
ggplot(economics, aes(date, unemploy)) +
geom_line() +
geom_text(
aes(x, y, label = caption),
data = data.frame(x = xrng[1], y = yrng[2], caption = caption),
hjust = 0, vjust = 1, size = 4
)
上述代码可以用 annotate() 来简化 geom_text() 部分: ggplot(economics, aes(date, unemploy)) +
geom_line() +
annotate('text', x = xrng[1], y = yrng[2], label = caption,
hjust = 0, vjust = 1, size = 4)
生成图片: 注释,在分面状态下的组间比较的时也非常有用。下面要做一组关于钻石质量(carat)和价格(price)比较的2d热图,按照切割品质(cut)进行分面: ggplot(diamonds, aes(log10(carat), log10(price))) +
geom_bin2d() +
facet_wrap(~cut, nrow = 1)
4. 群组几何对象(Collective Geoms)在ggplot2中,几何对象大致可以分为个体(individual)几何对象和群组(collective)两种类型。群组几何对象可以多角度的展现数据结果。 group (分组)这种图形属性可以用来设置:哪些观测值控制哪种图形元素
举例:纵向数据集Oxboys(nlme包)记录了26个男生(subject)在9个不同时期(occasion)中测定的身高(height)和中心化年龄(age)。 data(Oxboys, package = 'nlme')
> head(Oxboys)
#> Subject age height Occasion ## 以下是输出结果
#> 1 1 -1.0000 140 1
#> 2 1 -0.7479 143 2
#> 3 1 -0.4630 145 3
#> 4 1 -0.1643 147 4
#> 5 1 -0.0027 148 5
#> 6 1 0.2466 150 6
多个分组+单个图形属性当我们想从总体上查看数据,将数据中的每个个体区分开,然后用同样的方式映射。这在含有多个个体的纵向数据中很常见,叫“细面图”(spaghetti plot)。 例如,我们想在整体上观察26个男生的成长轨迹(并不区分哪条线是那个男生),就可以在映射 aes() 中添加参数 group=Subject : ggplot(Oxboys, aes(age, height, group = Subject)) +
geom_point() +
geom_line()
如果不加 group 这个参数,我们只会得到一条将所有点连起来的奇怪的折线,这就毫无疑义了 在不同图层进行分组如果我们想要将不同水平下的数据加以整合得到一个汇总信息,这时,基本的数据图层上是每个个体的数据,我们可以在第二个数据层上展示整体组群的信息。 例如在上面的例子中,我们想根据所有男孩的年龄和身高在图中添加一个平滑线条,如果按照上面的方式,在第一层函数中直接添加 group=Subject 就会给每个男孩的线条上加一个平滑曲线,这不能得到我们想要的结果: ggplot(Oxboys, aes(age, height, group = Subject)) +
geom_line() +
geom_smooth(method = 'lm', se = FALSE)
这时我们应该把分组参数放到另一个图层中,正确的代码如下: ggplot(Oxboys, aes(age, height)) +
geom_line(aes(group = Subject)) +
geom_smooth(method = 'lm', size = 2, se = FALSE)
修改默认分组在这里首先补充说明一下变量的分类:变量按其数值表现是否连续,分为连续变量和离散变量。 离散变量:指变量值可以按一定顺序一一列举,通常以整数位取值的变量。如职工人数、工厂数、机器台数等。 连续变量:在一定区间内可以任意取值的变量叫连续变量,其数值是连续不断的,相邻两个数值可作无限分割,即可取无限个数值。
当离散变量存在时,一般就会将其认为是默认分组变量。 如果图像中含有离散型变量,而你却想绘制连接所有分组的线条。这时就要修改默认分组。或者在新图层中设定一个新的分组,就能将二者结合起来。 在上个例子中,绘制各个时期(Occasion)和身高(height)的箱线图,离散型变量Occasion默认为分组变量: ggplot(Oxboys, aes(Occasion, height)) +
geom_boxplot()
然后要在此基础上添加个体轨迹,这时只添加 geom line() 函数不能达到预期效果,因为它还会默认Occasion为分组变量,这时应该将 aes(group=Subject) 添加在 geom line() 函数中,另外添加颜色属性 colour 将第二个图层区分开: ggplot(Oxboys, aes(Occasion, height)) +
geom_boxplot() +
geom_line(aes(group = Subject), colour = '#3366FF', alpha = 0.5)
匹配图形属性和图形对象如何将个体的图形属性映射给整体图形属性。 例如建立一个数据框,包括三个数据点,两条连接三点的线段。数据点比线段条数多一,线段的图形属性是由起始点的图形属性决定的,所以第一条线段使用第一个数据点的图形属性,第二条线段使用第二个数据点的图形属性,而第三个点的图形属性将不会被用到。下面代码生成图片的颜色是随着数据点,呈现离散状态。 library(ggplot2)
df <> data.frame(x = 1:3, y = 1:3, colourname = c(1,3,5))
ggplot(df, aes(x, y, colour = factor(colourname))) +
geom_line(aes(group = 1), size = 2) + ## group = 1 默认分组设置
geom_point(size = 5)
下面修改可以将颜色属性设置为渐变状态,但是数据点还是突出的: ggplot(df, aes(x, y, colour = colourname)) +
geom_line(aes(group = 1), size = 2) +
geom_point(size = 5)
在复杂一些,利用“线性插值法”可以将线段平稳地在图形属性间变化: 啥是“线性插值法”:已知坐标 (x0, y0) 与 (x1, y1),要得到 [x0, x1] 区间内某一位置 x 在直线上的值。
library(ggplot2)
df <> data.frame(x = 1:3, y = 1:3, colour = c(1,3,5))
xgrid <> with(df, seq(min(x), max(x), length = 50)) ## seq()是生成一组数字
interp <> data.frame(
x = xgrid,
y = approx(df$x, df$y, xout = xgrid)$y, ##approx()是排序
colour = approx(df$x, df$colour, xout = xgrid)$y
)
ggplot(interp, aes(x, y, colour = colour)) +
geom_line(size = 2) +
geom_point(data = df, size = 5)
对于多边形这类几何图像,当所有个体的图形属性都相同时,可以使用 fill() 参数。 当图形映射对象是离散型对象时,默认将群组几何对象分解成更小的部分。 如下例,耗油量数据集(mpg)中,用柱状图表示不同类别的汽车数量: library(ggplot2)
mpg
ggplot(mpg, aes(class)) +
geom_bar()
进一步,通过 fill() 参数,用不同颜色表示drv(动力传动系统:前轮f,后轮r,四轮4),填充每个class: library(ggplot2)
mpg
ggplot(mpg, aes(class, fill = drv)) +
geom_bar()
drv是离散型变量,所以可以用不同的颜色区分 如果根据连续型变量hwy(高速公路行驶记录每加仑行驶的英里数)填充class,如果不添加分组信息,则不会有不同颜色填充。 ggplot(mpg, aes(class, fill = hwy)) +
geom_bar()
如果在 fill() 后面添加 group() 参数,设置按 hwy 分组: ggplot(mpg, aes(class, fill = hwy, group = hwy)) +
geom_bar()
就可以形成按照hwy数量大小,渐变填充的状态。 5. 曲面图(Surface Plots)ggplot2包不能绘制3D曲面图像,但是可绘制能表示3D图的2D图像,比如等高线图、着色瓦片图、气泡图等 geom_contour() 等高线图:
library(ggplot2)
faithfuld
# A tibble: 5,625 x 3
eruptions waiting density
1 1.60 43.0 0.00322
2 1.65 43.0 0.00384
3 1.69 43.0 0.00444
4 1.74 43.0 0.00498
5 1.79 43.0 0.00542
6 1.84 43.0 0.00574
7 1.88 43.0 0.00592
8 1.93 43.0 0.00594
9 1.98 43.0 0.00581
10 2.03 43.0 0.00554
# ... with 5,615 more rows
ggplot(faithfuld, aes(eruptions, waiting)) +
geom_contour(aes(z = density, colour = ..level..))
geom_raster() 着色瓦片图:
ggplot(faithfuld, aes(eruptions, waiting)) +
geom_raster(aes(fill = density))
气泡图: library(ggplot2)
faithfuld
# Bubble plots work better with fewer observations
small <> faithfuld[seq(1, nrow(faithfuld), by = 10), ]
ggplot(small, aes(eruptions, waiting)) +
geom_point(aes(size = density), alpha = 1/3) +
scale_size_area()
参考资料: Hadley Wickham(2016). ggplot2. Springer International Publishing. doi: 10.1007/978-3-319-24277-4 《R语言应用系列丛书·ggplot2:数据分析与图形艺术》
|