本章主要介绍ggplot2的理论基础:图形图层语法
图形图层语法基于Wilkinson的图形语法,并在此基础上添加了许多新功能,使得图形更有表现力,并能完美嵌入到R环境中
在本章中,将简单学习一些语法组成组件的基本知识,学习如何将它们整合到一起
ggplot2的语法使得图形的重复更新变得简单,每次只需更新一个特征。ggplot2语法的价值在于它从更高的视角审视了图形的构成,它认为图形的每个组件都是可以修改的,为你提供一个关于图像的思考框架
1. 绘制散点图
发动机的尺寸和燃油的关系是怎样的?可以根据数据集创建一个关于发动机耗油量和高速公路每加仑行驶的英里数的箱线图
ggplot(mpg, aes(displ, hwy, color = factor(cyl))) + geom_point()
1. 图形属性和数据的映射
在散点图中,每一个观测值都用一个点来表示,点的位置由两个变量的值决定
每个点不仅有横坐标和纵坐标,还有大小、颜色和形状,这些属性称为图形属性(aesthetics)
每个图形属性都可以映射为一个变量或者设定为一个常数
在散点图中,用点来表示每个观测,倘若用直线连接所有观测,则会得到折线图。如果用条形来表示这些数据,就会得到条形图。不过对于这个数据集而言,折线图和条形图是没有意义的
ggplot(mpg, aes(displ, hwy, color = factor(cyl))) +
geom_line() + theme(legend.position = "none")
ggplot(mpg, aes(displ, hwy, color = factor(cyl))) +
geom_bar(stat = "identity", position = "identity", fill = NA) +
theme(legend.position = "none")
在ggplot2中,可以作出很多没有意义但符合语法的图形
点(point)、线(line)和条(bar)都是几何对象的具体形式,被称为geom
几何对象决定了图形的“类型(type)”
只含一种几何对象的图通常有特定的名字
图形名称 | 几何对象(geom) |
---|---|
散点图 | 点 |
气泡图 | 点 |
条形图 | 条形 |
箱型图 | 箱子 |
折线图 | 线 |
更复杂的图形一般没有特定的名称,因而需要一定的描述
下图在散点图的基础上对每个组添加了回归线
ggplot(mpg, aes(displ, hwy, color = factor(cyl))) +
geom_point() + geom_smooth(method = "lm")
2. 标度变换
前面表中的数值对于电脑而言没有任何意义,需要把它们从数据单位(如升、英里每加仑和气缸数)转换成电脑可以识别的物理单位(如像素和颜色)
这个转换过程称之为标度变换(scaling)
转换后的数据:颜色用六个字母组成的十六进制字符来表示,大小和形状分别用数字和整数来表示
这些R可以识别的图形属性值可参见vegnette(“ggplot2-specs”)
在这个例子中,有3个图形属性需要进行标度变换:水平位置(x)、竖直位置(y)和颜色(color)
在这个例子中,位置变换非常简单,因为我们用的是默认的线性变换,只需要将数据的范围线性映射到[0, 1]区间上即可
因为ggplot2调用的绘图系统grid包会帮忙处理好最终的转换细节,所以采用的是[0, 1]而不是精确的像素值
最后一步是如何根据点的位置(x和y)来确定它在图中的位置,这是由坐标系统决定的写作coord
大多数情况下,默认使用笛卡尔坐标系,不过有时也会采用极坐标系或用地图中的球投影
颜色可看作由3种组件组成,它们与人眼中识别颜色的3种细胞相对应,这3种细胞建立了一个三维的颜色空间,颜色的标度变换就是将数据的值映射到这个空间中
映射方法有很多,由于此处cyl是分类变量,所以把它等距地映射到色轮上,当变量是连续型时,将使用其它映射方法
点默认使用直径为1毫米的圆圈(R中标号19的形状)来表示
最后,还需要对这些数据进行渲染,生成能在屏幕上展示的图形。绘制一个完整的图形,需要3类图形对象:数据,用点来表示;标度和坐标系,用来生成坐标轴和图例,通过它们才能读出图中蕴含的信息;图形注释,如背景和标题
3. 更复杂的图形示例
ggplot(mpg, aes(displ, hwy)) + geom_point() +
geom_smooth() + facet_wrap(~year)
这幅图添加了3种新的组件:分面、多个图层和统计量
分面和图层将原数据切割成多个小数据集,即每个图层的每个分面面板(facet panel)都含一个小数据集
可以将它想象成一个三维矩阵:分面面板形成了一个二维网络,图层在第三维的方向上叠加。本例中所有图层的数据都是一样的,但是一般而言,可以在不同图层里使用不同的数据集
平滑曲线层与散点层的不同点在于它没有展示原数据,而是展示了统计变换后的数据。特别地,平滑曲线层模拟了一条穿过数据中间位置的平滑曲线。添加该图层需要在前面介绍过的流程里面再添加一步:将数据映射到图形属性后,要对其进行统计变换(对数据进行有效的处理),统计变换简写为stat。在本例中,统计变换首先用一条loess平滑曲线来拟合数据,然后在数据的范围内,利用等间隔的点,计算并返回点所对应的预测值
其它有用的统计变换包括1维和2维的封箱(binning),求组平均(group means),分位数回归(quantile regression)和等高线(contour)
因为添加了统计变换,所以在进行标度变换时需要添加额外的步骤
这是因为现在有多个数据集(对不同的分面和图层而言),所以需要确保所有的变换在各个数据集里都是相同的。标度变换实际上出现在三个地方:标度转换(transforming),标度训练(training)和标度映射(mapping)
在双对数图中,数据值不是直接线性映射到图形上的位置,而是先进行了对数变换
-
标度转换先于统计变换,因此统计量都是基于标度变换后的数据计算的。这样可以确保log(x)对log(y)在线性尺度上的图与x对y在对数尺度上的图看起来一样。另外,还有其它不同的变换可以使用,包括取平方根、对数和倒数。详见来连续的位置标度
-
计算完统计量之后,所有分面和图层的数据集中的每个标度都会被“训练”。标度训练将根据所有小数据集里数据的范围得到整体数据的范围。如果没有这一步,标度将只具有局部意义,当将不同的层叠加在一起时,它们的位置就会错乱。不过有些时候我们也需要得到不同分面间(绝不是图层间)标度有错位的图形,这种情况详见标度控制
-
最后,标度映射将数据映射到图形属性中。这是一个局部操作:每个数据集里的变量都映射给相应的图形属性值,生成一个新的数据集后再用几何对象来渲染