ggplot2作图详解3:映射(mapping)

  • A+
所属分类:Script

作图前的数据准备工作不仅仅指原始数据的收集,还包括数据外观的整理,这些工作对后续的作图无疑十分重要。和其他作图方法相比,ggplot2的优点之一就是把数据整理融合到了作图过程中,替用户分担了数据整型的部分工作。ggplot2数据层面的操作包括映射和分面。先说映射。

1 映射的类型

前面我们已经了解到ggplot对象的data项存储了整个数据框的内容,而“映射”则确定如何使用这些数据。

ggplot2按照图形属性提供了以下可用映射类型:

  • 颜色类型映射:包括 color(颜色或边框颜色)、fill(填充颜色)和 alpha(透明度)
  • 形状类型映射:包括 linetype(线型)、size(点的大小或线的宽度)和 shape(形状)
  • 位置类型映射:包括 x, y, xmin, xmax, ymin, ymax, xend, yend
  • 特殊类型:包括两类,一类是指定数据分组和顺序的映射group和order,另一类是字符串映射。

前两种类型是经典的美学属性映射,第三类的x和y映射也常规,第四类很特别,尤其是字符串映射,很另类,其他类型的映射都可以用aes函数指定,但H.W.为字符串映射专门造了个函数:aes_string。不知道他对字符串特别关照还是实在想不出其他解决方案。

2 颜色和形状类型映射

规律性的东西简单轻松,大家都喜欢;而到处暗藏潜规则、充斥着特例的东西(比如plotrix、perl和中国社会)很杂碎很累人,当然也很让人烦躁和讨厌。ggplot2中颜色和形状这两类映射最符合台面规则的,即:把数据框的变量和图形的美学属性对应起来。

2.1 映射的过程

先看下面ggplot2的数据diamonds:

library(ggplot2)
set.seed(100)
d.sub <- diamonds[sample(nrow(diamonds), 500), ]
head(d.sub, 4)
##       carat       cut color clarity depth table price    x    y    z
## 16601  1.01 Very Good     D     SI1  62.1    59  6630 6.37 6.41 3.97
## 13899  0.90     Ideal     D     SI1  62.4    55  5656 6.15 6.19 3.85
## 29792  0.30     Ideal     D     SI1  61.6    56   709 4.34 4.30 2.66
## 3042   0.30 Very Good     G     VS1  62.0    60   565 4.27 4.31 2.66

作图首先要指定x和y数据,即建立数据框变量和x/y之间的映射:

p  <- ggplot(data=d.sub, aes(x=carat, y=price))

作出散点图:

theme_set(theme_bw())
p  + geom_point()

20140426081359531

如果还要建立其他映射,比如用钻石颜色(color)分类数据确定点的颜色,图形外观就会发生变化(为方便说明,先去掉图例):

p  + geom_point() + aes(color=color) + theme(legend.position=c(2,2))
20140426081422140

 

ggplot2映射的过程可以用plot函数作图步骤进行分解,它包含三方面的操作(不包括图形页面设置):

  • 数据分组
  • 设定颜色标尺
  • 按颜色标尺指定每组数据的颜色
# 设定颜色标尺
levs  <- levels(d.sub$color)
cl  <-  rainbow(length(levs))
# 页面设置
par(mar=c(3,3,0.5,0.5), mgp=c(1.5, 0.5, 0), bg="white")
plot(d.sub$carat, d.sub$price, type='n', xlab="carat", ylab="price")
i  <- 1
for(lev in levs){
  # 数据分组
  datax  <- d.sub[d.sub$color==lev, ]
  # 作图并指定数据点颜色
  points(datax$carat, datax$price, pch=20, col=cl[i])
  i  <- i + 1
}

20140426081503343

上面对数据的分组只设定了一个变量,如果增加数据分组的变量,ggplot2中只需要增加映射的类型就可以了,比如在颜色分类的基础上加钻石切工(cut)进行分类:

p  + geom_point() + aes(color=color, shape=cut) + theme(legend.position=c(2,2))

20140426081526171

用plot函数处理起来要考虑的问题就多一些,可以自己试试。

2.2 映射的标尺

用plot函数作图我们得自己考虑使用什么颜色表示不同组的数据,也就是使用什么标尺(或比例尺)。ggplot2则自动应用标尺,这是一个隐含过程。标尺大体可以分为两类:

  • 离散型(或枚举型)标尺。罗列出所有数据分类并将其与美学属性一一对应,处理过程包含数据分类,如上例。
  • 连续型(或区间型)标尺。看下面例子:
p  + geom_point() + aes(size= x*y*z ) + theme(legend.position=c(2,2))

20140426081557000

上图中点的大小反映钻石的x*y*z值,相当于钻石的大小。用plot函数也可以实现:

cex <- d.sub[,"x"]*d.sub[,"y"]*d.sub[,"z"]
cex  <- cex/max(cex)*4
par(mar=c(3,3,0.5,0.5), mgp=c(1.5, 0.5, 0), bg="white")
plot(d.sub$carat, d.sub$price, type='n', xlab="carat", ylab="price")
points(d.sub[, "carat"], d.sub[, "price"], pch=20, cex=cex)

20140426081608437

可以看到作图过程也需要手动建立数据和图形属性间的对应关系,但没有对数据分类。

ggplot2对映射应用的标尺可以修改,ggplot提供了一大批 scale_xxxxxxxx 类型的函数,比如 scale_color_xxxx 类型函数用户修改颜色标尺,scale_shape_xxxx 修改形状,scale_linetype_xxxx 修改线型等。按照数据的类型,这些函数还有4种基本类型:

  • continuous:连续型
  • discrete:离散型
  • identity:和数据取值相同
  • manual:手工指定

有关颜色和坐标轴标尺设定的函数较多,适应不同需要。

cls  <- terrain.colors(length(levels(d.sub$color)))
p  + geom_point() + aes(color=color) + scale_color_manual(values=cls)

20140426081622828

 

2.3 映射与图例

映射还有一个作用:产生图例。这在ggplot2也是自动的隐含过程,但在plot函数作图中是一个体力活,制作过程就不举例说明了,可以参考legend函数。

2.4 图形颜色和形状的非映射设置

除了通过映射设置几何图形的图形颜色和形状属性外,ggplot2还提供了直接设定方式。和映射方式设置不一样的是:直接设定方式不会在图例上有反映。比较下面两图:

p  + geom_boxplot(aes(x=cut, fill=cut)) +
  scale_fill_manual(values=rep("cyan", length(levels(d.sub$cut))))
p  + geom_boxplot(aes(x=cut), fill="cyan")

2014042608164076520140426081648062

虽然填充色都是青色,但前者用的映射对数据进行了分组,所以会出现分组图例。注意:直接设定方法的参数名称和映射设定是一样的,但是不放在aes函数内部。

在qplot函数中如果要进行美学属性的非映射设定得用 “I” 函数,否则将被当长映射设置。

qplot(x=cut, y=price, data=d.sub, geom="boxplot", fill="cyan")
qplot(x=cut, y=price, data=d.sub, geom="boxplot", fill=I("cyan"))
2014042608170796820140426081716875

“I”函数表示设为固定值,如果不是在qplot函数中可以不用它。

透明度属性虽然包含在映射类型中,但一般情况下都是直接设定而非映射设定:

p + geom_point(data=diamonds, aes(alpha=carat/100))
p + geom_point(data=diamonds, alpha=0.05)
2014042608174968720140426081800328

第一张图就达不到设置透明度显示点密集度的效果

3 位置类型映射

x和y映射的用法很明确,就不再罗嗦了。xmin, xmax, ymin, ymax, xend, yend这几种映射属于特殊类型,H.W.在ggplot2的说明档里面写得很清楚(赞,H.W.不仅是写R软件的高手,还是普及教育的牛人),下面就照搬他的例子简单说明一下用法。

3.1 ymin/ymax映射的用法

下面代码通过直线拟合产生了钻石切工和价格的关系数据(预测的价格和标准差)

dmod <- lm(price ~ cut, data = diamonds)
cuts <- data.frame(cut = unique(diamonds$cut), predict(dmod, data.frame(cut =
unique(diamonds$cut)), se = TRUE)[c 1=""se.fit")" language="("fit","][/c])
cuts
##         cut  fit se.fit
## 1     Ideal 3458  27.00
## 2   Premium 4584  33.75
## 3      Good 3929  56.59
## 4 Very Good 3982  36.06
## 5      Fair 4359  98.79

通过设定ymin/ymax映射,用pointrange几何类型可以直接做出带误差线的散点图,无需使用errorbar设置:

se <- ggplot(cuts, aes(x = cut, y = fit, ymin = fit - se.fit, ymax = fit + se.fit, colour = cut))
se + geom_pointrange()

20140426081818500

当然也可以先画点再做误差线,这样思路明确些。或者做其他类型的图如柱形图:

se + geom_point() + geom_errorbar(width=0.2)
se + geom_bar(stat="identity", aes(fill=cut)) + geom_errorbar(width=0.2)

2014042608184320320140426081849953

min/ymax可以用来改变几何类型的坐标轴范围,但 这不是标准用法 ,最简单的是用ylim函数:

se + geom_point(aes(ymin = 3000, ymax = 4800)) + geom_errorbar(width=0.2)
se + geom_point() + geom_errorbar(width=0.2) + ylim(3000,4800)
# 或者用: scale_y_continuous(limits=c(3000,5000))

2014042608190371820140426081911625

但以上方法都不适用于柱形图,得用下面的方法,具体原因以后章节再说:

se + geom_bar(stat="identity", aes(fill=cut)) +
  geom_errorbar(width=0.2) + coord_cartesian(ylim=c(3000,4800))
20140426081925140

如果几何类型的设置参数中就包含位置类型映射,情况是很不一样的。所谓“太极”,有点道理:

px <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
px + annotate("rect", xmin = 2, xmax = 3.5, ymin = 2, ymax = 25, fill = "dark grey", alpha = .5)
library(grid)
px + geom_segment(aes(x = 5, y = 30, xend = 3.5, yend = 25), arrow = arrow(length = unit(0.5, "cm")))

2014042608193979620140426081949921

4 特殊类型映射

在ggplot2作图过程中,映射的处理在先于其他绘图步骤,也先于统计运算。颜色和形状类型的映射会对数据进行分组,统计运算使用的也是分组后的数据:

ggplot(d.sub, aes(x=carat, y=price, color=cut)) +
  geom_point() + geom_smooth(method="lm", se=FALSE)

20140426082439281

上面图中平滑曲线的统计处理是按cut进行分类后的数据进行的,分别作出了每一类数据的曲线。但如果要按分组前的数据做统计,就得把数据设为一个整体组;如果要按其他分组方式进行统计,也可以灵活设置:

ggplot(d.sub, aes(x=carat, y=price, color=cut)) +
  geom_point() + geom_smooth(aes(group=1), method="lm", se=FALSE)
ggplot(d.sub, aes(x=carat, y=price, color=cut)) + geom_point() +
  geom_smooth(aes(group=color, linetype=color), method="lm", se=FALSE, color="black")
2014042608250503120140426082513671

特殊类型映射有特殊应用。曲线图和柱形图对于x轴数据类型的要求是不一样的,曲线图要用连续型数据,而柱形图要用因子型(或离散型)数据,这两类图形如果不经特殊处理就不能放在一起。group映射可以轻松搞定它:

se + geom_bar(stat="identity", aes(fill=cut)) + geom_errorbar(width=0.2) +
  coord_cartesian(ylim=c(3000,4800)) + geom_line(aes(group=1), color="black")
20140426082544843

order映射用于改变数据类型的排序。注意是在图层中的排列顺序而不是图例的先后顺序。看下面图形颜色的差别:

p + geom_point(aes(color=cut, order=cut))
library(plyr) # 使用desc函数
p + geom_point(aes(color=cut, order=desc(cut)))

2014042608283995320140426082616515

aes_string太过另类,不说了。

5 SessionInfo

sessionInfo()
## R version 3.1.0 (2014-04-10)
## Platform: x86_64-pc-linux-gnu (64-bit)
## 
## locale:
##  [1] LC_CTYPE=zh_CN.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=zh_CN.UTF-8        LC_COLLATE=zh_CN.UTF-8    
##  [5] LC_MONETARY=zh_CN.UTF-8    LC_MESSAGES=zh_CN.UTF-8   
##  [7] LC_PAPER=zh_CN.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] grid      tcltk     stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
## [1] plyr_1.8.1      ggplot2_0.9.3.1 zblog_0.1.0     knitr_1.5      
## 
## loaded via a namespace (and not attached):
##  [1] colorspace_1.2-4 digest_0.6.4     evaluate_0.5.3   formatR_0.10    
##  [5] gtable_0.1.2     highr_0.3        labeling_0.2     MASS_7.3-31     
##  [9] munsell_0.4.2    proto_0.3-10     Rcpp_0.11.1      reshape2_1.2.2  
## [13] scales_0.2.4     stringr_0.6.2    tools_3.1.0

原文来自:http://blog.csdn.net/u014801157/article/details/24372505

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: