第四章 用图层构建图像
4.1 简介
本章主要对图层、几何对象、统计变换和位置调整的工作方式做一些技术说明:如何对他们进行调用和自定义。
4.2节将教你如何手动创建一个图形对象。4.3节将教你如何图形最开始不显示,直到至少一个图层被添加后图形才会显示出来。
4.2 创建绘图对象
当我们调用qplot()时,它其实为我们做了很多幕后工作:创建-一个图形对象,添加图层并且展示结果。在整个过程中它使用了很多默认的绘图参数。如果想手动创建图形对象,就要用到ggplot()函数。该函数有两个主要的参数:数据和图形属性映射。这两个参数将被设为绘图的默认参数,只有在新添加的图层里设定了新参数时,默认值才会被修改。参数数据指定绘图所用的默认数据集(必须是数据框);参数映射的设定方法与前面讲过的qplot()非常相似,只需要将图形属性和变量名放到函数aes()的括号里面即可。关于函数aes()的更多细节见4.5节,使用非常简单。下面的例子设定了- -组默认映射: x为carat,y为price, colour 为cut.
p <- ggplot(diamonds, aes(carat, price, colour = cut))
这个图形对象在加上图层之前无法显示,因此你现在什么也看不见。
但是当你保存为图片后,你只能得到一张函数坐标轴的一个图层,因为你没有定义几何对象。
ggsave(file = "test.png", plot = p, width = 4, height = 3)
4.3 图层
添加一个几何对象:
p <- p + layer(geom = "point")
注意我们是如何用+
来添加图层的。该图层使用默认的数据集和图形属性映射,并且使用了另外的两个可选参数的默认值:统计变换和位置调整。下面的图层设定列出了更多可选的参数选项:
layer(geom, geom_params, stat, stat_params, data, mapping, position)
下面的示例代码生成一个组距为2、铁青色的直方图:
# 这段代码我总是运行不成功,不知道是不是版本问题
p <- ggplot(diamonds, aes(x = carat))
p <- p + layer(
geom = "bar",
geom_params = list(fill = "steelblue"),
stat = "bin",
stat_params = list(binwidth = 2)
)
ggsave(file = "test.png", plot = p, width = 4, height = 3)
我么可以使用快捷函数来简化上面代码
p <- p + geom_histogram(binwidth =2, fill = "steelblue")
所有这类快捷函数都有相同的形式——以geom_
或stat_
开头:
geom_XXX(mapping, data, ..., stat, position)
stat_XXX(mapping, data, ..., stat, position)
它们的参数定义了图层的各种组件:
●mapping (可选)
一组图形属性映射,通过aes()函数来设定,详见4.5
节;
●data (可选)
一个数据集,它会修改默认的数据集。大部分情况下该参数被省略掉,默认数据集将被调用。详见4.4节;
- ...geom或stat的参数
例如直方图的组距(binwidth) 或者loess光滑曲线的带宽(bandwidth)。我们也可以用图形属性作为参数,这样该属性就被设定为-一个固定的值,而不是被映射给数据集中的一一个变量。上 面的例子展示了如何将直方图的填充色设为“铁青色”。4.5.2 节给出了更多的例子;
●geom或stat (可选)
我们可以修改geom默认的stat值,或者stat所默认的geom值。它们是一组字符串,包含了将要使用的几何对象或统计
变换的名称四。使用默认值将会得到标准的图形;修改默认值会得到- -些新奇的图形,详见4.9.1节;
●posisition (可选)
选择- -种调整对象重合的方式,详见4.8节。注意,参数data和mapping在ggplot()函数和图层函数中的位置是相反的。这是因为我们在图形对象中一般先设定数据集,而在图层函数中大多是设定图形属性而不是数据集。我建议尽量写清参数名而不要依赖参数的相对位置来设定参数,这样可以使得代码更具可读性,这也是本书遵循的原则之- - 。图层是普通的R对象,所以可以存储到变量里去,这有利于代码避繁就简。例如,- -组图形可以先用不同的数据来进行初始化,然后加上相同的图层,如果后面想改变图层,只需要修改一个地方即可。
4.4 数据
ggplot2要求数据集必须是一个数据框(data frame),由于保存一个数据框要比保存多个向量方便得多,所以无论是向别人发送数据还是让别人重复运行自己的代码,使用数据框都会更方便。
这种限制也可以方便我们用相同的代码、不同的数据集绘图——只需要改变数据集即可:
p1 <- ggplot(mtcars, aes(mpg, wt, colour = cyl)) + geom_point()
mtcars <- transform(mtcars, mpg = mpg^2)
p2 <- p1 %+% mtcars
library(gridExtra)
p <- grid.arrange(p1, p2, ncol=2)
ggsave(file = "test.png", plot = p, width=8, height=3)
数据是以副本而不是引用的形式存储到图形对象中的。这样做有两个重要的好处:其- -,如果你的数据改变了,绘图不会改变。其二,ggplot2 的对象都是自含型的(self- contained),所以它们可以被存储(save())到磁盘上,并且之后可以被直接加载运行(1oad()。
4.5 图形属性映射
aes()函数用来将数据变量映射到图形中,从而使变量成为可以被感知的图形属性。aes()函数里有一系列的图形属性参数:
aes(x= weight, y = height, colour = age)
其中,前两个参数可以省略名字。
注意,你最好不要使用指定数据集以外的变量(例如diamonds$carat),因为这样无法将绘图所用的数据都封装到-一个对象里。
4.5.1 图与图层
图形对象中默认的映射可以在新图层里进行扩充或修改:
p <- ggplot(mtcars, aes(mpg, wt))
p1 <- p + geom_point()
p2 <- p + geom_point(aes(colour = factor(cyl)))
p3 <- p + geom_point(aes(y = disp))
p <- grid.arrange(p1, p2, p3, ncol=3)
ggsave(file = "test.png", plot = p, width=12, height=3)
4.5.2 设定和映射
除了可以将--个图形属性映射到一个变量,你也可以在图层的参数里将其设定为-一个单一值(例如,colour: = "red")。图形属性可以根据观测的不同而变化,但是参数则不行。下面的例子中p1
用图层里的colour参数设定了点的颜色,这里将点的颜色设定为深蓝色。这和p2
的设定有很大区别。
p <- ggplot(mtcars, aes(mpg, wt))
p1 <- p + geom_point(colour = "darkblue")
p2 <- p + geom_point(aes(colour = "darkblue"))
p <- grid.arrange(p1, p2, ncol=2)
ggsave(file = "test.png", plot = p, width=8, height=3)
p2
将colour映射到"darkblue" 颜色。实际上是先创建了一个只含有"darkblue"字符的变量,然后将colour映射到这个新变量。因为这个新变量的值是离散型的,所以默认的颜色标度将用色轮上等间距的颜色,并且此处新变量只有一个值,因此这个颜色就是桃红色。图4.2展示了设定和映射的区别。在使用qplot() 函数的时候,可以将某个值放到I()里来实现映射(例如,colour = I("darkblue"))。 附录B介绍了如何为各种各样的图形属性设定合适的值。
4.5.3 分组
在ggplot2里,几何对象可以大致分为个体(individual) 几何对象和群组(collective)几何对象两大类。个体几何对象对数据框的每一条数据绘制- 一个可以区别于其他个体的图形对象。例如,点几何对象用点来表示每-一条观测。相.反地,群组几何对象用来表示多条观测,它们可以是某个统计摘要的一个结果,或者是几何对象的基础展示,例如多边形。线条和路径介于这两者之间:每条线都由许多线段组成,而每条线段又代表两个点。我们该如何来控制哪些观测值用哪种图形元素呢?这就是分组(group)图形属性的工作。
图中所有离散型变量的交互作用被设为分组的默认值,通常这样可以正确地给数据分组,但是如果没能正确分组或者图中没有离散型变量,那么就需要自定义分组结构,即将group映射到一个在不同的组有不同取值的变量。当现
有的单个变量不能够正确地分组,而两个变量的组合可以正确分组时,可以使用interaction()函数。
通常有三种情况是默认分组不能解决的,下 面我们将一- -介绍。在下面的例子里,我们将用nlme包里的一个简单的纵向数据集0xboys。该数据记录了
26名男孩(Subject) 在9个不同时期(Occasion) 所测定的的身高(height) 和中心化后的年龄(age)。
多个分组与单个图形属性
很多时候,我们都想将数据分成若干组,并用相同的方式对每个组进行渲染。当从总体上来查看数据时,我们通常希望区分每个个体而不是识别他们。这在含有多个个体的纵向数据中是很常见的,而这类图形也常被称为“细面图”
(spaghetti plot)。下图一个时间序列图,每条线代表-个男孩。 通过这个图你可以看到每个男孩的成长轨迹。生成这个图的代码是:
install.packages("nlme")
library("nlme")
Oxboys
p <- ggplot(Oxboys, aes(age, height, group = Subject))
p <- p + geom_line(aes(colour = Oxboys$Subject))
ggsave(file = "test.png", plot = p, width = 8, height = 5)
不同图层上的不同分组
有时我们想根据不同水平下的数据整合来对统计汇总信息(summary)进行图形绘制,从而不同的图层可能有不同的分组图形属性,因此,有的图层展示个体水平的数据,而有的图层则展示更大组群的统计信息。在前面例子的基础上,假设我们想根据所有男孩的年龄和身高在图中添加-.条光滑线条。如果还用和前面绘制折线图时同样的分组方式,一下代码中,p1
将会得到下图左图。
p1 <- p + geom_smooth(aes(group = Subject), method = "lm", se = F)
p2 <- p + geom_smooth(aes(group = 1), method = "lm", size = 2, se = F)
p <- grid.arrange(p1, p2, ncol=2)
ggsave(file = "test.png", plot = p, width = 8, height = 5)
这并不是我们想要的结果;我们无意间给每一个 男孩添加了一条光滑线条。因此,新图层需要- - 个不同的分组图形属性,groupup = 1,这样所绘出的线条才是基于整体数据的,p2
是修改后的代码,将得到右图。
修改默认分组
如果图像中含有离散型变量,而你却想绘制连接所有分组的线条,那么你可以采取绘制交互作用图、轮廓图以及平行坐标图时所用的策略。这里以绘制各个测量时期(Occasion)身高(height) 的箱线图为例,如图4.5的左图所示。
这里没有必要设定组图形属性;因为Occasion是一个离散型变量,所以默认的分组变量就是0ccasion。要在此基础上添加个体轨迹,我们需要用aes(group = Subject)修改第- -层的默认分组,如图4.5 的右图所示。
p <- ggplot(Oxboys, aes(Occasion, height))
p1 <- p + geom_boxplot(colour = rainbow(9))
p2 <- p1 + geom_line(aes(group = Subject), linetype = "dashed", alpha = 0.5)
p <- grid.arrange(p1, p2, ncol=2)
ggsave(file = "test.png", plot = p, width = 8, height = 5)
如果想用箱线图来查看每个时期的身高分布,默认的分组是正确的(左图)。如果想用geom. line()添加每个男孩的轨迹,就需要在新图层里设定aes(group = Subject)(右图)。在第二个图层中,我们改变了线条的颜色以区别箱线图。这又是一个将某个图形属性设定为固定值的例子。此处颜色是一个渲染属性,在数据中没有相对应的变量。
4.5.4 匹配图形属性和图形对象
4.6几何对象
几何图形对象,简称geom,控制着图像的类型。ggplot2中所有可用的几何对象如图所示:
每种几何对象都有一组它能识别的图形属性和一组绘图所需的值。所有几何对象的图形属性值如图所示:
4.7 统计变换
统计变换,简称stat,即对数据进行统计变换,它通常以某种方式对数据信息进行汇总。
下图列出了目前可用的统计变换。为了阐明在图形中的意义,一个统计变换必须是一个位置尺度不变量,即 并且。这样才能保证当改变图形的标度时,数据变换保持突变。
统计变换可将输入的数据集看做输入,将返回的数据集作为输出,因此统计变换可以向源数据中插入新的变量。例如,常被用来绘制直方图的stat_bin统计变换会生成如下变量:
- count,每个组里观测值的数目;
- density,每个组里观测度的密度(占整体的百分数/组宽);
- x,组的中心位置。
这些生成的变量可以被直接调用。例如,直方图默认将条形图的高度赋值为观测值的频数(count),如果你更喜欢传统的直方图,你可以用密度(density)来代替。下面的例子给出了钻石数据集中的克拉(carat)的密度直方图。
生成的变量的名字必须要用..
围起。这样可以防止原数据集中的变量和生成变量重命名时造成混淆,并且以后处理代码时,你可以很清晰得分辨出哪些变量是统计变换生成的。每个统计变换的帮助文档里都列出了其生成变量的名称。
4.8 位置调整
位置调整即对该层中的元素位置进行微调,下表列出了ggplot2中所有可用的位置调整参数。位置调整一般多见于处理离散型数据,因为连续型数据一般很少出现完全重叠的问题。
网友评论