ggplot2包的目的是提供一个全面的、基于语法的、连贯一致的图形生成系统,允许用户创建新颖的、有创新性的数据可视化图形。
1、简介ggplot2语法
下面将从一个例子来看看ggplot2的基本语法。
library(ggplot2) # 载入ggplot2包
ggplot(data=mtcars, aes(x=wt,y=mpg)) + # 指定绘图的数据 (1)
geom_point(pch=17,color='red',size=2) + # 绘图函数及其参数 (2)
geom_smooth(method='lm',color='green',linetype=2) + # 绘图函数(拟合曲线)(3)
labs(title='ggplot2', x='Weight', y='MPG') + # 添加注释信息(标题)(4)
theme(plot.title = element_text(hjust = 0.5)) # 调整标题位置 (5)
现在我们来一步步解析上面的代码:
(1)初始化图形并指定要用到的数据来源(mtcars)和变量(wt、mpg)。aes()
函数指定每个变量扮演的角色,这里的wt映射到x轴数值,mpg映射到y轴数值。当需要对数据进行分类时,还可将分类因子映射到图形性状或颜色上面;
(2)绘图函数(也称几何函数)使用一个或几个函数向图中添加几何对象(简写为geom),包括点、线、条、箱线图和阴影区域,这里向图中添加了散点图以及一条拟合曲线(代码3)。当需要在一个图中使用多个数据来源进行画图时,可以单独在每个几何函数中指定数据源;
(4)labs()
函数是可选的,用来添加注释(包括轴标签和标题信息);
(5)theme()
函数用来设置全局配置,这里设置了标题的位置为中间;
除了上面的一些基本设置外,ggplot2还提供了分组和小面化(faceting)以及图形组合的方法,这些较为高级的方法将在下面进行介绍。
2、几何函数
ggplot()
函数可用来指定要绘制的数据源和变量,也可不在ggplot()中设置而在每个几何函数中单独设置所用的数据源及变量,几何函数则指定了这些变量如何在视觉上进行展示(点、线、条、箱线图等)。使用命令ls(pattern = '^geom_', env = as.environment('package:ggplot2'))
可以查看所有可用的几何函数,常用的几何函数如下表:
函数 | 图形 | 常用选项 |
---|---|---|
geom_bar() | 条形图 | color、fill、alpha |
geom_boxplot() | 箱线图 | color、fill、alpha、notch、width |
geom_density() | 密度图 | color、fill、alpha、linetype |
geom_hist0gram() | 直方图 | color、fill、alpha、linetype、binwidth |
geom_hline() | 水平线 | color、alpha、linetype、size |
geom_jitter() | 抖动图 | color、size、alpha、shape |
geom_line() | 线图 | colorvalpha、linetype、size |
geom_point() | 散点图 | color、alpha、shape、size |
geom_rug() | 地毯图(轴须图) | color、size |
geom_smooth() | 拟合曲线 | method、formula、color、fill、linetype、size |
geom_text() | 文字注解 | 很多,参加函数帮助 |
geom_violin() | 小提琴图 | color、fill、alpha、linetype |
geom_vline() | 垂线 | color、alpha、linetype、size |
对于几何函数中每个选项的意义,详见下表:
选项 | 详述 |
---|---|
color | 对点、线和填充区域的边界进行着色 |
fill | 对填充区域着色,如条形和密度区域 |
alpha | 颜色的透明度,从0(完全透明)到1(不透明) |
linetype | 线条类型,1=实线,2=虚线,3=点,4=破折号,5=长破折号,6=双破折号 |
size | 点的尺寸和线的宽度 |
shape | 点的性状(和pch一样,0=方形,1=圆形,2=三角形,等等) |
position | 绘制诸如条形图和点等对象的位置。对于条形图来说,‘dodge’将分组条形图并排,‘stacked’则为堆叠条形图,‘fill’标准化堆叠条形图。对于点来说,‘jitter’抖动减少点重叠 |
binwidth | 直方图的宽度 |
notch | 表示方块图是否为缺口(TRUE、FALSE),常见于箱线图 |
sides | 地毯图的安置('b'=底部,'l'=左部,'t'=顶部,'r'=右部,'bl'=左下部,等等) |
width | 箱线图的宽度 |
library(ggplot2)
mtcars$am <- factor(mtcars$am, levels=c(0,1), labels=c('Automatic', 'Manual'))
ggplot() +
geom_point(data=mtcars, aes(x=wt,y=mpg,shape=am, color=am),size=2) + # 性状和颜色都使用am进行分组
geom_smooth(data=mtcars, aes(x=wt,y=mpg),method='lm',color='green',linetype=2) +
labs(title='ggplot2', x='Weight', y='MPG') +
theme(plot.title = element_text(hjust = 0.5))
下图是对例子的一个改进,在上面的代码中可以看到,我们将数据分别放在了各个几何函数中,之所以这么做是为了对所有的数据进行拟合曲线,若将数据源一起放在ggplot()
中进行设置的话,后面进行数据拟合的话会分别对am的分组数据进行拟合。
下面再看一个箱线图的简单例子。
> library(ggplot2)
> mtcars$am <- factor(mtcars$am, levels=c(0,1), labels=c('Automatic', 'Manual'))
> mtcars$cyl <- factor(mtcars$cyl, levels=c(4,6,8), labels=c('cyl-4', 'cyl-6','cyl-8'))
> ggplot(data=mtcars, aes(x=cyl, y=mpg, fill=am)) + # 使用am填充分组
+ geom_boxplot() +
+ labs(title='ggplot2', x='cyl', y='MPG') +
+ theme(plot.title = element_text(hjust = 0.5))
在这里我们使用箱线图展示了cyl和mpg的关系,并使用am进行了二次分组,分组方式为填充颜色表示(fill=am
)。
最后我们再来看一个使用了多个几何函数的图形,该图形使用的是Salaries数据集。
> data(Salaries,package='car')
> ggplot(Salaries, aes(x=rank, y=salary)) +
+ geom_boxplot(fill='cornflowerblue', color='black',notch=TRUE) + # 添加箱线图
+ geom_point(position='jitter',color='blue',alpha=0.5) + # 添加打散(jitter)了的散点图
+ geom_rug(sides='l',color='green') # 在左侧添加轴须图
+ labs(title='ggplot2') # 添加标题,默认添加在左上方
3、分组
通常为了更好地理解数据,在一个图中画出两个或更多组的观察值通常都是很有帮助的。ggplot2中的分组是通过一个或多个带有诸如性状、颜色、填充、尺寸和线条类型的视觉特征的分组变量来完成的。ggplot2中的aes()
函数负责分配变量(图形的视觉特征),所以这是一个分配分组变量的自然地方。
这里我们将继续使用Salaries数据集,首先来查看下薪水是如何随学术等级而变化的。代码:
> ggplot(data=Salaries, aes(x=salary, fill=rank)) + # 根据学术等级rank进行分类
+ geom_density(alpha=0.3) # 添加密度图
从图中可以看到不同学术等级的薪水虽然有重叠,但仍能看到随着学术水平的增加薪水提高了。接下来,我们通过性别和学术等级分组,绘制获得博士学位年数与薪水的关系,代码:
> ggplot(Salaries, aes(x=yrs.since.phd, y=salary, color=rank, shape=sex)) +
# 这里使用了两个分组变量sex和rank,在图中分别通过不同的颜色和不同的形状表示
+ geom_point()
最后,选项可以通过不同的方式使用,这取决于他们发生在
aes()
函数内部还是外部。让我们比较下面的一段代码绘制的图形:
> p1<-ggplot(Salaries, aes(x=rank, fill=sex)) + geom_bar()
> p2<-ggplot(Salaries, aes(x=rank)) + geom_bar()
> p3<-ggplot(Salaries, aes(x=rank,fill='red')) + geom_bar()
> p4<-ggplot(Salaries, aes(x=rank)) + geom_bar(fill='red')
> library(gridExtra)
> grid.arrange(p1,p2,p3,p4,ncol=4) # 组合图形
在第一个图(p1)中,sex变量通过条形图中的填充颜色来展示。在第二个图(p2)中,没有设置分组变量也没有设置填充颜色,只绘制了各个rank的数量。第三个图(p3)中,ggplot2假定‘red’是变量名,结果得到的结果与图2基本相同。第四个图(p4),使用红色来填充图形。
4、刻面
如果组在图中并排出现而不是重叠为单一的图形,关系就是清晰的。我们可以使用facet_wrap()
和facet_grid()
函数创建网格图形(也称刻面图)。这些函数的使用方法如下,其中var,rowvar,colvar是因子:
语法 | 结果 |
---|---|
facet_wrap(~var, ncol=n) | 将每个var水平排列成n列的独立图 |
facet_wrap(~var, nrow=n) | 将每个var水平排列成n行的独立图 |
facet_grid(rowvar~colvar) | rowvar和colvar组合的独立图,其中rowvar表示行,colvar表示列 |
facet_grid(rowvar~.) | 每个rowvar水平的独立图,配置成一个单列 |
facet_grid(.~colvar) | 每个colvar水平的独立图,配置成一个单行 |
接下来我们使用mtcars数据,以am和cyl作为分组变量对mpg进行分组绘制直方图。
library(ggplot2)
mtcars$am <- factor(mtcars$am, levels=c(0,1), labels=c('Automatic', 'Manual'))
mtcars$cyl <- factor(mtcars$cyl, levels=c(4,6,8), labels=c('cyl-4', 'cyl-6','cyl-8'))
ggplot(data=mtcars, aes(x=mpg)) +
geom_histogram(fill='green') +
facet_wrap(~cyl, nrow=1) # 使用cyl作为分组变量将mpg分组绘制
library(ggplot2)
mtcars$am <- factor(mtcars$am, levels=c(0,1), labels=c('Automatic', 'Manual'))
mtcars$cyl <- factor(mtcars$cyl, levels=c(4,6,8), labels=c('cyl-4', 'cyl-6','cyl-8'))
ggplot(data=mtcars, aes(x=mpg)) +
geom_histogram(fill='green') +
facet_grid(am~cyl) # 同时使用am和cyl作为分组变量,交叉分组
5、拟合曲线
选项 | 描述 |
---|---|
method | 使用的平滑函数。可选的值包括lm, glm, smooth,rlm和gam,分别对应线性,广义线性,loess,健壮线性和广义相加模型。默认为smooth |
formula | 在光滑曲线中使用的公式,例如y~x ,y~log(x) ,y~poly(x, n) |
se | 绘制置信区间。默认为TRUE |
level | 使用的置信区间水平(默认为95%) |
fullrange | 指定拟合应涵盖全图(TRUE)或仅仅是数据(FALSE),默认为FALSE |
本部分我们将分析一下添加平滑曲线(线性,非线性和非参数)到散点图中的方法。我们可以使用geom_smooth()
函数来添加一系列平滑曲线和置信区域。函数的参数见下表:
选项 | 描述 |
---|---|
method | 使用的平滑函数。可选的值包括lm, glm, smooth,rlm和gam,分别对应线性,广义线性,loess,健壮线性和广义相加模型。默认为smooth |
formula | 在光滑曲线中使用的公式,例如y~x ,y~log(x) ,y~poly(x, n) |
se | 绘制置信区间。默认为TRUE |
level | 使用的置信区间水平(默认为95%) |
fullrange | 指定拟合应涵盖全图(TRUE)或仅仅是数据(FALSE),默认为FALSE |
这里使用Salaries数据集,我们先检验博士毕业年数和薪水之间的关系。在这个例子中,我们使用带有95%置信区间的非参数光滑曲线(loess)。暂时忽略学术等级和性别,代码:
> data(Salaries, package='car')
> library(ggplot2)
> ggplot(data=Salaries, aes(x=yrs.since.phd, y=salary)) +
+ geom_point() +
+ geom_smooth(color='red')
图形显示,随着博士毕业年数的增加,薪水先增加后来又会降低。
接下来,我们按性别拟合一个二次多项式回归(一个弯曲):
> ggplot(data=Salaries, aes(x=yrs.since.phd, y=salary, linetype=sex, color=sex, shape=sex)) +
+ geom_smooth(method=lm, formula=y~poly(x,2),se=FALSE,size=1) +
+ geom_point(size=2)
正如前面第一部分我们说的那样,当使用全局的数据源(在ggplot中设置)时,我们会拟合出分类数条曲线。这里我们分别对女性和男性的薪水随博士毕业年限的变化拟合了两条曲线。
6、修改ggplot2图形的外观
在R基本绘图中,我们可以使用par()
函数定义全局参数。在ggplot2中提供了特定的函数来改变图形外观。
6.1 坐标轴
ggplot2在创建图形时会自动创建刻度线、刻度标记和坐标轴标签,有时我们可能想自定义这些图形。前面我们已经看到了labs()
函数可以用来添加标题和轴标题,本节中我们将自定义轴标签,自定义轴标签的函数如下:
函数 | 选项 |
---|---|
scale_x_continous()、scale_y_continous | breaks=指定刻度标记,labels=指定刻度标记标签,limits=控制要展示的值得范围 |
scale_x_discret()和scale_y_discret() | breaks=对因子的水平进行放置和排序,labels=指定这些水平的标签,limits=表示那些水平应该展示 |
coord_flip() | 颠倒X轴和Y轴 |
可以看到,ggplot2的函数区分x轴和y轴,以及轴线是否代表一个连续或离散变量(因子)。
下面我们将这些函数应用到一个分组箱线图中,其中包含按学术等级和性别分组的薪资水平,代码:
> ggplot(data=Salaries, aes(x=rank, y=salary, fill=sex)) +
+ geom_boxplot() +
+ scale_x_discrete(breaks=c('AsstProf', 'AssocProf', 'Prof'),
labels=c('Assistant\nProfessor', 'Associate\nProfessor', 'Full\nProfessor')) +
+ scale_y_continuous(breaks=c(50000, 100000, 150000, 200000),
labels=c('$50K','$100K','$150K','$200K')) +
+ labs(title='Faculty Salary by Rank and Sex', x='rank',y='salary')
可以很明显的看到,平均收入随着学术排名的上升而上升,在每个学术等级中男性的薪资水平高于女性。
6.2 图例
图例是指如何用颜色、形状尺寸等视觉特性表示数据特征的指南。ggplot2包能自动生成图例,而且很多时候能满足我们的需求;但在某些时候,我们可能需要对其进行自定义。标题和位置是最常用的定制特征。
当更改图例的标题时,必须考虑图例是否基于颜色、尺寸、形状或他们的组合。在6.1节中,图例代表fill,因此我们可以通过将fill='mytitle'
加到labs()
函数中来改变标题。标题的位置由theme()函数中的legend.position选项控制。可能的值包括'left'、'right'(默认)、'top'和'bottom'。我们也可以在图中给定位置指定一个二元向量。下面我们对6.1节中的图进行更改,增加一个分类因子color=discipline
,并改变图例的标题和位置。
> ggplot(data=Salaries, aes(x=rank, y=salary, fill=sex, color=discipline)) +
+ geom_boxplot() +
+ scale_x_discrete(breaks=c('AsstProf', 'AssocProf', 'Prof'),
labels=c('Assistant\nProfessor', 'Associate\nProfessor', 'Full\nProfessor')) +
+ scale_y_continuous(breaks=c(50000, 100000, 150000, 200000),
labels=c('$50K','$100K','$150K','$200K')) +
+ labs(title='Faculty Salary by Rank and Sex', x='rank',y='salary',color='Discip', fill='Gender') +
### labs()中的color='Discip'和fill='Gender'分别表示color和fill两个分类的图例的名称
+ theme(legend.position=c(0.1,0.8)) # 设置图例位置
本例中
c(0.1,0.8)
分别表示距离左侧边缘10%和底部边缘80%的部分。如果想删除图例则可以使用
legend.position='none'
。
6.3 标尺
ggplot2包使用标尺把数据映射到可视化的空间中。标尺既可以应用到连续的变量,也可以应用到离散的变量。下面我们使用mtcars数据集,将disp变量映射到图形中点的大小,代码:
> ggplot(mtcars, aes(x=wt, y=mpg, size=gear)) + # gear映射到散点的大小
+ geom_point(shape=21, color='black', fill='cornsilk') +
+ labs(x='Weight', y='Miles Per Gallon', title='Bubble Chart', size='Gear')
下面代码我们继续使用mtcars数据集,将cyl映射到图形颜色上(将颜色作为不同等级的标尺),并通过
scale_color_manual()
函数来手动设定三个cyl的点的颜色。
> mtcars$cyl <- factor(mtcars$cyl, levels=c(4,6,8), labels=c('cyl-4', 'cyl-6','cyl-8'))
> ggplot(mtcars, aes(x=wt, y=mpg, color=cyl)) +
+ geom_point(shape=21) +
+ labs(x='Weight', y='Miles Per Gallon') +
+ scale_color_manual(values=c('red','blue','green'))
此外,如果不想自己设置每一种颜色,可通过
scale_color_brewer()
和
scale_fill_brewer()
函数来指定颜色集。
6.4 主题
theme()
函数中的选项可以让我们调整字体、北京、颜色和网格线等。主题可以使用一次,也可以保存起来应用到多个图中。
library(ggplot2)
data(Salaries, package='car')
mytheme<-theme(plot.title=element_text(face='bold.italic',size=14,color='brown',hjust=0.5), # 指定图标题的字体以及位置
axis.title=element_text(face='bold.italic',size=10,color='brown'), # 设置轴标题的字体大小等
axis.text=element_text(face='bold.italic',size=9,color='darkblue'), # 轴标签字体设置
panel.background=element_rect(fill='white',color='darkblue'), # 背景设置
panel.grid.major.y=elemnt_line(color='grey',linetype=1), # 设置网格线
panel.grid.minor.y=element_line(color='grey', linetype=2), # 设置网格线
panel.grid.minor.x=element_blank()) # 垂直网格不输出
ggplot(Salaries, aes(x=rank,y=salary,fill=sex)) +
geom_boxplot() +
labs(title='Salary by Rank and Sex',x='RANK',y='Salary') +
mytheme
7、组合图
在基础绘图中,我们使用par()
函数的mfrow和mfcol参数和layout()
来将多个图形组合起来。将多个ggplot图形组在一起最简单的方式是使用gridExtra包中的grid.arrange()
函数,使用前需先安装这个包。
下面我们将三个ggplot图形合并到一个图中,代码:
> p1<-ggplot(data=Salaries, aes=(x=rank)) + geom_bar()
> p1<-ggplot(data=Salaries, aes(x=rank)) + geom_bar()
> p2<-ggplot(data=Salaries, aes(x=sex)) + geom_bar()
> p3<-ggplot(data=Salaries, aes(x=yrs.since.phd, y=salary)) + geom_point()
> library(gridExtra)
> grid.arrange(p1, p2, p3)
> grid.arrange(p1, p2, p3, ncol=3)
8、保存图形
保存图形能使用基础绘图的方法,但ggsave()
函数能更为方便地保存它。它的选项包括保存那幅图形,保存位置以及保存形式。
myplot<-ggplot(data=mtcars, aes(x=mpg)) + geom_histogram()
ggsave(file='filename.tiff', plot=myplot, width=5, height=4)
我们可以通过将文件名的扩展格式设置为不同的格式来以不同的方式保存。如果忽略plot=
选项,最近创建的图形会被保存。