R语言最擅长绘图。R语言最擅长的绘图包是ggplot2,由于很多朋友没有接触过ggplot2,必须要对其语言方式有个初步的认识。所以入门学习是必须的。公众号先前若干篇文章已经介绍ggplot2绘图的基本方法(具体可以关注文末链接),为推动学习,今天介绍再次系统的一番。
ggplot2包是R的一个作图用的最精彩的扩展包,它实现了“图形的语法”,将一个作图任务分解为若干个子任务,只要完成各个子任务就可以完成作图。在作常用的图形时,只需要两个步骤:首先将图形所展现的数据输入到ggplot()函数中,然后调用某个geom_xxx()函数,指定图形类型,如散点图、曲线图、盒形图等。
如果需要进一步控制图形细节,只要继续调用其它函数,就可以控制变量值的表现方式(scale)、图例、配色等。这使得我们很容易做出基本的图形,在有需要时再深入学习,做出更为满意的图形。
与基本R中的作图系统相比, ggplot2的作图有规律可循,作图结果直接达到出版印刷质量,除了可以按照一些既定模式做出常见种类的图形,也很容易将不同图形种类组合在一起,或者设计新颖的图形。基本R的作图结果通常不够美观,如果要将不同种类图形组合在一起比较困难,对设计新的图形类型支持也不够好。
ggplot2 的绘图理念与基础的绘图有很大的不同,基础的绘图就好像是先铺好画布,然后在画布上画图,是一个平面的,而ggplot2打破了这种画图的方式 ,采用了图层的概念进行画图,先画好基础图,然后再往上一层一层的叠加图层,所以在进行ggplot2画图的时候,代码中会有大量的“+”,这就是对于图层的叠加。本章将大致的给大家介绍医学数据应用ggplot2基本的结构。
ggplot2 图层元素
1.数据(data):将要可视化的数据
2.映射(aes):数据中的变量值
3.几何对象(geom):如bar条形图,point散点图
4. 统计变换(stats):对数据进行计算
5.标度(scale):变量以什么形状、颜色映射到图形上
6. 分面(facet):将数据拆开,进行分层画图
7. 主题(theme):主题设定,与数据无关的图层可以通过这个函数实现。
8. 注释 (annotate): 对图形增加文字类的注释
ggplot()图层
ggplot ()图层包括数据和映射。ggplot函数相当于一幅基本的画布,画者在上面绘制好坐标轴,设置好基本的格局和色彩、线条。
geom_XXX() 图层
geom_XXX() 指的是我们要绘制的图形类型,常见包括以下:
geom_point()绘制散点图
geom_bar()绘制条形图
geom_line()绘制线图
geom_histogram()绘制直方图
geom_boxplot() 绘制箱式图
geom_density() 绘制概率密度函数
scale_ XXX 图层
scale_ XXX 标度是一种函数,size对大小进行调整,shape对形状进行调整,fill、col对颜色进行调整,可根据自己喜好调整
ggplot(data =数据 , aes(x =变量1 , y = 变量2,col=变量3)) +
geom_point(stat = 'count',position=”dodge”)+ #计数、并排
scale_fill_manual(values = c("颜色1","颜色2"))
facet_grid() 图层
facet_grid(...) 对图层进行分面,数据分成多个子集进行绘图
ggplot(data =数据 , aes(x =变量1 , y = 变量2,col=变量3)) +
geom_point(stat = 'count',position=”dodge”)+
scale_colour_manual(values = c("颜色1","颜色2"))+
facet_grid(变量4~变量5) #要求变量属于分类变量,分成多行多列的图
theme() 图层
theme() 是主题修改,是一个对绘图精雕细琢的过程, 主要对标题、坐标轴标签、图例标签等文字调整, 以及网格线、背景、轴的颜色搭配。
theme(plot.title = element_text(size = , color =, hjust = , face = ))
ggplot2的作图一般步骤为:
· 准备数据,一般为数据框,且一般为长表,即每个观测时间占一行,每个观测变量占一列。
· 载入R包,R包括可以通过tidyverse包整体载入。
· 将数据输入到ggplot()函数中,并指定参与作图的每个变量分别映射到哪些图形特性,比如映射为x坐标、y坐标、颜色、形状等。这些映射称为aesthetic mappings或aesthetics。
很多人不明白所谓的映射。其实映射,通俗来讲,就是告诉软件,这幅图所涉及到的变量,并且指出每个变量的用途。比如,x=gender,指的是x轴是性别;y=age,指的是y轴表示年龄大小,shape=location,指的是不同地区图标的形状不一样(比如城市用星号,农村用三角)
· 选择一个合适的图形类型,函数名以geom_开头,如geom_point()表示散点图。图形类型简称为geom。将ggplot()部分与geom_xxx()部分用加号连接。到此已经可以作图,下面的步骤是进一步的细化设定。
· 设定适当的坐标系统,如coord_cartesian(), scale_x_log10()等。仍用加号连接。
· 设定标题和图例位置等,如labs()。仍用加号连接。
这个流程的一个大致的模板为:
p <-ggplot(data=<输入数据框>,
mapping=aes(<维度>=<变量名>,
<维度>=<变量名>, <...>))
p +geom_<图形类型>(<...>) +
scale_<映射>_<类型>(<...>) +
coord_<类型>(<...>) +
labs(<...>)
其中<...>表示额外的选项。变量p包含做出的图形的所有数据与设定,变量名可以任意取。
我接下来讲引用R语言自带数据库,以散点图为例,进行ggplot2绘图。
本文数据集来自gapminder扩展包的gapminder数据集,有若干个国家不同年份的一些数据,包括所属洲、期望寿命、人口数、人均GDP。有1704个观测和6个变量。数据库的变量包括country(国家) 、continent(洲)、year(年)、lifeExp(期望寿命)、pop(人口数)、gdpPercap(人均GDP)
library(gapminder)
head(gapminder, 6)
# A tibble: 6 x 6
country continent year lifeExp pop gdpPercap
1 Afghanistan Asia 1952 28.8 8425333 779.
2 Afghanistan Asia 1957 30.3 9240934 821.
3 Afghanistan Asia 1962 32.0 10267083 853.
4 Afghanistan Asia 1967 34.0 11537966 836.
5 Afghanistan Asia 1972 36.1 13079460 740.
6 Afghanistan Asia 1977 38.4 14880372 786.
这个数据集有多个国家在多个年份的期望寿命与人均GDP值,作期望寿命对人均GDP的散点图,每个国家的每个年份作为一个点。散点图最重要的映射是x轴与y轴两个维度。
1. 最基本的散点图
首先调用绘图基本函数ggplot()函数,指定数据集,将人均GDP映射到x轴,将期望寿命映射到y轴,结果保存为一个R变量:
p <-ggplot(data = gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp))
ggplot()的调用中,可以省略data =, mapping =, x =, y =,写成:
p <-ggplot(gapminder, aes(gdpPercap, lifeExp))
ggplot函数,相当于一幅基本的画布,画者在上面绘制好坐标轴,设置好基本的格局和色彩、线条。
在如上指定了数据和映射后,只要用geom_xxx()指定一个图形类型,并与ggplot()的结果用加号连接就可以作图了,如:
p +geom_point()
x、y轴是最常见的映射,也可以将变量映射为颜色、符号、线型等,这时不需要指定具体的颜色、符号、线型,而是将变量映射为这些图形元素类型。
2. 更多的美图
指定数据集、指定映射、选择适当的图形类型就可以做出基本的图形,随后可以逐步对坐标系、坐标系刻度、标签与图例、配色等进行改善。实际上,ggplot2包已经提供了十分合理的预设值,用户只要进行一些必要的改动即可。
作图步骤之间用加号连接,这是ggplot包特有的语法。例如,用相同的映射基于geom_smooth() 做出拟合曲线图:
p +geom_smooth()
## `geom_smooth()` using method ='gam' and formula 'y ~ s(x, bs = "cs")'
用相同的映射做出散点图并叠加拟合曲线图:
p +geom_point() +geom_smooth()
## `geom_smooth()` using method ='gam' and formula 'y ~ s(x, bs = "cs")'
geom_smooth()的默认设置调用了gam()函数来拟合曲线,可以用geom_smooth()的参数选择不同的拟合方法,如直线拟合:
p +geom_point() +geom_smooth(method="lm")
注意geom_xxx()函数计算所需的变量值是从ggplot()函数保存在变量p中的信息提取的。
在以上的所有图形中, x轴变量(人均GDP)分布非正态,严重右偏,使得大多数散点重叠地分布在直角坐标系的左下角。将x轴用对数刻度可以改善,函数为scale_x_log10():
p +geom_point() +
geom_smooth(method="gam") +
scale_x_log10()
广义可加模型拟合的曲线基本是一条直线。注意,对数刻度实际上是对原始数据进行对数变换,而geom_smooth()的拟合计算是在对数变换之后进行的。
刚刚的图形的横坐标轴刻度不太友好,可以调用scales扩展包的适当函数进行改善,作为scale_x_log10()的labels选项:
p +geom_point() +
geom_smooth(method="gam") +
scale_x_log10(labels=scales::dollar)
scale_xxx()的labels选项指定如何标出坐标刻度数字,参数值是一个函数对象,如果scales包中找不到适当的功能,可以自定义一个函数将数值转换为字符串。 scales包提供了comma, date, dollar, math,number, ordinal, pvalue, scientific, time 等坐标刻度值转换函数。
4. 在geom_point()和geom_smooth()加点简单元素
geom_xxx()函数接受许多关于颜色、透明度、符号、线型的设置参数。比如,下面的程序指定了散点的透明度,以及散点图的颜色的粗细:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp))
p +geom_point(color="chartreuse4",alpha=0.5) +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)
当然,也可以对geom_smooth()玩一把
p +geom_point(color="chartreuse4",alpha=0.5) +
geom_smooth(color="cadetblue1", se =FALSE, size =2, alpha =0.3)
程序中size指定了线的以毫米为单位的粗细, se = FALSE关闭了置信区间显示。用alpha =设置了透明度,取0和1之间的值,数值越小越透明。在有许多个点时适当设置透明度可以比较好地显示出重叠的点,重叠点越多点的颜色越深。虽然这里设置了固定的透明度,也可以在aes()中将透明度alpha映射到某个变量,使得该变量值大小用点的透明度表示。
画线时可以用linetype参数指定线型, 0表示实线, 1到6分别表示不同的虚线线型。
最后,来一个下面用labs()函数给图形加上适当的标题:
p +geom_point(color="chartreuse4",alpha=0.5) +
geom_smooth(color="cadetblue1", se =FALSE, size =2, alpha =0.3)
labs(
x ="人均GDP",
y ="期望寿命(年数)",
title ="经济增长与期望寿命",
subtitle ="数据点为每个国家每年",
caption ="数据来源: gapminder" )
3.颜色、符号、线型等映射
在ggplot()函数的mapping参数的aes()设定中将变量映射到x、y轴,颜色、符号、线型等图形元素类型,也可以作为图形设置将某些图形元素设置为固定值。
例如,用不同颜色表示不同大洲,就是将continent变量映射到color:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp,
color = continent))
程序中仅指定了将大洲映射到颜色维,并不具体指定所用的颜色。
作带有局部多项式曲线拟合的散点图:
p +geom_point() +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)
可以看出,不同散点用了不同颜色表示其continent变量的值,五个大洲分别进行了曲线拟合,曲线使用了不同颜色但置信域颜色相同,使得难以认读。在图形右侧自动生成了颜色与continent变量值的对应关系图例。
下面的图形仍分不同大洲作曲线拟合,并将置信区间阴影的颜色也用不同大洲区分,方法是在aes()中将color和fill都指定为变量continent:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp,
color = continent,
fill = continent))
p +geom_point() +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)
4. 在geom_xxx() 映射变量
在前面的一个例图中,在ggplot()函数中将color和fill映射到了continent变量,使得不仅散点颜色代表了不同大洲,还使得每个大洲单独拟合了曲线。如果希望所有大洲拟合同一条曲线怎么办?
在必要时,可以在geom_xxx()函数中用mapping = aes(<...>)单独指定变量映射。例如,下面的程序在geom_point()中将不同大洲映射为不同颜色,而不影响geom_smooth()中的颜色以及分组:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp))
p +geom_point(mapping =aes(color = continent)) +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)
也可以将一个分类变量映射到不同绘图符号。例如,取gapminder 2007年数据子集,将大洲映射到符号(shape):
p <- ggplot(data = filter(gapminder,year==2007),
mapping = aes(
x = gdpPercap,
y = lifeExp))
p + geom_point(mapping =aes(shape = continent), alpha = 0.4, size = 4) +
scale_x_log10(labels=scales::dollar)
这种映射仅适用于点数比较少的情况,太多密密麻麻不好看(为此我们用了filter函数抽取2007年的数据),还用了size参数指定符号的大小(单位:毫米)。如果所有点使用同一符号并需要指定符号,可以在geom_point()中用shape参数指定,可以用0到25的整数值表示,比如19为实心点,也可以用字符串符号名称表示,如"circle"表示实心点。参见ggplot2帮助目录中的vignette ggplot2:ggplot2-specs。
也可以将连续变量映射为渐变色。除了表示二元函数的等值线图以外这种方法并不利于读者认读。
例如,将人口数取自然对数映射为渐变色:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp,
color =log(pop)))
p +geom_point() +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)
5.小图
前面所有国家的图包含了过多的曲线, 使得图形表现得很拥挤。可以将一个作图区域拆分成若干个小块, 称为小图(facet), 按照某一个或两个分类变量的不同值将数据分为若干个子集, 每个数据子集分别在小图上作图。
对于上面的例子, 可以将每个大洲的图形分别放置在一个小图上。小图不是一种变量映射, 而是一种图形摆放方法, 所以不设置在aes()函数内, 而是用facet_wrap()函数规定。 程序如:
p <-ggplot(data=gapminder,
mapping =aes(
x = gdpPercap,
y = lifeExp,
color= continent))
p +geom_point() +
geom_smooth(method="loess") +
scale_x_log10(labels=scales::dollar)+
facet_wrap(~ continent, ncol = 2)
区分不同小图的标签写在每个小图的上方。可以用facet_wrap()参数strip_position和参数switch调整标签的上下左右。
小图之间默认公用了横坐标和纵坐标且坐标范围保持一致。如果不保持一致, 读者可能会有误解。但是x轴或y轴映射为分类变量且不同小图的分类完全不同时, 可以令各小图中该轴的取值不统一。facet_wrap()选项scales默认为"fixed", 即所有小图的x轴、y轴都范围一致, 取"free_x"则允许各小图的x轴不统一, "free_y"允许各小图的y轴不统一, "free"允许各小图的x轴和y轴都不统一。
在facet_wrap()中可以用ncol参数指定小图的列数, 用nrow指定小图的行数。各个小图的次序应该设定为一定的合理次序, 比如用来分类的变量本身有序, 或者令各小图中的数据值有一定的增减次序。
6.总结
ggplot2的不仅仅是能够做一些固定格式的图形, 而是按照一种图形语法构建图形。小图功能可以将数据集分成若干子集作多幅小图, 每幅小图中, 有可以分层, 每层有不同类型的图, 各层叠加显示在一起。所以,分层语法作图结构如下:
有一个主要的数据集, 以及从数据集变量到坐标位置、颜色、填充、大小、符号等的映射关系(aesthetics);
有一到多个图层, 比如散点图和平滑曲线图层, 每个图层有几何对象、必要的统计变换、位置调整, 还可以有额外的数据集以及额外的映射关系;
对每个映射关系有一个刻度(scaling), 对x、y维,一般需要线性变换,偶尔用到对数变换之类的其它变换, 颜色、填充等维度需要一些复杂的对应关系。无特殊需要时只要使用默认刻度;
有一个坐标系统, 如直角坐标系、极坐标系、球面坐标系等, 一般只要使用默认的坐标系统;
可以划分小图(facetting)。
利用绘图语法既可以做出常见的统计图形, 也可以做出各种新颖的图形, 当然, 就像语法正确的语句不一定有意义, 用绘图语法做得新颖图形不一定有实际意义, 还是要按照可视化的一般原则做出能说服读者的图形