ggplot2作图详解:ggplot图形对象

转载自:http://blog.csdn.net/u014801157/article/details/24372503

前面我们使用qplot函数对ggplot2做图的方法进行了初步的了解,并比较了qplot和plot函数的用法。从最终得到的结果(图形)来看,除了外观不同外好像qplot函数和plot函数并没有什么本质的差别。这其实是一个骗局!

1 图形对象

我们知道,R语言基本做图方法都是通过函数完成的(如果不了解请参考本博客《散点图》一文),这些函数直接在输出设备上执行一些列操作得到图形。很多函数没有返回值,即使有返回值也不会反映绘图操作的整个过程。但ggplot2不一样,它用图形对象存储做图的细节,通过输出图形对象获得图形。一行一行地运行下面代码可以发现这一点:

<span style="color: rgb(0, 42, 84);">library</span>(ggplot2)
<span style="color: rgb(0, 42, 84);">theme_set</span>(<span style="color: rgb(0, 42, 84);">theme_bw</span>())
x <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(184, 93, 0);">1</span>:<span style="color: rgb(184, 93, 0);">100</span>
y <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(0, 42, 84);">rnorm</span>(<span style="color: rgb(184, 93, 0);">100</span>)
p1 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(0, 42, 84);">plot</span>(x, y)
p2 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(0, 42, 84);">qplot</span>(x, y)

很显然执行最后一行代码不会得到想要的图形。下面再看看 p1 和 p2 分别是什么:

<span style="color: rgb(0, 42, 84);">class</span>(p1)
## [1] "NULL"
<span style="color: rgb(0, 42, 84);">class</span>(p2)
## [1] "gg"     "ggplot"
<span style="color: rgb(0, 42, 84);">typeof</span>(p2)
## [1] "list"
<span style="color: rgb(0, 42, 84);">str</span>(p2)
## List of 9
##  $ data       :'data.frame':	0 obs. of  0 variables
##  $ layers     :List of 1
##   ..$ :Classes 'proto', 'environment'  
##  $ scales     :Reference class 'Scales' [package "ggplot2"] with 1 fields
##   ..$ scales: list()
##   ..and 21 methods, of which 9 are possibly relevant:
##   ..  add, clone, find, get_scales, has_scale, initialize, input, n,
##   ..  non_position_scales
##  $ mapping    :List of 2
##   ..$ x: symbol x
##   ..$ y: symbol y
##  $ theme      : list()
##  $ coordinates:List of 1
##   ..$ limits:List of 2
##   .. ..$ x: NULL
##   .. ..$ y: NULL
##   ..- attr(*, "class")= chr [1:2] "cartesian" "coord"
##  $ facet      :List of 1
##   ..$ shrink: logi TRUE
##   ..- attr(*, "class")= chr [1:2] "null" "facet"
##  $ plot_env   : 
##  $ labels     :List of 2
##   ..$ x: chr "x"
##   ..$ y: chr "y"
##  - attr(*, "class")= chr [1:2] "gg" "ggplot"

plot函数的返回值p1的class属性为NULL(空),而qplot函数的返回值p2的calss属性有两个“gg” 和 “ggplot”,其本质是长度为9的列表对象。打印这个对象就会得到图形:

<span style="color: rgb(0, 42, 84);">print</span>(p2)

qplot函数的作用是产生一个ggplot对象,但获得ggplot对象的更一般方法是使用对象类型的同名函数ggplot。它的用法是:

<span style="color: rgb(0, 0, 195);"># 非运行代码</span>
<span style="color: rgb(0, 42, 84);">ggplot</span>(df, <span style="color: rgb(0, 42, 84);">aes</span>(x, y, <other aesthetics>))
<span style="color: rgb(0, 42, 84);">ggplot</span>(df)
<span style="color: rgb(0, 42, 84);">ggplot</span>()

ggplot函数用于初始化一个ggplot对象,即使不指定任何做图相关的内容,它的结构也是完整的:

<span style="color: rgb(0, 42, 84);">length</span>(p2)
## [1] 9
<span style="color: rgb(0, 42, 84);">length</span>(<span style="color: rgb(0, 42, 84);">ggplot</span>())
## [1] 9

2 ggplot图形对象组成

ggplot图形对象是由9个元素组成的列表,这点已经清楚。元素的名称为:

<span style="color: rgb(0, 42, 84);">names</span>(p2)
## [1] "data"        "layers"      "scales"      "mapping"     "theme"      
## [6] "coordinates" "facet"       "plot_env"    "labels"

但是单从图形对象的结构上没办法理解ggplot2做图的过程和细节,所以还得了解一点相关的理论。ggplot2是Wilkinson做图理论 Grammer of Graphics 的R语言实现。太高深了,不知道从哪开始,还是从ggplot图形列表对象的元素组成做一点简单了解吧。

2.1 数据 data

似乎就是数据。但是如果试图查看上面p2对象的数据:

p2$data
## data frame with 0 columns and 0 rows

是空的。但如果使用qplot函数时指定了data,情况就不一样了:

p3 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(0, 42, 84);">qplot</span>(carat, price, <span style="color: rgb(0, 84, 0);">data</span>=diamonds, <span style="color: rgb(0, 84, 0);">color</span>=cut, <span style="color: rgb(0, 84, 0);">shape</span>=cut)
<span style="color: rgb(0, 42, 84);">head</span>(p3$data, <span style="color: rgb(184, 93, 0);">3</span>)
##   carat     cut color clarity depth table price    x    y    z
## 1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
## 2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
## 3  0.23    Good     E     VS1  56.9    65   327 4.05 4.07 2.31
<span style="color: rgb(0, 42, 84);">nrow</span>(p3$data)
## [1] 53940

列表对象的data元素存储了整个diamnods数据框的数据。用ggplot函数可以单独指定data项:

p4 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> <span style="color: rgb(0, 42, 84);">ggplot</span>(diamonds)
<span style="color: rgb(0, 42, 84);">head</span>(p4$data, <span style="color: rgb(184, 93, 0);">3</span>)
##   carat     cut color clarity depth table price    x    y    z
## 1  0.23   Ideal     E     SI2  61.5    55   326 3.95 3.98 2.43
## 2  0.21 Premium     E     SI1  59.8    61   326 3.89 3.84 2.31
## 3  0.23    Good     E     VS1  56.9    65   327 4.05 4.07 2.31

2.2 映射 mapping

ggplot对象的data项存储了整个数据框的内容,而“映射”则确定如何使用这些数据。在ggplot2中,图形的可视属性如形状、颜色、透明度等称为美学属性(或艺术属性),确定数据与美学属性之间对应关系的过程称为映射,通常使用aes函数完成(qplot函数中使用参数设置映射):

<span style="color: rgb(0, 42, 84);">str</span>(p3$mapping)
## List of 4
##  $ colour: symbol cut
##  $ shape : symbol cut
##  $ x     : symbol carat
##  $ y     : symbol price
<span style="color: rgb(0, 42, 84);">str</span>(p4$mapping)
##  list()
p4 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> p4 + <span style="color: rgb(0, 42, 84);">aes</span>(<span style="color: rgb(0, 84, 0);">x</span>=carat, <span style="color: rgb(0, 84, 0);">y</span>=price, <span style="color: rgb(0, 84, 0);">color</span>=color, <span style="color: rgb(0, 84, 0);">shape</span>=cut)
<span style="color: rgb(0, 42, 84);">str</span>(p4$mapping)
## List of 4
##  $ x     : symbol carat
##  $ y     : symbol price
##  $ colour: symbol color
##  $ shape : symbol cut
p4 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> p4 + <span style="color: rgb(0, 42, 84);">aes</span>(<span style="color: rgb(0, 84, 0);">x</span>=carat, <span style="color: rgb(0, 84, 0);">y</span>=price, <span style="color: rgb(0, 84, 0);">color</span>=cut, <span style="color: rgb(0, 84, 0);">shape</span>=cut)
<span style="color: rgb(0, 42, 84);">str</span>(p4$mapping)
## List of 4
##  $ x     : symbol carat
##  $ y     : symbol price
##  $ colour: symbol cut
##  $ shape : symbol cut

需要说明的是,上面第三行代码使用了加号,这是ggplot2为ggplot对象定义的运算方法,表示设置ggplot对象中对应的内容。

2.3 图层 layers

2.3.1 图层组成

在ggplot的列表结构里面看不到我们指定的图形类型参数。这些设置被分派到layers里面了:

p3$layers
## [[1]]
## geom_point:  
## stat_identity:  
## position_identity: (width = NULL, height = NULL)

一个图层包含了至少3个东西(数据和映射当然必需,另算):geom、stat和position

  • 几何类型 geom:是数据在图上的展示形式,即点、线、面等。在ggplot2里面有很多预定义的几何类型。
  • 统计类型 stat:是对数据所应用的统计类型/方法。上面的p2和p3对象我们并没有指定统计类型,但是自动获得了identity,因为ggplot2为每一种几何类型指定了一种默认的统计类型,反之亦然。所以如果仅指定geom或stat中的一个,另外一个会自动获取。
  • 位置 position:几何对象在图像上的位置调整,这也有默认设定。

不指定几何类型或统计类型的ggplot对象的图层是空列表,即没有图层,也不能输出图像:

p4$layers
## list()
<span style="color: rgb(0, 42, 84);">print</span>(p4)
## Error: No layers in plot

也就是说,指定了几何类型或统计类型,图层就会产生:

(p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>())$layers
## [[1]]
## geom_point: na.rm = FALSE 
## stat_identity:  
## position_identity: (width = NULL, height = NULL)
(p4 + <span style="color: rgb(0, 42, 84);">stat_identity</span>())$layers
## [[1]]
## geom_point:  
## stat_identity: width = NULL, height = NULL 
## position_identity: (width = NULL, height = NULL)

为什么图层说“至少”包含3个内容呢?如果你把整个图层的内容转成列表结构显示以下就会发现更多:

<span style="color: rgb(0, 42, 84);">as.list</span>((p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>())$layers[[<span style="color: rgb(184, 93, 0);">1</span>]])
## $mapping
## NULL
## 
## $geom_params
## $geom_params$na.rm
## [1] FALSE
## 
## 
## $stat_params
## named list()
## 
## $stat
## stat_identity: 
## 
## $inherit.aes
## [1] TRUE
## 
## $geom
## geom_point: 
## 
## $position
## position_identity: (width = NULL, height = NULL)
## 
## $subset
## NULL
## 
## $data
## list()
## attr(,"class")
## [1] "waiver"
## 
## $show_guide
## [1] NA

2.3.2 图层加法

从图层的结构可以看到它在ggplot对象中是一个多重列表,如果对ggplot对象做图层加法运算,是增加图层而不是替换图层:

(p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>() + <span style="color: rgb(0, 42, 84);">geom_line</span>())$layers
## [[1]]
## geom_point: na.rm = FALSE 
## stat_identity:  
## position_identity: (width = NULL, height = NULL)
## 
## [[2]]
## geom_line:  
## stat_identity:  
## position_identity: (width = NULL, height = NULL)

2.3.3 图层顺序

ggplot2按“层”做图,所以图层的顺序对于图形的表现会有影响,如果几何对象有叠加,那么后面图层的对象会覆盖前面图层的对象。下面只是调换了两个图层的顺序,但由于数据点是相同的,所以图形的颜色完全不一样:

p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>(<span style="color: rgb(0, 84, 0);">color</span>=<span style="color: rgb(209, 0, 0);">"red"</span>) + <span style="color: rgb(0, 42, 84);">geom_point</span>(<span style="color: rgb(0, 84, 0);">color</span>=<span style="color: rgb(209, 0, 0);">"blue"</span>)
p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>(<span style="color: rgb(0, 84, 0);">color</span>=<span style="color: rgb(209, 0, 0);">"blue"</span>) + <span style="color: rgb(0, 42, 84);">geom_point</span>(<span style="color: rgb(0, 84, 0);">color</span>=<span style="color: rgb(209, 0, 0);">"red"</span>)

2.4 标尺 scales

这是ggplot2中比较复杂的一个概念,从ggplot对象中能获取的信息不多:

p4$scales
## Reference class object of class "Scales"
## Field "scales":
## list()

在ggplot2中,一个标尺就是一个函数,它使用一系列参数将我们的数据(如钻石价格、克拉)转成计算机能够识别的数据(如像素、颜色值),然后展示在图像上。使用标尺对数据进行处理的过程称为缩放(scaling)。坐标的产生和图形美学属性的处理都需要使用标尺对数据进行缩放。这个过程比较复杂,尤其是美学属性与数据的关联,因为和美学属性相关的数据不仅有连续型还有离散型,多组数据之间还要相互关照。但这些过程我们都可以不管,ggplot2也替我们做了。

标尺是函数,它的反函数用于产生坐标刻度标签和图表的图例等,这样我们才能把图形外观、位置等信息和数据对应起来。

2.5 坐标 coordinates

这都知道,用于确定采用的坐标系统和坐标轴的范围。

<span style="color: rgb(0, 42, 84);">str</span>(p4$coordinates)
## List of 1
##  $ limits:List of 2
##   ..$ x: NULL
##   ..$ y: NULL
##  - attr(*, "class")= chr [1:2] "cartesian" "coord"

2.6 主题 theme

标题文字(字体、字号、颜色)、图形边框和底纹等跟数据无关的一些图形元素的设置都可以归到“主题”这一类。ggplot2提供了4个成套主题:theme_gray(), theme_bw() , theme_minimal() 和 theme_classic()。其中theme_gray()为默认主题,灰背景;后两个是0.9.3版才增加的。

p5 <span style="color: rgb(84, 0, 84);"><strong><-</strong></span> p4 + <span style="color: rgb(0, 42, 84);">geom_point</span>(<span style="color: rgb(0, 84, 0);">color</span>=<span style="color: rgb(209, 0, 0);">"blue"</span>)
p5 + <span style="color: rgb(0, 42, 84);">theme_gray</span>() + <span style="color: rgb(0, 42, 84);">ggtitle</span>(<span style="color: rgb(209, 0, 0);">"theme_gray()"</span>)
p5 + <span style="color: rgb(0, 42, 84);">theme_bw</span>() + <span style="color: rgb(0, 42, 84);">ggtitle</span>(<span style="color: rgb(209, 0, 0);">"theme_bw()"</span>)
p5 + <span style="color: rgb(0, 42, 84);">theme_minimal</span>() + <span style="color: rgb(0, 42, 84);">ggtitle</span>(<span style="color: rgb(209, 0, 0);">"theme_minimal()"</span>)
p5 + <span style="color: rgb(0, 42, 84);">theme_classic</span>() + <span style="color: rgb(0, 42, 84);">ggtitle</span>(<span style="color: rgb(209, 0, 0);">"theme_classic()"</span>)


2.7 分面 facet:

一页多图,跟图层好像没有直接关系。以后再说。

2.8 标签 labels:

<span style="color: rgb(0, 42, 84);">str</span>(p4$labels)
## List of 4
##  $ x     : chr "carat"
##  $ y     : chr "price"
##  $ colour: chr "cut"
##  $ shape : chr "cut"

3 ggplot2做图过程

如果E文水平可以,下载 Hadley Wickham 写的《ggplot2: Elegant Graphics for Data Analysis》一书来看看(到处都有)。理论性太强,太高深,不敢乱说。

4 SessionInfo

<span style="color: rgb(0, 42, 84);">sessionInfo</span>()
## 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] tcltk     stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
## [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] grid_3.1.0       gtable_0.1.2     highr_0.3        labeling_0.2    
##  [9] MASS_7.3-31      munsell_0.4.2    plyr_1.8.1       proto_0.3-10    
## [13] Rcpp_0.11.1      reshape2_1.2.2   scales_0.2.4     stringr_0.6.2   
## [17] tools_3.1.0

中译本序, 每当我们看到一个新的软件,第一反应会是:为什么又要发明一个新软件?ggplot2是R世界里相对还比较年轻的一个包,在它之前,官方R已经有自己的基础图形系统(graphics包)和网格图形系统(grid包),并且Deepayan Sarkar也开发了lattice包,看起来R的世界对图形的支持已经足够强大了。那么我们不禁要问,为什么还要发明一套新的系统?, 设计理念, 打个比方,想想我们小时候怎样学中文的。最开始的时候我们要识字,不认识字就没法阅读和写作,但我们并不是一直按照一个个汉字学习的,而是通过句子和具体的场景故事学习的。为什么不在小学时背六年字典呢?那样可能认识所有的汉字。原因很简单,光有单字,我们不会说话,也无法阅读和写作。缺的是什么?答案是对文字的组织能力,或者说语法。, R的基础图形系统基本上是一个“纸笔模型”,即:一块画布摆在面前,你可以在这里画几个点,在那里画几条线,指哪儿画哪儿。后来lattice包的出现稍微改善了这种情况,你可以说,我要画散点图或直方图,并且按照某个分类变量给图中的元素上色,此时数据才在画图中扮演了一定的中心角色,我们不用去想具体这个点要用什么颜色(颜色会根据变量自动生成)。然而,lattice继承了R语言的一个糟糕特征,就是参数设置铺天盖地,足以让人窒息,光是一份xyplot()函数的帮助文档,恐怕就够我们消磨一天时间了,更重要的是,lattice仍然面向特定的统计图形,像基础图形系统一样,有直方图、箱线图、条形图等等,它没有一套可以让数据分析者说话的语法。, 那么数据分析者是怎样说话的呢?他们从来不会说这条线用#FE09BE颜色,那个点用三角形状,他们只会说,把图中的线用数据中的职业类型变量上色,或图中点的形状对应性别变量。有时候他们画了一幅散点图,但马上他们发现这幅图太拥挤,最好是能具体看一下里面不同收入阶层的特征,所以他们会说,把这幅图拆成七幅小图,每幅图对应一个收入阶层。然后发现散点图的趋势不明显,最好加上回归直线,看看回归模型反映的趋势是什么,或者发现图中离群点太多,最好做一下对数变换,减少大数值对图形的主导性。, 从始至终,数据分析者都在数据层面上思考问题,而不是拿着水彩笔和调色板在那里一笔一划作图,而计算机程序员则倾向于画点画线。Leland Wilkinson的著作在理论上改善了这种状况,他提出了一套图形语法,让我们在考虑如何构建一幅图形的时候不再陷在具体的图形元素里面,而是把图形拆分为一些互相独立并且可以自由组合的成分。这套语法提出来之后他自己也做了一套软件,但显然这套软件没有被广泛采用;幸运的是,Hadley Wickham在R语言中把这套想法巧妙地实现了。, 为了说明这种语法的想法,我们考虑图形中的一个成分:坐标系。常见的坐标系有两种:笛卡尔坐标系和极坐标系。在语法中,它们属于一个成分,可自由拆卸替换。笛卡尔坐标系下的条形图实际上可以对应极坐标系下的饼图,因为条形图的高可以对应饼图的角度,本质上没什么区别。因此在ggplot2中,从一幅条形图过渡到饼图,只需要加极少量的代码,把坐标系换一下就可以了。如果我们用纸笔模型,则可以想象,这完全是不同的两幅图,一幅图里面要画的是矩形,另一幅图要画扇形。, 更多的细节在本书中会介绍,这里我们只是简略说明用语法画图对用纸笔画图来说在思维上的优越性;前者是说话,后者是说字。, 发展历程, ggplot2是Hadley在爱荷华州立大学博士期间的作品,也是他博士论文的主题之一,实际上ggplot2还有个前身ggplot,但后来废弃了,某种程度上这也是Hadley写软件的特征,熟悉他的人就知道这不是他第一个“2”版本的包了(还有reshape2)。带2的包和原来的包在语法上会有很大的改动,基本上不兼容。尽管如此,他的R代码风格在R社区可谓独树一帜,尤其是他的代码结构很好,可读性很高,ggplot2是R代码抽象的一个杰作。读者若感兴趣,可以在GitHub网站上浏览他的包:https://github.com/hadley。在用法方面,ggplot2也开创了一种奇特而绝妙的语法,那就是加号:一幅图形从背后的设计来说,是若干图形语法的叠加,从外在的代码来看,也是若干R对象的相加。这一点精妙尽管只是ggplot2系统的很小一部分,但我个人认为没有任何程序语言可比拟,它对作为泛型函数的加号的扩展只能用两个字形容:绝了。, 至2013年2月26日,ggplot2的邮件列表(http://groups.google.com/group/ggplot2 )订阅成员已达3394人,邮件总数为15185封,已经成为一个丰富、活跃的用户社区。未来ggplot2的发展也将越来越依赖于用户的贡献,这也是很多开源软件最终的走向。, 关于版本更新, 原书面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值