实用教程!R语言 ggplot2 绘图入门

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

 <fct>       <fct>     <int>   <dbl>    <int>     <dbl>

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)。

利用绘图语法既可以做出常见的统计图形, 也可以做出各种新颖的图形, 当然, 就像语法正确的语句不一定有意义, 用绘图语法做得新颖图形不一定有实际意义, 还是要按照可视化的一般原则做出能说服读者的图形

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,230评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,261评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,089评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,542评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,542评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,544评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,922评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,578评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,816评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,576评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,658评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,359评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,920评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,859评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,381评论 2 342

推荐阅读更多精彩内容