如何使用 ggplot2
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用 ggplot2相关的知识,希望对你有一定的参考价值。
R语言 高阶可视化绘图系统:ggplot2入门
ggplot2是《The Grammar of Graphics》/《图形的语法》中提出了一套图形语法,将图形元素抽象成可以自由组合的要素,类似Photoshop中的图层累加,ggplot2将指定的元素/映射关系逐层叠加,最终形成所图形。更加深入学习ggplot2,请参考《ggplot2: 数据分析与图形艺术》。
目 录
引言:ggplot2基本要素
1. 数据(Data)和映射(Mapping)
2、几何对象(Geometric)
3、标度(Scale):fill、color、shape
4、统计变换(Stat)
5、坐标系统(Coordinante)
6、分面(Facet)
7、主题(Theme)
附:ggplot2函数速查表
引言:ggplot2基本要素
“+”和“%+%”
数据(data)和映射(mapping):ggplot2的数据(data)必须是一个数据框(dataframe)。
几何对象(geometric):几何对象(geom)代表你在图中实际看到的元素,如点、线、多边形等。
统计变换(statistics):统计变换(stat)是对数据进行的某种汇总。
标度(Scale):标度(scale)的作用是将数据的取值映射到图形空间,例如用颜色、大小或形状来表示不同的取值。
坐标系统(Coordinate):坐标系(coord)描述了数据是如何映射到图形所在的平面的,它同时提供了看图所需的坐标轴和网格线。
图层(Layer):一个图层由4部分组成:数据和图形属性映射;一种统计变换;一种几何对象;一种位置调整方式。
分面(Facet):分面(facet)描述了如何将数据分解为各个子集,以及如何对子集作图并联合进行展示。
其中各要素通过“+”以图层(layer)的方式来粘合构图(可以简单理解为要素/图层叠加符号);另外在ggplot2中,数据集必须为数据框(data.frame)格式,并且可以通过%+%符号调整已有数据集(ggplot2指导文档中明确写出“To override the data, you must use %+%”,也就是覆盖数据必须通过%+%)。以mpg数据集为例。
p1 <- base + geom_smooth() + labs(title="图1") #如图1
#用%+%调整映射关系中的数据
base <- ggplot(mpg, aes(displ, hwy)) + geom_point()
# To override the data, you must use %+%
#也即覆盖原始数据必须通过%+%
p2 <- base %+% subset(mpg, fl == "p") + labs(title="图2") #图2
#第二种调整数据的方法list
# Alternatively, you can add multiple components with a list.
# This can be useful to return from a function.
p3 <- base + list(subset(mpg, fl == "p"), geom_smooth(), labs(title="图3")) #图3
###########一页多图########
#library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(2,2))) #将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p1, vp = vplayout(1,1)) #(1,1)的位置画图1
print(p2, vp = vplayout(1,2)) #(1,2)的位置画图2
print(p3, vp = vplayout(2,1)) #(2,1)的位置画图3
1. 数据(Data)和映射(Mapping)
前文已经提及在ggplot2中,数据集必须为数据框(data.frame)格式,并且可以通过%+%符号调整已有数据集。
映射是将一个变量中离散或连续的数据与一个图形属性中以不同的参数来相互关联, 而设定能够将这个变量中所有的数据统一为一个图形属性。aes()函数是ggplot2中的映射函数, 所谓的映射即为数据集中的数据关联到相应的图形属性过程中一种对应关系(注意第10行)。可以发现, 在p2中, 通过aes()指定了横纵坐标分别为wt和hp
> p1 <- ggplot(data = mtcars
> summary(p1)
data: mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb [32x11]
faceting: <ggproto object: Class FacetNull, Facet, gg>
…… #此部分省略一些内容
> p2 <- ggplot(data = mtcars, mapping = aes(x = wt, y = hp))
> summary(p2)
data: mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb [32x11]
mapping: x = ~wt, y = ~hp faceting: <ggproto object: Class FacetNull, Facet, gg>
…… #此部分省略一些内容
另外,在ggplot2中,ggplot()函数声明了全局数据和映射关系,在后续几何对象中如未重新设定数据和映射关系,几何对象将沿用ggplot()中声明的数据与映射关系;当然几何对象可重新设定数据与映射关系,并作用于此几何对象(对比图4和图7),但并不对初始图图层产生影响(对比图4和图6,图6虽对几何图形中重新定义y变量为carb,但纵坐标依然是wt)。
#library(ggolot2)
p <- ggplot(mtcars, aes(x = mpg, y = wt))#设定默认的映射关系
p4 <- p + geom_point() + labs(title="图4")#图4沿用默认的映射关系来绘制散点图
p5 <- p + geom_point(aes(shape = factor(carb))) + labs(title="图5") #图5添加图层中的shape的映射关系
p6 <- p + geom_point(aes(y = carb)) + labs(title="图6")#图6修改默认的y的映射关系, 注意图中y轴名称仍然以默认的wt表示
df <- mtcars[which(mtcars$am==1),]
p7 <- p + geom_point(data = df,aes(x = mpg, y = wt)) + labs(title="图7")
#重新定义point几何对象中的数据与映射关系
###########一页多图########
#library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(2,2))) #将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p4, vp = vplayout(1,1)) #(1,1)的位置画图4
print(p5, vp = vplayout(1,2)) #(1,2)的位置画图5
print(p6, vp = vplayout(2,1)) #(2,1)的位置画图6
print(p7, vp = vplayout(2,2)) #(2,2)的位置画图7
2、几何对象(Geometric)
上述例子中,数据映射关系有ggplot()函数设定,使用geom_point()添加一个几何图层,告诉ggplot绘画点图,并将图层属性映射到散点上。
geom_point之外,ggplot2提供了多种几何对象映射,如geom_histogram直方图,geom_bar画柱状图,geom_boxplot画箱式图等等。不同的几何对象,要求的属性会有些不同,这些属性也可以在几何对象映射时提供。
> library(ggplot2)
> ls("package:ggplot2", pattern="^geom_.+")
[1] "geom_abline" "geom_area" "geom_bar" "geom_bin2d" "geom_blank"
[6] "geom_boxplot" "geom_col" "geom_contour" "geom_count" "geom_crossbar"
[11] "geom_curve" "geom_density" "geom_density_2d" "geom_density2d" "geom_dotplot"
[16] "geom_errorbar" "geom_errorbarh" "geom_freqpoly" "geom_hex" "geom_histogram"
[21] "geom_hline" "geom_jitter" "geom_label" "geom_line" "geom_linerange"
[26] "geom_map" "geom_path" "geom_point" "geom_pointrange" "geom_polygon"
[31] "geom_qq" "geom_qq_line" "geom_quantile" "geom_raster" "geom_rect"
[36] "geom_ribbon" "geom_rug" "geom_segment" "geom_sf" "geom_sf_label"
[41] "geom_sf_text" "geom_smooth" "geom_spoke" "geom_step" "geom_text"
[46] "geom_tile" "geom_violin" "geom_vline"
#library(ggplot2)
p <- ggplot(mtcars, aes(x = mpg, y = wt))
p8 <- p + geom_point() + labs(title="图8") #图8散点图
p <- ggplot(mtcars, aes(x = factor(carb), y = wt))
p9 <- p + geom_bar(stat= 'identity') + labs(title="图9") #图9条形图
###########一页多图########
#library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(1,2))) #将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p8, vp = vplayout(1,1)) #(1,1)的位置画图8
print(p9, vp = vplayout(1,2)) #(1,2)的位置画图9
3、标度(Scale):fill、color、shape
在对图形属性进行映射之后,使用标度可以控制这些属性的显示方式,比如颜色属性、形状属性等。对比图10和图11,aes中color参数属性可以发现,如color对应变量为factor因子时,图10中图例分组显示不同颜色;但如factor对应的变量为数值,ggplot将其识别为连续变量,数值大小决定颜色深度;对比12和图13,不论是在ggplot函数中定义color还是在几何对象中定义color,其具有相同的效果。
#library(ggplot2)
p <- ggplot(mtcars, aes(x = mpg, y = wt))
p10 <- p + geom_point(aes(color=factor(gear))) + labs(title="图10") #图10
p11 <- p + geom_point(aes(color=gear)) + labs(title="图11") #图11
p <- ggplot(mtcars, aes(x = mpg, y = wt,color = factor(gear)))
p12 <- p + geom_point(aes(shape=factor(cyl))) + labs(title="图12") #图12
p <- ggplot(mtcars, aes(x = mpg, y = wt))
p13 <- p + geom_point(aes(color=factor(gear),shape=factor(cyl))) + labs(title="图13") #图13
###########一页多图#########
library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(2,2))) #将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p10, vp = vplayout(1,1)) #(1,1)的位置画图10
print(p11, vp = vplayout(1,2)) #(1,2)的位置画图11
print(p12, vp = vplayout(2,1)) #(2,1)的位置画图12
print(p13, vp = vplayout(2,2)) #(2,2)的位置画图13
4、统计变换(Stat)
统计变换对原始数据进行某种计算,然后在图上显示出来,例如在散点图上加一条回归线。
ggplot(mtcars, aes(x = mpg, y = wt))+geom_point()+scale_y_log10()+stat_smooth(method = "auto", formula = y ~ x)
aes所提供的参数,就通过ggplot提供,而不是提供给geom_point,因为ggplot里的参数,相当于全局变量,geom_point()和stat_smooth()都知道x,y的映射,如果只提供给geom_point(),则相当于是局部变量。ggplot2提供了多种统计变换方式:
> library(ggplot2)
> ls("package:ggplot2",pattern="stat_.+")
[1] "stat_bin" "stat_bin_2d" "stat_bin_hex" "stat_bin2d" "stat_binhex"
[6] "stat_boxplot" "stat_contour" "stat_count" "stat_density" "stat_density_2d"
[11] "stat_density2d" "stat_ecdf" "stat_ellipse" "stat_function" "stat_identity"
[16] "stat_qq" "stat_qq_line" "stat_quantile" "stat_sf" "stat_sf_coordinates"
[21] "stat_smooth" "stat_spoke" "stat_sum" "stat_summary" "stat_summary_2d"
[26] "stat_summary_bin" "stat_summary_hex" "stat_summary2d" "stat_unique" "stat_ydensity"
[31] "update_stat_defaults"
5、坐标系统(Coordinante)
坐标系统控制坐标轴进行变换,例如XY轴翻转,笛卡尔坐标和极坐标转换。
#设置基本映射关系
p <- ggplot(mtcars)
p14 <- p + geom_bar(aes(x = factor(carb)))+coord_flip() + labs(title="图14") #图14原图
#坐标轴翻转由coord_flip()实现
p15 <- p + geom_bar(aes(x = factor(carb)))+coord_flip() + labs(title="图15") #图15
#转换成极坐标可以由coord_polar()实现:风玫瑰图(windrose)
p16 <- p + geom_bar(aes(x = factor(1),fill=factor(gear))) + coord_polar() + labs(title="图16") #图16
#转换成极坐标可以由coord_polar()实现:风玫瑰图(windrose)
p17 <- p + geom_bar(aes(x = factor(carb),fill=factor(gear))) + coord_polar() + labs(title="图17") #图17
###########一页多图########
#library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(2,2))) #将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p14, vp = vplayout(1,1)) #(1,1)的位置画图14
print(p15, vp = vplayout(1,2)) #(1,2)的位置画图15
print(p16, vp = vplayout(2,1)) #(2,1)的位置画图16
print(p17, vp = vplayout(2,2)) #(2,2)的位置画图17
6、分面(Facet)
分面可以让我们按照某种给定的条件,对数据进行分组,然后分别画图。
#facet_grid
mt <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) + geom_point()
mt + facet_grid(. ~ cyl, scales = "free")
#facet_wrap
ggplot(mpg, aes(displ, hwy)) + geom_point() + facet_wrap(~class, scales = "free")
7、主题(Theme)
p1 <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + labs(title = "Fuel economy declines as weight increases") + labs(title="图20") #图20
p17 <- p1 + theme(plot.title = element_text(size = rel(2))) + labs(title="图17") #图17
p18 <- p1 + theme(plot.background = element_rect(fill = "green")) + labs(title="图18") #图18
p19 <- p1 + theme(panel.background = element_rect(fill = "white", colour = "grey50")) + labs(title="图19") #图19
###########一页多图########
#library(grid)
grid.newpage() ##新建页面
pushViewport(viewport(layout = grid.layout(2,2)))#将页面分成2*2矩阵
vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y)
print(p1, vp = vplayout(1,1)) #(1,1)的位置画图20
print(p17, vp = vplayout(1,2)) #(1,2)的位置画图17
print(p18, vp = vplayout(2,1)) #(2,1)的位置画图18
print(p19, vp = vplayout(2,2)) #(2,2)的位置画图19
ggplot2的核心理念是将绘图与数据分离,数据相关的绘图与数据无关的绘图分离
ggplot2是按图层作图
ggplot2保有命令式作图的调整函数,使其更具灵活性
ggplot2将常见的统计变换融入到了绘图中。
==================================================================
1、ggplot2的逻辑。
ggplot2的逻辑在我看来其实是真正实现了一个图层叠加的概念:一句语句代表一张图,然后再有最小的单元图层。这个与其他命令式的绘图完全不同,来做个比较:
#这是基于graphic包里例子
x <- rnorm(100,14,5)
y <- x + rnorm(100,0,1)
plot(x,y)
text(13,20, expression(x[1] == x[2]))
输出的图是这样的:
我们可以看到这种绘图方式实际上是按命令添加的,以plot开始,可以以任何方式结束,每加上一个元素,实际上都是以一句单独的命令来实现的。这样做的缺点就是,其实不符合人对于画图的一般认识。其次,就是,我们没有一个停止绘图的标志,这使得有时候再处理的时候就会产生一些困惑。优势其实也有,在做参数修改的时候,我们往往可以很方便地直接用一句单独的命令修改,譬如对于x轴的调整,觉得不满意就可以写命令直接调整。而ggplot2则意味着要重新作图。
再来看ggplot2的代码:
x <- rnorm(100,14,5)
y <- x + rnorm(100,0,1)
ggplot(data= NULL, aes(x = x, y = y)) + #开始绘图
geom_point(color = "darkred") + #添加点
annotate("text",x =13 , y = 20,parse = T,
label = "x[1] == x[2]") #添加注释
画出的结果如下:
我们可以发现,ggplot的绘图有以下几个特点:第一,有明确的起始(以ggplot函数开始)与终止(一句语句一幅图);其二,图层之间的叠加是靠“+”号实现的,越后面其图层越高。
其次就是对于分组数据的处理,其实这方面,lattice已经做得很好了,不过我会在后面更仔细地叙述ggplot2是怎么看分组数据的绘图的。
2. ggplot2的要素
我们这里不谈qplot(quickly plotting)方法,单纯谈ggplot方法。不谈底层的实现思想,我们简单地理解,ggplot图的元素可以主要可以概括如下:最大的是plot(指整张图,包括background和title),其次是axis(包括stick,text,title和stick)、legend(包括backgroud、text、title)、facet这是第二层次,其中facet可以分为外部strip部分(包括backgroud和text)和内部panel部分(包括backgroud、boder和网格线grid,其中粗的叫grid.major,细的叫grid.minor)。大致见下图,这部分内容的熟悉程度直接影响到对于theme的掌握,因此希望大家留心。
3. ggplot2图层以及其他函数的分类
好了,现在把这些理念的东西讲完了之后,下面来理解ggplot2里的绘图命令。
ggplot2里的所有函数可以分为以下几类:
用于运算(我们在此不讲,如fortify_,mean_等)
初始化、展示绘图等命令(ggplot,plot,print等)
按变量组图(facet_等)
真正的绘图命令(stat_,geom_,annotate),这三类就是实现一个函数一个图层的核心函数。
微调图型:严格意义上说,这一类函数不是再实现图层,而是在做局部调整。
scale_:直译为标尺,这就是与aes内的各种美学(shape、color、fill、alpha)调整有关的函数。
guides:调整所有的text。
coord_:调整坐标。
theme:调整不与数据有关的图的元素的函数。
4. 绘图
第一步:初始化。ggplot2风格的绘图的第一步就是初始化,说白了就是载入数据空间、选择数据以及选择默认aes。
p <- ggplot(data = , aes(x = , y = ))
data就是载入你要画的数据所在的数据框,指定为你的绘图环境,载入之后,就可以免去写大量的$来提取data.frame之中的向量。当然,如果你的数据都是向量,也可不指定,但是要在申明中标注data = NULL,不然就会得到不必要的报错。
第二个是重头戏,即aes,是美学(aesthetic)的缩写。这是在ggplot2初学者眼里最不能理解的东西,甚至很多老手也会在犹豫,什么时候要把参数写在aes里,什么时候要写在aes外。我们做一个简单的,不非常恰当的解释:任何与数据向量顺序相关,需要逐个指定的参数都必须写在aes里。这之后我们会进一步解释,现在我们初始化的时候,最好只是把关于位置的x和y指定一下就好。
第二部,绘制图层。
很多人在解释ggplot2的时候喜欢说,ggplot2绘图有两种函数,一类是geom_,绘图用的;一类是stat_,统计变换用的。这样说不是不对,只是很不恰当,很多人就会问出一些问题,比如,统计变换竟然是做运算用的,为什么可以用来画图?为什么stat_bin和geom_histgram画出来的图是一样,竟然一样,为什么要重复?
事实上,任何一个ggplot2图层都包括stat和geom俩部分,或者说两个步骤(其实还包括position)。 而stat_identity则表示不做任何的统计变换。
我们来举个例子,还是上面的代码,为了更直观,我在此作了修改:
x <- c(rnorm(100,14,5),rep(20,20))
y <- c(rnorm(100,14,5) + rnorm(100,0,1),rep(20,20))
ggplot(data= NULL, aes(x = x, y = y)) + #开始绘图
geom_point(color = "darkred")
做出的图如下:
我们查看码源,就知道geom_point的默认stat是identity,即不做任何统计变换:
> geom_point
function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
na.rm = FALSE, ...)
GeomPoint$new(mapping = mapping, data = data, stat = stat,
position = position, na.rm = na.rm, ...)
<environment: namespace:ggplot2>
大家可以发现,我在(20,20)这个点的数据事实上是有20个的,但由于没做统计转换(20,20)这个点被画了20次,因此我们理论上看到的点其实是最后一次画的那个点。可能这不够直观,没关系,我们调整一下透明度到10%:
ggplot(data= NULL, aes(x = x, y = y)) + #开始绘图
geom_point(color = "darkred",alpha = 0.1)
得到如下图:
这样应该就很明显了,由于(20,20)点被画了20次,所以透明度会叠加为20*10% = 200%实际只展现100%。
我们现在就使用坐标转换来重新画这个图:
ggplot(data= NULL, aes(x = x, y = y)) + #开始绘图
geom_point(color = "darkred",stat = "sum")
好了,解释一下,stat_sum实际的意思就是按照某一点占所有点出现频率然后换算成大小来作图,因此,以上代码就可以得到下面这张图,因为(20,20)这个点出现频率为20/120=16.667%:
好了,我们可以发现了,一个单纯的geom_point里面也是带有stat_的,因此,其实geom_和stat_实际上是一回事。可能你会问了,那照我的说法,以上这幅图用的是geom_point里的一个参数,而不是再用stat_sum,这是一回事吗?bingo!这个问题相当好,的确,按照以上的推理,应该存在一种以stat_sum作为主函数的方法来绘制这幅图,搞不好,里面还有个参数geom,要设置成“point”。我们来实践一下吧:
ggplot(data= NULL, aes(x = x, y = y)) + #开始绘图
stat_sum(color = "darkred",geom = "point")
尼玛,还真可以,还长得一模一样。
现在就讲通了,对于有过经验的同学现在应该重新修正这个观点——stat_和geom_是两种绘图方法。这是错的,其实它们是ggplot2每一个图层绘制都必须有的,是一个图层的一体两面。
在这一步之中,我们也要回到我们在第一步时出现的问题,aes到底是什么?为什么说任何与数据向量顺序相关,需要逐个指定的参数都必须写在aes里?什么时候color、shape、size、fill写外面,什么时候写里面?
aes实际上做的是将aes里的向量的顺序逐个地绘制。譬如以下代码(转自geom_point帮助文档中的实例):
p <- ggplot(mtcars, aes(wt, mpg)) #<---- code 1
p + geom_point(aes(colour = qsec)) #<---- code 2
结果是:
我们来分析一下ggplot2是怎么作图的。首先,我们来看一下mtcars这个数据集长什么样:
> head(mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
code 1: ggplot首先载入了这个mtcars的集合,然后指定给了mpg作为其x坐标位置,wt为y坐标位置。
code 2: 指定了qsec作为其染色的标准(分组),qsec为numeric变量,因此,应该选择连续型的标尺,而不是分组染色。然后开始绘制,读取mtcars$mpg[1]、mtcars$wt[1],确定位置,然后为其染成mtcars$qsec[1]颜色;再绘制第二点。。。
因此,aes里的美学特征其实就是按照向量顺序指定每个位置的美学特征,大家可以比较tapply函数的写法。
好了,现在问题就来了。我想为所有点的颜色都染成绿色,怎么办?其实很简单,如果不需要指定这么一个染色的顺序,而选择将整个图层染成一种颜色,则只需要将color写在aes外:
p + geom_point(color = "green")
哦,怪不得写在aes里染出来的颜色不是绿色,但为什么写到里面就不可以了,为了写到里面,然出来的是粉色?
好了,我们再来分析一下把color = "green"写到了aes里,到底发生了什么。
p + geom_point(aes(colour = "green"))
首先,数据的初始化跟上面那个例子是相同的。然后,因为color放到了aes里,于是ggplot开始搜索mtcars里面的向量了,发现没有叫"green"的,然后又找了global,也没有。于是,ggplot就开始把它认作了一个新的向量。等等,有个问题,我要按照这个向量来分别染色,而事实上,这个向量长度为1,怎么办?ggplot就先把他展开成了factor(rep("green",nrow(mtcars)),levels = unique("green")),bingo!现在开始染色了。啊第一个数据mtcars$mpg[1]、mtcars$wt[1],其颜色变量是"green",因子水平是1,染成默认调色第一种,哦,就是这个蛋蛋的粉红色;再染第二个,还是"green",因子水平也是1,染成蛋蛋的粉红色;... 终于完成了,咦?怎么都是蛋蛋的粉红色。
通过举了这个染色的例子大家应该都弄懂了,aes到底在干什么了。其他的美学特征其实也是完全一致的。只是需要解释group=1的意思就是说不做分组来进行绘图。什么?还是搞不清该放aes里面还是外面?那就记着想统一整个图层时就放到aes外,想分成不同组调整,并且已经有一个与x、y长度一致的分组变量了,那就放到aes里。
在这一步里,还要要说的就是我们要讲的是ggplot2大致内置了哪些图:
点(point, text):往往只有x、y指定位置,有shape但没有fill
线(line,vline,abline,hline,stat_function等):一般是基于函数来处理位置
射(segment):特征是指定位置有xend和yend,表示射线方向
面(tile, rect):这类一般有xmax,xmin,ymax,ymin指定位置
棒(boxplot,bin,bar,histogram):往往是二维或一维变量,具有width属性
带(ribbon,smooth):透明是特征是透明的fill
补:包括rug图,误差棒(errorbar,errorbarh)
然后,就是按照你的需要一步步加图层了(使用“+”)。
第三部,加注释。所有注释的实现都是通过annotate函数实现的,其实annotate就是一个最简单的geom_单元,它一次只添加一个位置上的图形(可以通过设置向量来实现同时绘制多个图形,但这个理念和注释的理念有所偏差)。annotate的geom就是指定注释的类型,其属性按照geom的不同而发生变化。
第四步,调整。这里的调整主要是使用微调图形这大类的函数做美学特征、坐标轴、标题、绘图主题的调整。这部分也就是继承了命令式作图的思想,使ggplot2的灵活性增加。
如何搜索你要用什么美学特征调整函数,其实就是按照美学特征的名字来,例如,你要调整的是fill,就找scale_fill_之后就有一些不同的染色方法(关于色彩,如果有时间还会添加相关知识);调整的是横坐标标尺,就找scale_x_然后后面跟上你的横坐标类型;其他雷同。
在调整主题这方面,值得褒奖的是,theme函数其实最妙的地方是将对于数据相关的美学调整和与数据无关的美学调整分离了。譬如说,我们要改变x轴的颜色,或者panel的底色,这个其实与数据处理无关,这种分离就会使得我们可以如此流程化地操作作图,而不需要在考虑数据的时候还要关注到与数据无关的美学参数。有人有时候会觉得ggplot2很奇怪的地方就是为什么调整legend的时候,有时要用scale_,有时又要用theme,其实这都是对于ggplot2这个设计理念的不理解,作者的设计思路是要将数据处理与数据美学分开,数据美学与数据无关的调整分开。
其次,theme函数采用了四个简单地函数来调整所有的主题特征:element_text调整字体,element_line调整主题内的所有线,element_rect调整所有的块,element_blank清空。这种设计相当地棒。
由此,一个极具诚意的作图应该长成下面这个样子:
ggplot(data = , aes(x = , y = )) +
geom_XXX(...) + ... + stat_XXX(...) + ... +
annotate(...) + ... +
scale_XXX(...) + coord_XXX(...) + guides(...) + theme(...)
5. ggplot2的一些缺点
公式支持不好,自带的plotmath公式无法满足很多需求
无法针对多个legends进行调整
效率不高,绘图速度较慢,这也表示二次开发的可能性不高
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
以上是使用的心得,希望对大家有用。主要是在理念上解释一些容易产生困惑的问题。本回答被提问者和网友采纳
如何使用 ggplot 添加彩色图例?
【中文标题】如何使用 ggplot 添加彩色图例?【英文标题】:How can I add with ggplot the colored legend? 【发布时间】:2019-04-04 10:28:33 【问题描述】:我有这个数据框,我想用 ggplot 在 x 轴上绘制 result_df50$id 列,在 y 轴上绘制 result_df50$Sens 和 列result_df50$Spec.
我还希望 result_df50$Sens 和 result_df50$Spec 以不同的颜色显示。图例还应显示列的不同颜色。
> result_df50
Acc Sens Spec id
1 12 51 15 1
2 24 78 28 2
3 31 86 32 3
4 78 23 90 4
5 49 43 56 5
6 25 82 33 6
7 6 87 8 7
8 60 33 61 8
9 54 4 66 9
10 5 54 9 10
11 1 53 4 11
12 2 59 7 12
13 4 73 3 13
14 48 41 55 14
15 30 72 39 15
16 57 10 67 16
17 80 31 91 17
18 30 65 36 18
19 58 45 61 19
20 12 50 19 20
21 39 47 46 21
22 38 49 45 22
23 3 69 5 23
24 68 24 76 24
25 35 64 42 25
到目前为止,我已经尝试过了,对此我很满意。
ggplot(data = result_df50) +
geom_line(data= result_df50, aes(x = result_df50$id, y = result_df50$Spec), colour = "blue") +
geom_line(data= result_df50, aes(x = result_df50$id, y = result_df50$Sens), colour = "red") +
labs(x="Number of iterations")
现在我只想添加带有每行颜色的图例。我试过fill
,但R给出警告并忽略了unknown aesthetics: fill
....
我该怎么做?
【问题讨论】:
【参考方案1】:这是因为您的数据集格式错误(宽)。您必须将其转换为长格式才能使其工作如下:
result_df50 <- read.table(text="Acc Sens Spec id
1 12 51 15 1
2 24 78 28 2
3 31 86 32 3
4 78 23 90 4
5 49 43 56 5
6 25 82 33 6
7 6 87 8 7
8 60 33 61 8
9 54 4 66 9
10 5 54 9 10
11 1 53 4 11
12 2 59 7 12
13 4 73 3 13
14 48 41 55 14
15 30 72 39 15
16 57 10 67 16
17 80 31 91 17
18 30 65 36 18
19 58 45 61 19
20 12 50 19 20
21 39 47 46 21
22 38 49 45 22
23 3 69 5 23
24 68 24 76 24
25 35 64 42 25")
# conversion to long format
library(reshape2)
result_df50 <- melt(result_df50, id.vars=c("Acc", "id"))
head(result_df50)
# Acc id variable value
# 1 12 1 Sens 51
# 2 24 2 Sens 78
# 3 31 3 Sens 86
# 4 78 4 Sens 23
# 5 49 5 Sens 43
# 6 25 6 Sens 82
# your plot
ggplot(data = result_df50, aes(x = id, y =value , color=variable)) +
geom_line() +
labs(x="Number of iterations")+
scale_color_manual(values=c("red", "blue")) # in case you want to keep your colors
这是你想要的吗?
【讨论】:
感谢您的评论!我如何(使用您的答案)在 y 轴上绘制两条线,分别是Sens
和 Spec
?
正是我的示例向您展示的方式。首先,您必须更改数据格式,以便 Spec 和 Sens 成为新列中的两个因子级别/字符。在 ggplot 美学的颜色参数中指定该列后,两条线都会以您想要的方式出现。复制并粘贴我的整个示例(您向下滚动了吗?)并尝试一下。它应该可以工作。
好吧,我没有看到其余的...刚刚试了一下,它的工作原理。谢谢! :)
您的示例数据很长,这使得示例比它必须的要长。您只需要很短的转换和情节部分。
我的真实数据更长...再次感谢!以上是关于如何使用 ggplot2的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ggplot2 + directlabels 为标签使用自定义名称
如何使用 ggplot2 在 R 中制作具有透明背景的图形?