第4章 用图层构建图像
每个图层孝可以有自己的数据集和图形属性映射,附加的数据元素可以通过图层添加到图形中。
4.2 创建绘图对象
ggplot()函数,有两个主要参数:数据和图形属性映射。这两个参数被设定为绘图的默认参数,只有在新添加的图层里设定新的参数时,默认值都会被修改。
- 数据data,指定绘图所用的默认数据集(必须是数据框dataframe);
- 映射mapping,将图形属性和变量名放至函数aes()内。
p <- ggplot(diamonds, aes(carat, price, colour = cut))
这个图形对象在加上图层之前无法显示。
4.3 图层
因为每一个几何对象都对应着一个默认的统计变换和位置参数,而每一个统计变换都对应着一个默认的几何对象参数,所以对于一个图层,我们只需要设定stat或geom参数即可。
- geom_XXX(mapping, data, ..., stat, position)
- stat_XXX(mapping, data, ..., geom, position)
它们的参数定义了图层的各种组件:
- mapping(可选): 一组图形属性映射,通过aes()函数来设定;
- data(可选):一个数据集,可以修改默认数据集;
- ...:geom或stat的参数,如直方图的组距(binwidth)或者loess曲线的带宽(bandwidth)。
- geom或stat(可选):可以修改geom默认的stat值,或stat默认的geom值。它们是一组字符串,包含了将要使用的几何对象或统计变换的名称。
- position(可选):选择一种调整对象重合的方式。
注意,在图形对象中一般先设定数据集,而在图层函数中一般先设定图形属性。
4.4 数据
数据集必须是一个数据框(data frame)。
数据是以副本而不是引用的形式存储到图形对象中。有两个好处:
- 如果数据变了,绘图不会改变;
- ggplot2的对象都是自含型的(self-contained),可以被存储到磁盘上,并可以被直接加载运行(load())。
4.5 图形属性映射
aes()函数用来将数据变量映射到图形中,从而使变量成为可以被感知的图形属性。
aes(x=weight, y=height, colour=age)
4.5.1 图和图层
默认的图形属性映射可以在图形对象初始化时设定,
p <- ggplot(mtcars, aes(x=mpg, y=wt))
p + geom_point()
或者过后用+修改。
p + geom_point(aes(colour = factor(cyl))
p + geom_point(aes(y=disp))
p <- ggplot(mtcars, aes(x=mpg, y=wt))
p1 <- p + geom_point()
p2 <- p + geom_point(aes(colour = factor(cyl))) #添加
p3 <- p + geom_point(aes(y=disp)) #修改
grid.arrange(p1, p2, p3, ncol=3)
一个图层里设定的图形属性映射只对该图层起作用。因此第三张图只改变了坐标点(aes(mpg,disp)),并没有改变坐标轴标签(wt)。
4.5.2 设定和映射
除了可以将一个图形属性映射到一个变量,也可以在图层的参数将其设定为一个单一值,如colour="red"。
p <- ggplot(mtcars, aes(mpg,wt))
p1 <- p + geom_point(colour = "darkblue") #将点设定为深蓝色。
p2 <- p + geom_point(aes(colour="darkblue")) #将colour映射到“darkblue”颜色
grid.arrange(p1,p2, ncol=2)
第二张图,将将colour映射到“darkblue”颜色。实际上是先创建了一个只含有“darkblue"字符的变量,然后将colour映射到这个新变量。因为这个新变量的值是离散型的,所有默认的颜色标度用色轮上等间距的颜色,并且由于只有一个值,所以这个颜色就是默认的桃红色。
4.5.3 分组
在ggplot2中,几何对象可以大致分为个体几何对象和群组几何对象两大类:
- 个体(individual)几何对象,对数据框的每一条数据绘制一个可以区别于其他个体的图形对象。如,点几何对象用点来表示每一条观测。
- 群组(collective)几何对象,用来表示多条观测,它们可以是某个统计摘要的一个结果,或者是几何对象的基础展示,如多边形。
- 线条和路径介于两者之间:每条线都由许多线段组成,每条线段又代表两个点。
分组(group)图形属性的工作就是控制哪些观测值用哪种图形元素。
- 图中所有离散型变量的交互作用被设为分组的默认值。
- 如果没能正确分组或者图中没有离散型变量,那么就需要自定义分组结构,即将group映射到一个在不同的组有不同取值的变量。
- 当现有的单个变量不能够正确地分组,而两个变量的组合可以正确分组时,使用interactio()函数。
下面的案例使用nlme包里的一个简单的纵向数据集Oxboys。该数据记录了26个男孩(Subject)在9个不同时期(Occasion)所测定的身高(height)和中心化后的年龄(age)。
多个分组与单个图形属性
library(nlme)
p1 <- ggplot(Oxboys, aes(age, height, group=Subject)) + geom_line()
p2 <- ggplot(Oxboys, aes(age, height)) + geom_line()
grid.arrange(p1,p2,ncol=2)
这里指定Subject为分组变量,每个男孩对应一条线。如果不指定,就会得到一条通过每个点的单一线条,没有任何意义。
不同图层上的不同分组
根据不同水平下的数据整合来对统计汇总信息(summary)进行图形绘制。
即,有的图层展示个体水平的数据,有的图层展示更大组群的统计信息。
假设我们想根据所有男孩的年龄和身高在图中添加一条光滑线条。
library(nlme)
p <- ggplot(Oxboys, aes(age, height, group=Subject)) + geom_line()
p1 <- p+geom_smooth(aes(group=1), method="lm", size=2, se=F)
p1
新图层需要一个不同的分组图形属性,group=1,绘出的线条是基于整体数据的。如果是group=Subject,则给每个男孩添加一条光滑线条。
修改默认分组
如果图像中含有离散型变量,而你却想绘制连贯所有分组的线条,那么你可以采取绘制交互作用图、轮廓图以及平行坐标图时所用的策略。
以绘制各个测量时期(Occasion)身高(height)的箱线图为例,
#Occasion是一个离散型变量,所以默认分组变量是Occasion。
boysbox <- ggplot(Oxboys, aes(Occasion, height)) + geom_boxplot()
#添加个人轨迹,用aes(group=Subject)修改第一层的默认分组。
boysbox2 <- boysbox + geom_line(aes(group = Subject), colour="darkblue")
grid.arrange(boysbox, boysbox2, ncol=2)
4.5.4 匹配图形属性和图形对象
(省略)
4.6 几何对象
- 几何对象简称geom,执行图层的实际渲染,控制生成的图像类型。如用点几何属性(point geom)将会生成散点图。
- 每个几何对象都有一组它能识别的图形属性和一组绘图所需的值。例如,一个点含有颜色、大小、和形状等图形属性,以及x和y位置坐标。
- 每个几何对象都有一个默认的统计变换,并且每一个统计变换都有一个默认的几何对象。如封箱(bin)统计变换默认使用条状几何对象(bar geom)来绘制直方图。
名称 | 描述 | 默认统计变换 | 图形属性 |
---|---|---|---|
abline | 线,由斜率和截距决定 | abline | colour, linetype, size |
area | 面积图(area plot) | identity | colour, fill, linetype, size, x, y |
bar | 条形图 | bin | colour, fill, linetype, size, weight, x |
bin2d | 2维热图 | bin2d | colour, fill, linetype, size, weight, xmax, xmin, ymax, ymin |
blank | 空白,什么也不画 | identity | |
boxplot | 箱线图 | boxplot | colour, fill, lower, middle, size, weight, x, ymax, ymin |
contour | 等高线图 | contour | colour, fill, linetype, size, weight, x, y |
crossbar | 带水平中心线的盒子图 | identity | colour, linetype, size, weight, x, y, ymax, ymin |
density | 光滑密度曲线图 | density | colour, fill, linetype, size, weight, x, y |
density2d | 2维密度等高线图 | density2d | colour, fill, linetype, size, weight, x, y |
dotplot | 点直方图,用点表示观测值的个数 | bindot | colour, fill, x, y |
errorbar | 误差棒 | identity | colour, linetype, size, width, x, ymax, ymin |
errorbarh | 水平误差棒 | identity | colour, linetype, size, width, y, ymax, ymin |
freqpoly | 频率多边形图 | bin | colour, fill, linetype, size, weight, x |
hex | 用六边形表示的2维热图 | binhex | colour, fill, size, x, y |
histogram | 直方图 | bin | colour, fill, linetype, size, weight, x |
hline | 水平线 | hline | colour, fill, linetype, size |
jitter | 给点添加扰动,减轻图形重叠问题 | identity | colour, fill, shape, size, x, y |
line | 按x坐标的大小顺序依次连接各个观测值 | identity | colour, linetype, size, x, y |
linerange | 一条代表一个区间的竖直线 | identity | colour, linetype, size, x, ymax, ymin |
map | 基准地图里的多边形 | identity | colour, fill, linetype, size, x, y, map_id |
path | 按数据的原始顺序连接各个观测值 | identity | colour, linetype, size, x, y |
point | 散点图 | identity | colour, fill, shape,size, x, y |
pointrange | 用一条中间带点的竖直线代表一个区间 | identity | colour, fill, linetype, shape size, x, y, ymax, ymin |
polygon | 多边形,相当于一个有填充的路径 | identity | colour, fill, linetype, size, x, y |
quantile | 添加分位数回归线 | quantile | colour, linetype, size, weight, x, y |
raster | 高效的矩形瓦片图 | identity | colour, fill, linetype, size, x, y |
rect | 2维的矩形图 | identity | colour, fill, linetype, size, xmax, xmin, ymax, ymin |
ribbon | 色带图,连续的x值所对应的y的范围 | identity | colour, fill, linetype, size, x, ymax, ymin |
rug | 边际地毯图 | identity | colour, linetype, size |
segment | 添加线段或箭头 | identity | colour, linetype, size, x, xend, y, yend |
smooth | 添加光滑的条件均值线 | smooth | alpha, colour, fill, linetype, size, weight, x, y |
step | 以阶梯形式连接各个观测值 | identity | colour, linetype, size, x, y |
text | 文本注释 | identity | angle, colour,hjust, label, size, vjust, x, y |
tile | 瓦片图 | identity | colour, fill, linetype, size, x, y |
violin | 小提琴图 | ydensity | weight, colour, fill, size, linetype, x, y |
vline | 竖直线 | vline | colour, linetype, size |
4.7 统计变换
统计变换,简称stat,即对数据进行统计变换,通常以某种方式对数据信息进行汇总民。
名称 | 描述 |
---|---|
bin | 计算封箱(bin)数据 |
bin2d | 计算矩形封箱内的观测值个数 |
bindot | 计算“点直方图”的封箱数据 |
binhex | 计算六边形热图的封箱数据 |
boxplot | 计算组成箱线图的各元素值 |
contour | 三维数据的等高线 |
density | 一维密度估计 |
density2d | 二维密度估计 |
function | 添加新函数 |
identity | 不对数据进行统计变换 |
计算qq图的相关值 | |
quantile | 计算连续的分位数 |
smooth | 添加光滑曲线 |
spoke | 将角度和半径转换成xend和yend |
sum | 计算每个单一值的频数,有助于解决散点图的图形重叠问题 |
summary | 对每个x所对应的y值做统计描述 |
summary2d | 对2维矩形封箱设定函数 |
summaryhex | 对2维六边形封箱设定函数 |
unique | 删除重复值 |
ydensity | 小提琴图,计算1维y轴方向的核密度函数估计值 |
统计变换可将输入的数据集看做输入,将返回的数据集作为输出,因此统计变换可以向原数据集中插入新的变量。
例如,直方图的stat_bin统计变换会生成如下变量:
- count, 每个组里观测值的数目;
- density, 每个组里观测值的密度(占整体的百分数/组宽);
- x, 组的中心位置。
这些生成的变量可以被直接调用。生成变量的名字必须要用..围起来。这样可防止原数据集中的变量与生成变量重名时造成的混淆。
ggplot(diamonds, aes(carat)) + geom_histogram(aes(y=..density..), binwidth = .1)
4.8 位置调整
位置调整,即对该层中的元素位置进行微调。
位置调整,一般多见于处理离散型数据。
名称 | 描述 |
---|---|
dodge | 避免重叠,并排放置 |
fill | 堆叠图形元素并将高度标准化为1 |
identity | 不做任何调整 |
jitter | 给点添加扰动避免重合 |
stack | 将图形元素堆叠起来 |
p1 <- ggplot(diamonds, aes(x=clarity)) + geom_bar(aes(fill=cut), position="stack")
p2 <- ggplot(diamonds, aes(x=clarity)) + geom_bar(aes(fill=cut), position="fill")
p3 <- ggplot(diamonds, aes(x=clarity)) + geom_bar(aes(fill=cut), position="dodge")
grid.arrange(p1,p2,p3, ncol=2)
4.9 整合
4.9.1 结合几何对象和统计变换
d <- ggplot(diamonds, aes(carat)) + xlim(0,3)
d1 <- d+stat_bin(aes(ymax=..count..), binwidth = 0.1, geom="area")
d2 <- d+stat_bin(aes(size=..density..), binwidth = 0.1, geom="point", position="identity")
# d3 <- d+stat_bin(aes(y=1, fill=..count..), binwidth = 0.1, geom="tile", position="identity")
grid.arrange(d1, d2, ncol=2)
d+stat_bin(aes(y=..count.., linetype=cut), binwidth = 0.1, geom="line", position="identity")
4.9.2 显示已计算过的统计量
如果你有已经汇总过的数据,并想直接用它,而不进行其他统计变换,可以使用stat_identity(),然后将合适的变量映射到相应的图形属性中。
4.9.3 改变图形属性和数据集
如何结合统计模型输出的结果和原始数据来更深刻地理解数据和模型。
require(nlme, quiet=TRUE, warn.conflicts = FALSE)
#拟合一个截距和斜率都包含随机效应的混合模型
model <- lme(height ~ age, data=Oxboys, random = ~ 1+age|Subject)
oplot <- ggplot(Oxboys, aes(age, height, group=Subject))+geom_line()
#建立一个包含所有年龄(age)和个体(subjects)组合的网络数据框。
age_grid <- seq(-1, 1, length=10)
subjects <- unique(Oxboys$Subject)
preds <- expand.grid(age=age_grid, Subject=subjects)
#把模型的预测值添加到新变量height
preds$height <- predict(model, preds)
#把预测值和原始数据绘制到同一张图上
oplot+geom_line(data=preds, colour="red", size=0.4)
#比较模型拟合好坏的另一种方法是观察残差。
#把拟合值(fitted)和残差(resid)都添加到原数据里。
Oxboys$fitted <- predict(model)
Oxboys$resid <- with(Oxboys, fitted-height)
#更新数据集(用%+%),将默认的y图形属性改为resid,最后对整个数据添加一条光滑曲线。
oplot %+% Oxboys +aes(y=resid) +geom_smooth(aes(group=1))
#向模型添加二次项,再次计算拟合值和残差并重新绘制残差图。
model2 <- update(model, height ~ age + I(age^2))
Oxboys$fitted2 <- predict(model2)
Oxboys$resid2 <- with(Oxboys, fitted2-height)
oplot %+% Oxboys + aes(y=resid2) + geom_smooth(aes(group=1))