1.ggplot2发展历程
ggplot2是Hadley在爱荷华州立大学博士期间的作品,也是他博士论文的主题之一,实际上ggplot2还有个前身ggplot,但后来废弃了,某种程度上这也是Hadley写软件的特 征,熟悉他的人就知道这不是他第一个“2”版本的包了(还有reshape2)。带2的包和原来的包在语法上会有很大的改动,基本上不兼容。尽管如此,他的R代码风格在R社区可谓独树一帜,尤其是他的代码结构很好,可读性很高,ggplot2是R代码抽象的一个杰作。读者若感兴趣,可以在GitHub网站上浏览他的包:https://github.com/hadley。在用法方面,ggplot2也开创了一种奇特而绝妙的语法,那就是加号:一幅图形从背后的设计来说,是若干图形语法的叠加,从外在的代码来看,也是若干R对象的相加。这一点精妙尽管只是ggplot2系统的很小一部分,但我个人认为没有任何程序语言可比拟,它对作为泛型函数的加号的扩展只能用两个字形容:绝了。
2.作者简介
Hadley Wickham,RStudio首席科学家,美国莱斯大学统计学助理教授,毕业于爱荷华州立大学统计系。Hadley是R社区最活跃的人之一,代码风格独树一帜,致力于开发用于数据处理、分析、成像的工具,截至2012年已经开发了超过30个高质量的R软件包,比如ggplot2, lubridate,plyr, reshape2, stringr, httr等。
3.qplot(quick plot)快速绘图函数
本节会使用ggplot2包内带的汽车测试数据(mpg)来举个例子,变量包括发动机容量(displ)、高速公路上的每加仑行驶里数(hwy)、汽缸数目(cyl)等。
ggplot2 中最简单的绘图方式是利用qplot() 函数,即快速绘图函数。格式为:
qplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE, geom = "auto", xlim = c(NA, NA), ylim = c(NA, NA), log = "", main = NULL, xlab = deparse(substitute(x)), ylab = deparse(substitute(y)), asp = NA, stat = NULL, position = NULL) quickplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE, geom = "auto", xlim = c(NA, NA), ylim = c(NA, NA), log = "", main = NULL, xlab = deparse(substitute(x)), ylab = deparse(substitute(y)), asp = NA, stat = NULL, position = NULL)
参数含义:
选项 |
描述 |
alpha |
元素重叠的alpha透明度,数值为0(完全透明)到1(完全不透明)间的分数 |
color、shape、size、fill |
把变量的水平与符号颜色、形状或大小联系起来。对于直线图, color将把线条颜色与变量水平联系起来,对于密度图和箱线图, fill将把填充颜色与变量联系起来。图例将会被自动绘制 |
data |
指定一个数据框 |
facets |
指定条件变量,创建一个栅栏图。表达式如rowvar ~ colvar(示例见图16-10)。为创建一个基于单条件变量的栅栏图,可用rowvar ~ .或. ~ colvar |
geom |
设定定义图形类型的几何形状。 geom选项是一个单条目或多条目的字符型向量,包括 "point" 、 "smooth" 、 "boxplot" 、 "line" 、 "histogram" 、"density" 、 "bar" 和"jitter" |
main、sub |
字符向量,设定标题和副标题 |
method、formula |
若geom = "smooth" ,则会默认添加一条平滑拟合曲线和置信区间。 当观测数大于1000时,便需要调用更高效的平滑拟合算法。方法包括回归lm、广义可加模型gam、稳健回归rlm。 formula参数指定拟合的形式例如,要添加简单的回归曲线,则设定geom = "smooth", method = "lm",formula = y ~ x。将表达式改为y ~ poly(x, 2) 将生成二次拟合。注意表达式使用的是字母x和y,而不是变量的名称对于method = "gam" ,一定要记得加载mgcv包。对于method = "rml" ,则需加载MASS包 |
x、y |
指定摆放在水平轴和竖直轴的变量。对于单变量图形(如直方图),则省略y |
xlab、ylab |
字符向量,设定横轴和纵轴标签 |
xlim、ylim |
二元素数值型向量,分别指定横轴和纵轴的最小值和最大值 |
stat |
废弃 |
asp |
The y/x aspect ratio ,y/x宽高比 |
log |
Which variables to log transform ("x", "y", or "xy"),指定对数变换的变量 |
margins |
See facet_grid : display marginal facets?用于facet-grid:是否显示边界分面
|
# 使用默认设置画散点图 qplot(mpg, wt, data = mtcars)
# 根据cyl属性使用颜色标记 qplot(mpg, wt, data = mtcars, colour = cyl)
# 根据cyl属性使用尺寸大小表示 qplot(mpg, wt, data = mtcars, size = cyl)
# 使用vs~am分为4个组 分别画散点图 qplot(mpg, wt, data = mtcars, facets = vs ~ am)
qplot(1:10, rnorm(10), colour = runif(10))
mod <- lm(mpg ~ wt, data=mtcars) qplot(resid(mod), fitted(mod))
f <- function() { a <- 1:10 b <- a ^ 2 qplot(a, b) } f()
# 指定颜色 qplot(mpg, wt, data = mtcars, colour = I("red"))
# 频数图qplot(mpg, data = mtcars)
qplot(y = mpg, data = mtcars)
# Use different geoms使用不同的几何对象 qplot(mpg, wt, data = mtcars, geom = "path")# 路径 qplot(factor(cyl), wt, data = mtcars, geom = c("boxplot", "jitter"))# 箱线图+抖动 qplot(mpg, data = mtcars, geom = "dotplot")# 点图
4.ggplot2基本元素
图层(Layer):如果你用过photoshop,那么对于图层一定不会陌生。一个图层好比是 一张玻璃纸,包含有各种图形元素,你可以分别建立图层然后叠放在一起,组合成图形的最终效果。图层可以允许用户一步步的构建图形,方便单独对图层进行修 改、增加统计量、甚至改动数据。
标度(Scale):标度是一种函数,它控制了数学空间到图形元素空间的映射。一组连续数据可以映射到X轴坐标,也可以映射到一组连续的渐变色彩。一组分类数据可以映射成为不同的形状,也可以映射成为不同的大小。
坐标系统(Coordinate):坐标系统控制了图形的坐标轴并影响所有图形元素,最常用的是直角坐标轴,坐标轴可以进行变换以满足不同的需要,如对数坐标。其它可选的还有极坐标轴。
位面(Facet):很多时候需要将数据按某种方法分组,分别进行绘图。位面就是控制分组绘图的方法和排列形式。
数据(data):需要可视化的数据。
映射(mapping):一系列将数据中变量对应到图形属性。
几何对象(geom):代表在图中实际看到的图形元素,如点、线、多边形等。
统计变换(stats):是对数据进行某种汇总。例如:将数据分组计数以创建直方图,或是将一个二维的关系用线性模型进行解释。统计变换是可选个的,但通常非常有用。
4.1ggplot绘图函数格式
ggplot(data = NULL, mapping = aes(), ..., environment = parent.frame())
4.2数据(data)和映射(mapping)
以钻石数据集为例,由于数据量大,随机选取一个子集来画图:
require(ggplot2) data(diamonds) set.seed(42) newDiamonds <- diamonds[sample(nrow(diamonds), 1000), ] head(newDiamonds) ## carat cut color clarity depth table price x y z ## 49345 0.71 Very Good H SI1 62.5 60 2096 5.68 5.75 3.57 ## 50545 0.79 Premium H SI1 61.8 59 2275 5.97 5.91 3.67 ## 15434 1.03 Ideal F SI1 62.4 57 6178 6.48 6.44 4.03 ## 44792 0.50 Ideal E VS2 62.2 54 1624 5.08 5.11 3.17 ## 34614 0.27 Ideal E VS1 61.6 56 470 4.14 4.17 2.56 ## 27998 0.30 Premium E VS2 61.7 58 658 4.32 4.34 2.67
查看summary:
summary(newDiamonds) ## carat cut color clarity depth table ## Min. :0.2200 Fair : 28 D:121 SI1 :258 Min. :55.20 Min. :50.10 ## 1st Qu.:0.4000 Good : 88 E:186 VS2 :231 1st Qu.:61.00 1st Qu.:56.00 ## Median :0.7100 Very Good:227 F:164 SI2 :175 Median :61.80 Median :57.00 ## Mean :0.8187 Premium :257 G:216 VS1 :141 Mean :61.71 Mean :57.43 ## 3rd Qu.:1.0700 Ideal :400 H:154 VVS2 : 91 3rd Qu.:62.50 3rd Qu.:59.00 ## Max. :2.6600 I:106 VVS1 : 67 Max. :72.20 Max. :65.00 ## J: 53 (Other): 37 ## price x y z ## Min. : 342.0 Min. :3.850 Min. :3.840 Min. :2.330 ## 1st Qu.: 989.5 1st Qu.:4.740 1st Qu.:4.758 1st Qu.:2.920 ## Median : 2595.0 Median :5.750 Median :5.775 Median :3.550 ## Mean : 4110.5 Mean :5.787 Mean :5.791 Mean :3.572 ## 3rd Qu.: 5495.2 3rd Qu.:6.600 3rd Qu.:6.610 3rd Qu.:4.070 ## Max. :18795.0 Max. :8.830 Max. :8.870 Max. :5.580
绘图实际上是将数据中的变量映射到图形属性上,将克拉(carat)数映射为x轴变量,价格(price)映射为y轴变量,如下所示:
g <- ggplot(data = newDiamonds,mapping = aes(x = carat,y = price)) # 查看变量g的数据 head(g$data) ## carat cut color clarity depth table price x y z ## 49345 0.71 Very Good H SI1 62.5 60 2096 5.68 5.75 3.57 ## 50545 0.79 Premium H SI1 61.8 59 2275 5.97 5.91 3.67 ## 15434 1.03 Ideal F SI1 62.4 57 6178 6.48 6.44 4.03 ## 44792 0.50 Ideal E VS2 62.2 54 1624 5.08 5.11 3.17 ## 34614 0.27 Ideal E VS1 61.6 56 470 4.14 4.17 2.56 ## 27998 0.30 Premium E VS2 61.7 58 658 4.32 4.34 2.67 # 查看变量g的映射 g$mapping ## * x -> carat ## * y -> price
以上代码将数据映射到XY坐标轴上,然后需要告诉ggplot2,这些数据要映射成什么样的几何对象,下面以散点为例:
# 设定几何对象为散点geom_point() g <- g + geom_point() # 显示图层 g
如果想要将属性切工(cut)映射到形状属性,可以通过下面的代码实现:
g <- ggplot(data = newDiamonds,mapping = aes(x = carat,y = price,shape = cut)) g +geom_point()
将钻石的颜色(color)映射颜色属性:
g <- ggplot(data=newDiamonds, mapping=aes(x = carat, y = price, shape = cut, colour = color)) g+geom_point()
4.3几何对象(geom Geometric)
4.1中各种属性映射由ggplot函数执行,只需要加一个图层(用+连接),使用geom_point()告诉ggplot要画散点,于是所有的属性都映射到散点上。geom_point()就是几何对象散点的映射,ggplot2提供了各种几何对象的映射,如geom_histogram用于直方图,geom_bar用于柱状图,geom_boxplot用于箱线图等等,见下表(省略geom_):
查看可用几何对象:
ls("package:ggplot2", pattern="^geom_.+") ## [1] "geom_abline" "geom_area" "geom_bar" "geom_bin2d" ## [5] "geom_blank" "geom_boxplot" "geom_contour" "geom_count" ## [9] "geom_crossbar" "geom_curve" "geom_density" "geom_density_2d" ## [13] "geom_density2d" "geom_dotplot" "geom_errorbar" "geom_errorbarh" ## [17] "geom_freqpoly" "geom_hex" "geom_histogram" "geom_hline" ## [21] "geom_jitter" "geom_label" "geom_line" "geom_linerange" ## [25] "geom_map" "geom_path" "geom_point" "geom_pointrange" ## [29] "geom_polygon" "geom_qq" "geom_quantile" "geom_raster" ## [33] "geom_rect" "geom_ribbon" "geom_rug" "geom_segment" ## [37] "geom_smooth" "geom_spoke" "geom_step" "geom_text" ## [41] "geom_tile" "geom_violin" "geom_vline"
不同的几何对象,要求的属性会有些不同,这些属性也可以在几何对象映射时提供,比如上一图,也可以用以下语法来画:
g <- ggplot(newDiamonds) g+geom_point(aes(x=carat, y=price, shape=cut, colour=color))
由于ggplot2支持图层,通常,把不同的图层中共用的映射提供给ggplot函数,而某一几何对象才需要的映射参数提供给geom_xxx函数。
下面介绍各种结合对象的画法:
4.3.1直方图histogram
ggplot2使用图层将各种图形元素逐步添加组合,从而形成最终结果。第一层必须是原始数据层,其中data参数控制数据来源,注意数据形式只能是数据框格式。aes参数控制了对哪些变量进行图形映射,以及映射方式,aes是Aesthetic的缩写。
直方图最容易,提供一个x变量,画出数据的分布。
ggplot(newDiamonds) + geom_histogram(aes(x = price))
同样可以根据另外的变量给它填充颜色,比如按不同的切工:
ggplot(newDiamonds) + geom_histogram(aes(x = price,fill = cut))
也可以将其分开,side-by-side地画直方图。
ggplot(newDiamonds) + geom_histogram(aes(x = price,fill = cut), position="dodge")
还可以使用position="fill",按照相对比例来画。
查看信息:
g <- ggplot(newDiamonds) g <- g+geom_histogram(aes(x = price,fill = cut), position="dodge") print(g) summary(g) ## data: carat, cut, color, clarity, depth, table, price, x, y, z [1000x10] ## faceting: facet_null() ## ----------------------------------- ## mapping: x = price, fill = cut ## geom_bar: na.rm = FALSE ## stat_bin: binwidth = NULL, bins = NULL, na.rm = FALSE, pad = FALSE ## position_dodge
上面的信息告诉我们,g对象含有两层(由--------分界),第一层数据层描述了变量和映射方式,第二层是直方图对象(geom_histogram),geom表示几何对象,它是ggplot中重要的图层控制对象,因为它负责图形渲染的类型。geom_histogram是图形渲染类型的一种,其它类型可参见官网。
每个geom对象都需要有数据输入,数据可以从第一层中自动读取,也可以在aes参数中直接设置。而且每个geom还默认搭配某种统计变换(stat),geom_histogram的默认统计变换是stat_bin。它负责对数据进行分组计数。
下面我们尝试两种更为复杂的直方图,首先将数据按照year这个变量划分为两组,用不同的颜色绘制直方图,而且用频率而非计数来刻画Y轴,并添加密度曲线。
g <- ggplot(data = mpg,aes(hwy)) g <- g + geom_histogram(position = ‘identity‘,alpha = 0.5,aes(y = ..density..,fill = factor(year))) g <- g + stat_density(geom = ‘line‘,position = ‘identity‘,aes(colour = factor(year)),adjust = 0.5) print(g)
alpha:透明度调节;position: fill:填充色,此处是根据因子年份来选择颜色进行填充,一般使用与条形图,fill后面跟着的是一个变量,且是一个分类变量,得到的结果是颜色会根据分类不同使用不同颜色
;colour:边框色或线颜色;position = "dodge"将同类条形图并排放着,(dodge英文意思是闪躲回避的意思,这样记它的作用会比较快)
将两年分开表示:
g <- ggplot(data = mpg,aes(hwy)) g <- g + geom_histogram(position = ‘identity‘,alpha = 0.5,aes(y = ..density..,fill = factor(year))) g <- g + stat_density(geom = ‘line‘,position = ‘identity‘,aes(colour = factor(year)),adjust = 0.5) g <- g + facet_wrap(~year,ncol = 1) print(g)
下面逐步变化直方图:
ggplot(data=iris,aes(x=Sepal.Length))+ geom_histogram()
上面的图形不够生动,我们可以调整一些3参数,使之变得不一样:
ggplot(iris,aes(x=Sepal.Length))+ geom_histogram(binwidth=0.1, # 设置组距 fill=‘skyblue‘, # 设置填充色 colour=‘black‘) # 设置边框色
直方图加密度曲线:直方图的作用主要是展现分组计数和分布特性,因为考查一个样本是否符合某个分布在传统统计学中有着重要的意义。不过有另一种方法也可以展现数据的分布,即核密度估计曲线。简单来说就是根据数据估算一条可以代表其分布的密度曲线。我们可以将直方图和密度曲线重叠显示。
ggplot(iris,aes(x=Sepal.Length)) + geom_histogram(aes(y=..density..), fill=‘skyblue‘, color=‘black‘) + stat_density(geom=‘line‘,color=‘black‘, linetype=2,adjust=2)
密度曲线:adjust参数和窗宽参数类似,它将会控制密度曲线的细节表现能力。我们来尝试用不同的参数绘制多条密度曲线。可见参数越小曲线越为波动灵敏,adjuct负责控制这个参数。
ggplot(iris,aes(x=Sepal.Length)) + geom_histogram(aes(y=..density..), # 注意要将y设为相对频数 fill=‘gray60‘, color=‘gray‘) + stat_density(geom=‘line‘,color=‘blue‘,linetype=1,adjust=0.5)+ stat_density(geom=‘line‘,color=‘red‘,linetype=2,adjust=1)+ stat_density(geom=‘line‘,color=‘green‘,linetype=3,adjust=2)
密度曲线还方便对不同数据进行比较,例如我们要对iris中三种不同花的Sepal.Length分布进行比较,可以像下面一样:
ggplot(iris,aes(x=Sepal.Length,fill=Species)) + geom_density(alpha=0.5,color=‘red‘)
4.3.2条形图或柱形图bar
柱状图两个要素,一个是分类变量,一个是数目,也就是柱子的高度。数目在这里不用提供,因为ggplot2会通过x变量计算各个分类的数目。
mpg数据集中各车型所比例,以及在这些车型中各年份所占的比例。
class <- factor(mpg$year) p <- ggplot(mpg,aes(x=class,fill=year))+ geom_bar(color=‘black‘) print(p)
条形图位置调整,也就是前面总出现的position参数的设置值:位置调整(Position adjustments)是针对同一图层内元素的位置进行微调的方法。它包括五种设置,分别是stack(堆叠)、dodge(躲开,闪避)、fill(填充)、identity(密度)、jitter(抖动)。
仍使用mpg数据集,其中用到的变量是class,即生产汽车的类型,以及year生产年份。下面的条形图是将各类型的汽车数量进行汇集,并以年份作为分组变量。我们首先载入扩展包,然后用频数表对数据进行大致的了解,最后绘制了四种条形图。
library(ggplot2) with(mpg,table(class,year)) ## year ## class 1999 2008 ## 2seater 2 3 ## compact 25 22 ## midsize 20 21 ## minivan 6 5 ## pickup 16 17 ## subcompact 19 16 ## suv 29 33 g <- ggplot(data=mpg,aes(x=class,fill=factor(year))) summary(g) ## data: manufacturer, model, displ, year, cyl, trans, drv, cty, hwy, fl, class ## [234x11] ## mapping: x = class, fill = factor(year) ## faceting: facet_null() g + geom_bar(position=‘dodge‘)+labs(x="class",y="count",title = "dodge闪避")#也可以写成position_dodge() g + geom_bar(position=‘stack‘)+labs(x="class",y="count",title = "stack堆叠")#也可以写成position_stack() g + geom_bar(position=‘fill‘)+labs(x="class",y="count",title = "fill填充")#也可以写成position_fill() g + geom_bar(position=‘identity‘,alpha=0.3) + labs(x="class",y="count",title = "identity密度")#也可以写成position_identity()
可以看到dodge方式是将不同年份的数据并列放置;stack方式是将不同年份数据推叠放置,这也是geom_bar和geom_histogram的默认处理方式;fill方式和stack类似,但Y轴不再是计数,而是以百分比显示;identity方式是不做任何改变直接显示出来,所以需要设置透明度才能看得清楚。注意:position同样适用于直方图
柱状图和直方图的区别:
柱状图和直方图是很像的,直方图把连续型的数据按照一个个等长的分区(bin)来切分,然后计数,画柱状图。而柱状图是分类数据,按类别计数。我们可以用前面直方图的参数来画side-by-side的柱状图,填充颜色或者按比例画图,它们是高度一致的。
柱状图是用来表示计数数据的,但在生物界却被经常拿来表示均值,加上误差来表示数据分布,这可以通常图层来实现,我将在图层一节中给出实例。
更多参考如下官网:
http://docs.ggplot2.org/current/
http://docs.ggplot2.org/current/vignettes/ggplot2-specs.html
http://docs.ggplot2.org/current/vignettes/extending-ggplot2.html
4.4统计变换(statistics)
统计变换是以某种方式对数据信息进行汇总,几何对象控制生成的图像类型。“一个几何对象包含了一种统计变换,一个统计变换包含了一个几何对象”这句话更准确地来说是“每一个几何对象都有一个默认的统计变换,并且每一个统计变换也都有一个默认的几何对象”。
查看可用统计变换:
ls("package:ggplot2", pattern="^stat_.+") ## [1] "stat_bin" "stat_bin_2d" "stat_bin_hex" ## [4] "stat_bin2d" "stat_binhex" "stat_boxplot" ## [7] "stat_contour" "stat_count" "stat_density" ## [10] "stat_density_2d" "stat_density2d" "stat_ecdf" ## [13] "stat_ellipse" "stat_function" "stat_identity" ## [16] "stat_qq" "stat_quantile" "stat_smooth" ## [19] "stat_spoke" "stat_sum" "stat_summary" ## [22] "stat_summary_2d" "stat_summary_bin" "stat_summary_hex" ## [25] "stat_summary2d" "stat_unique" "stat_ydensity"
举个例子来说明每一个几何对象都会有一个默认的统计变换。如果我们想要绘制ggplot2中的数据集diamonds中的carat直方图:
ggplot(diamonds,aes(carat))+geom_histogram(binwidth=0.1)
这里geom_histogram意味着我们选择的几何对象是直方图,而绘制一个直方图就需要确定条形图的高度和组的中心值,所以必须要对数据进行统计变换,这里的统计变换包括count(观测值计数),density(观测值密度),x(组的中心位置),然后默认将条形图的高度赋值为观测值的频数(count),当然如果想要用密度代替也是可以的:
ggplot(diamonds,aes(carat))+geom_histogram(aes(y=..density..),binwidth=0.1)
同样每个统计变换都有默认的几何对象,封箱(bin)统计变换默认使用条状几何对象(bar geom)来绘制直方图,下面的语句所绘制的图像和之前绘制的直方图是一样的。
ggplot(diamonds,aes(carat))+stat_bin(binwidth = 0.1) ggplot(diamonds,aes(carat))+stat_bin(aes(y=..density..),binwidth = 0.1)
既然是默认的统计变换/几何对象,那么是可以改变默认值的,这样会画出新奇甚至怪异的图像。
我们把统计变换bin默认的几何对象”bar“改为”area“和”step“
ggplot(diamonds,aes(carat))+stat_bin(aes(ymax=..density..),binwidth = 0.1,geom="area") ggplot(diamonds,aes(carat))+stat_bin(aes(ymax=..count..),binwidth = 0.1,geom="step")
统计变换对原始数据进行某种计算,然后在图上表示出来,例如对散点图上加一条回归线。可以使用stat=来设定统计变换方式。
ggplot(newDiamonds, aes(x=carat, y=price))+geom_point()+scale_y_log10()+stat_smooth()
这里就不按颜色、切工来分了,不然ggplot会按不同的分类变量分别做回归,图就很乱,如果我们需要这样做,我们可以使用分面,这个将在后面介绍。这里,aes所提供的参数,就通过ggplot提供,而不是提供给geom_point,因为ggplot里 的参数,相当于全局变量,geom_point()和stat_smooth()都知道x,y的映射,如果只提供给geom_point(),则相当于是 局部变量,geom_point知道这种映射,而stat_smooth不知道,当然你再给stat_smooth也提供x,y的映射,不过共用的映射, 还是提供给ggplot好。
在ggplot2中,每种几何类型都有对应的(默认)统计类型,反之亦然,两者不分家,下面对二者进行组合说明:
看一下几何函数geom_point和统计函数stat_identity的参数:
# 函数说明,非运行代码 geom_point(mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, ...) stat_identity(mapping = NULL, data = NULL, geom = "point", position = "identity", width = NULL, height = NULL, ...)
有4个参数是一样的:映射(mapping)、数据(data)、位置(position)和点点点(Dot-dot-dot: …)。H.W.特别强调了mapping和data参数的先后顺序在几何/统计类型设定函数和ggplot函数中的差别:ggplot函数先设定数据,再 设定映射;而几何/统计类型函数则相反,因为确定作图或统计之前一般都已经有数据,只需指定映射即可。如果不写参数名,它们的用法是这样的:
# 示例,非运行代码 ggplot(数据, 映射) geom_xxx(映射, 数据) stat_xxx(映射, 数据
"点点点"参数是R语言非常特殊的一个数据类型,用在函数的参数用表示任意参数,在这里表示传递给图层的任意参数如color, shape, alpha等。
前面我们一直用geom_point来做散点图,其实完全可以用stat_identity来做,得到的图形是完全相同的:
# 取ggplot2的diamonds数据集的一部分数据: set.seed(100) d.sub <- diamonds[sample(nrow(diamonds), 500),] g <- ggplot(d.sub, aes(x=carat, y=price)) theme_set(theme_bw()) g + stat_identity() + ggtitle("geom_identity()") g + geom_point() + ggtitle("geom_point()")
4.5坐标系统(coordinate)
坐标系统控制坐标轴,可以进行变换,例如XY轴翻转,笛卡尔坐标和极坐标转换,以满足我们的各种需求。
坐标轴翻转由coord_flip()实现:
ggplot(newDiamonds)+geom_bar(aes(x=cut, fill=cut))+coord_flip()
而转换成极坐标可以由coord_polar()实现:
ggplot(newDiamonds)+geom_bar(aes(x=factor(1), fill=cut))+coord_polar(theta="y")
这也是为什么之前介绍常用图形画法时没有提及饼图的原因,饼图实际上就是柱状图,只不过是使用极坐标而已,柱状图的高度,对应于饼图的弧度,饼图并不推荐,因为人类的眼睛比较弧度的能力比不上比较高度(柱状图)
还可以画靶心图:
ggplot(newDiamonds)+geom_bar(aes(x=factor(1), fill=cut))+coord_polar()
以及风玫瑰图(windrose):
ggplot(newDiamonds)+geom_bar(aes(x=clarity, fill=cut))+coord_polar() head(newDiamonds) ## carat cut color clarity depth table price x y z ## 49345 0.71 Very Good H SI1 62.5 60 2096 5.68 5.75 3.57 ## 50545 0.79 Premium H SI1 61.8 59 2275 5.97 5.91 3.67 ## 15434 1.03 Ideal F SI1 62.4 57 6178 6.48 6.44 4.03 ## 44792 0.50 Ideal E VS2 62.2 54 1624 5.08 5.11 3.17 ## 34614 0.27 Ideal E VS1 61.6 56 470 4.14 4.17 2.56 ## 27998 0.30 Premium E VS2 61.7 58 658 4.32 4.34 2.67
4.6图层(Layer)
4.6.1图层对象
geom_xxx和stat_xxx可以指定数据,映射、几何类型和统计类型,一般来说,有这些东西我们就可以作图了。但实际情况是这些函数不可以直接出图,因为它不是完整的ggplot对象:
g <- geom_point(mapping=aes(x=carat, y=price), data=d.sub) class(g) ## [1] "LayerInstance" "Layer" "ggproto" g ## mapping: x = carat, y = price ## geom_point: na.rm = FALSE ## stat_identity: na.rm = FALSE ## position_identity
图层只是存储类型为environment的R语言对象,它只有建立在ggplot结构的基础上才会成为图形,在这里哪怕是一个空的ggplot对象框架都很有用。这好比仓库里的帐篷,如果你找不到地方把它们支起来,这些东西顶多是一堆货物:
ggplot() + g class(ggplot() + g) ## [1] "gg" "ggplot"
前面说过多个图层的相加是有顺序的,图层和ggplot对象的加法也是有顺序的,如果把ggplot对象加到图层上就没有意义。这种规则同样适用于映射和ggplot的相加:
g + ggplot() ## NULL class(aes(x=carat, y=price) + ggplot(d.sub)) ## [1] "NULL" class(ggplot(d.sub) + aes(x=carat, y=price)) ## [1] "gg" "ggplot"
4.6.2图层的位置调整参数
当前版ggplot2常用的有5种:
- dodge:“避让”方式,即往旁边闪,如柱形图的并排方式就是这种。
- fill:填充方式, 先把数据归一化,再填充到绘图区的顶部。
- identity:原地不动,不调整位置
- jitter:随机抖一抖,让本来重叠的露出点头来
- stack:叠罗汉
前面有讲到用法,此处就不再贴图了!代码如下:
g <- ggplot(d.sub, aes(x=cut, y=price, fill=color)) g + geom_bar(stat="summary", fun.y="mean", position="stack") g + geom_bar(stat="summary", fun.y="mean", position="fill") g + geom_bar(stat="summary", fun.y="mean", position="dodge") g + geom_bar(stat="summary", fun.y="mean", position="jitter")
对于抖动效果,加在散点图上比较有效果:
g <- ggplot(d.sub, aes(x=cut, y=price, fill=color)) g + geom_point(position="identity") g + geom_point(position="jitter")
所以怎么调整还得看图形的需要。再看看x轴数据连续的图形:
g <- ggplot(d.sub, aes(x=price, fill=cut, color=cut)) g + stat_density(position="stack") g + stat_density(position="fill") g + stat_density(position="identity") g + stat_density(position="identity", fill="transparent")
4.6.3图层组合
图层的组合不是连续使用几个几何或统计类型函数那么简单。ggplot函数可以设置数据和映射,每个图层设置函数(geom_xxx和stat_xxx) 也都可以设置数据和映射,这虽然给组合图制作带来很大便利,但也可能产生一些混乱。如果不同图层设置的数据和映射不同,将会产生什么后果?得了解规则。
简单组合:
不同的图层使用同一套数据,只是几何类型或统计类型有差别。这是最简单也是最常用的,用ggplot函数设置好数据和映射,把几个图层加起来即可:
datax <- data.frame(x=1:10, y=rnorm(10)+1:10) g <- ggplot(datax, aes(x=x, y=y)) g + geom_point() + geom_line() g + geom_point() + geom_smooth(method="lm")
ggplot2的图层设置函数对映射的数据类型是有较严格要求的,比如geom_point和geom_line函数要求x映射的数据类型为数值向量,而 geom_bar函数要使用因子型数据。如果数据类型不符合映射要求就得做类型转换,在组合图形时还得注意图层的先后顺序:
datax <- data.frame(x=1:10, y=rnorm(10)+1:10) g <- ggplot(datax, aes(x=factor(x), y=y)) + xlab("x") g + geom_bar(stat="identity", fill="gray") + geom_line(aes(group=1), size=2) + geom_point(color="red") g + geom_bar(stat="identity", fill="gray") + geom_smooth(aes(group=1), method="lm", se=FALSE, size=2)
上面第一个图除了花哨一点外没有任何科学意义,如果放在论文中会被骂得狗学喷头:一套数据重复作图还都是一个意思,是不是脑子有病?但这里只是说明作图方 法。作图过程应先作柱形图,因为它要求x映射是因子型数据。x映射为因子的数据作散点图的调整步骤相对简单。如果先作散点图,把坐标轴从数值向量(连续 型)改为因子型相当麻烦。
不同映射的组合:
映射反映的是数据变量。多数情况下一个图形中使用的是同一个数据集,只是变量不同。通常情况下x,y轴至少有一个是相同的,可以用不同图层叠加不同的数据变量:
g <- ggplot(d.sub, aes(x=carat)) + ylab("depth (blue) / table (red)") g + geom_point(aes(y=depth), color="blue") + geom_point(aes(y=table), color="red")
但是为什么要这么做呢?预先处理一下数据再作图会更好,图标都已经帮你设好了:
library(reshape2) head(d.sub) ## 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 ## 25272 2.06 Premium I SI2 61.0 61 13912 8.18 8.10 5.02 ## 26093 1.56 Very Good G VVS1 59.7 59 15334 7.48 7.57 4.49 datax <- melt(d.sub, id.vars="carat", measure.vars=c("depth", "table")) head(datax) ## carat variable value ## 1 1.01 depth 62.1 ## 2 0.90 depth 62.4 ## 3 0.30 depth 61.6 ## 4 0.30 depth 62.0 ## 5 2.06 depth 61.0 ## 6 1.56 depth 59.7 tail(datax) ## carat variable value ## 995 0.91 table 56 ## 996 0.37 table 58 ## 997 1.27 table 58 ## 998 0.70 table 58 ## 999 0.71 table 62 #3 1000 1.24 table 56 ggplot(datax, aes(x=carat, y=value, color=variable)) + geom_point()
不同类型数据的组合:
如果在geom_xxx函数中改变数据会怎么样呢?不同类型的数据一般不会有完全相同的变量,否则就不是“不同类型”了,所以映射也会相应做修改。下面把 钻石数据diamonds和汽车数据mtcars这两个风牛马不相及的数据放在一起看看。(首先声明:下面的方法只是演示,图形没有任何科学意义。科学图 形应该能让观众直观地了解数据,而不是让明白者糊涂让糊涂者脑残。有不少人喜欢用双坐标作混合数据图,个人认为那是很愚昧的做法。)
diamonds数据我们在前面已经了解过了,先看看R datasets包里面的mtcars数据:
data(mtcars, package="datasets") str(mtcars)
## ‘data.frame‘: 32 obs. of 11 variables: ## $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ... ## $ cyl : num 6 6 4 6 8 6 8 4 4 6 ... ## $ disp: num 160 160 108 258 360 ... ## $ hp : num 110 110 93 110 175 105 245 62 95 123 ... ## $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ... ## $ wt : num 2.62 2.88 2.32 3.21 3.44 ... ## $ qsec: num 16.5 17 18.6 19.4 17 ... ## $ vs : num 0 0 1 1 0 1 0 1 1 1 ... ## $ am : num 1 1 1 0 0 0 0 0 0 0 ... ## $ gear: num 4 4 4 3 3 3 3 4 4 4 ... ## $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
head(mtcars, 4)
## 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
g <- ggplot(data=d.sub, aes(x=carat, y=price, color=cut)) layer <- geom_point(aes(x=carb, y=mpg), mtcars, color="black") (g <- g + layer)
图中数据点是正确的,但坐标轴标题却对不上号。看看ggplot对象的数据、映射和图层:
head(g$data, 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 g$mapping ## * x -> carat ## * y -> price ## * colour -> cut g$layers ## [[1]] ## mapping: x = carb, y = mpg ## geom_point: na.rm = FALSE ## stat_identity: na.rm = FALSE ## position_identity
数据和映射都还是ggplot原来设置的样子,layer图层设置的都没有存储到ggplot图形列表对象的data和mapping元素中,而是放在了图层中,但图层中设定的数据不知道跑哪里。
如果再增加一个图层,把坐标轴标题标清楚:
newlayer <- geom_point(aes(y=depth)) (g <- g + newlayer + xlab("carb(black) / carat") + ylab("mpg(black) / depth"))
newlayer重新指定了y映射,但没碰原来ggplot对象设置的x和color映射,从获得的图形来看y数据改变了,x和color还是原ggplot对象的设置。查看一下映射和图层:
g$mapping ## * x -> carat ## * y -> price ## * colour -> cut g$layers ## [[1]] ## mapping: x = carb, y = mpg ## geom_point: na.rm = FALSE ## stat_identity: na.rm = FALSE ## position_identity ## ## [[2]] ## mapping: y = depth ## geom_point: na.rm = FALSE ## stat_identity: na.rm = FALSE ## position_identity
可以这么理解:ggplot2图层作图时依次从ggplot对象和图层中获取数据/映射,如果两者映射有重叠,后者将替换前者,但只是在该图层中进行替换而不影响ggplot对象。
如果ggplot对象的映射比图层的映射多,而图层又使用了不同的数据,这是什么情况?看看:
g + geom_point(aes(x=carb, y=mpg), mtcars) ## Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : ## 参数值意味着不同的行数: 32, 0
由于图层继承了ggplot对象的color映射,但又找不到数据,所以没法作图。解决办法是把原有的映射用NULL取代,或者设为常量(非映射):
g + geom_point(aes(x=carb, y=mpg, color=NULL), mtcars) g + geom_point(aes(x=carb, y=mpg), mtcars, color="red")
photoshop流行的原因在于PS 3.0时引入图层的概念,ggplot的牛B之处在于使用+号来叠加图层,这堪称是泛型编程的典范。在前面散点图上,我们已经见识过,加上了一个回归线拟合的图层。有了图层的概念,使用ggplot画起图来,就更加得心应手。做为图层的一个很好的例子是蝙蝠侠logo,batman logo由6个函数组成,在下面的例子中,先画第一个函数,之后再加一个图层画第二个函数,不断重复这一过程,直到六个函数全部画好。
# batman logo是由六个函数构成的。 # 利用ggplot2将多个线画到同一幅图案里面。 require(ggplot2) f1 <- function(x) { y1 <- 3*sqrt(1-(x/7)^2) y2 <- -3*sqrt(1-(x/7)^2) y <- c(y1,y2) d <- data.frame(x=x,y=y) d <- d[d$y > -3*sqrt(33)/7,] return(d) } x1 <- c(seq(3, 7, 0.001), seq(-7, -3, 0.001)) d1 <- f1(x1) p1 <- ggplot(d1,aes(x,y)) + geom_point(color="red") print(p1)
x2 <- seq(-4,4, 0.001) y2 <- abs(x2/2)-(3*sqrt(33)-7)*x2^2/112-3 + sqrt(1-(abs(abs(x2)-2)-1)^2) #only work with ggplot2 <= 0.8.9 #p2 <- p1 + geom_point(aes(x=x2,y=y2), color="yellow") # in ggplot2 0.9.0, should be: d2 <- data.frame(x2=x2, y2=y2) p2 <- p1 + geom_point(data=d2, aes(x=x2,y=y2), color="yellow") print(p2)
x3 <- c(seq(0.75,1,0.001), seq(-1,-0.75,0.001)) y3 <- 9-8*abs(x3) #p3 <- p2+geom_point(aes(x=x3,y=y3), color="green") d3 <- data.frame(x3=x3, y3=y3) p3 <- p2+geom_point(data=d3, aes(x=x3,y=y3), color="green") print(p3)
x4 <- c(seq(0.5,0.75,0.001), seq(-0.75,-0.5,0.001)) y4 <- 3*abs(x4)+0.75 #p4 <- p3+geom_point(aes(x=x4,y=y4), color="steelblue") d4 <- data.frame(x4=x4,y4=y4) p4 <- p3+geom_point(data=d4, aes(x=x4,y=y4), color="steelblue") print(p4)
x5 <- seq(-0.5,0.5,0.001) y5 <- rep(2.25,length(x5)) #p5 <- p4+geom_point(aes(x=x5,y=y5)) d5 <- data.frame(x5=x5,y5=y5) p5 <- p4+geom_point(data=d5, aes(x=x5,y=y5)) print(p5)
x6 <- c(seq(-3,-1,0.001), seq(1,3,0.001)) y6 <- 6 * sqrt(10)/7 + (1.5 - 0.5 * abs(x6)) * sqrt(abs(abs(x6)-1)/(abs(x6)-1)) - 6 * sqrt(10) * sqrt(4-(abs(x6)-1)^2)/14 #p6 <- p5+geom_point(aes(x=x6,y=y6), colour="blue") d6 <- data.frame(x6=x6,y6=y6) p6 <- p5+geom_point(data=d6,aes(x=x6,y=y6), colour="blue") print(p6)
p <- p6+theme_bw() print(p)
4.7分面(Facet)
分面可以让我们按照某种给定的条件,对数据进行分组,然后分别画图。ggplot2的分面有两种方式,分别使用 facet_wrap 或 facet_grid 函数。
# 准备工作 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
theme_set(theme_bw()) g <- ggplot(data=d.sub, aes(x=carat, y=price))
4.7.1缠绕分面facet_wrap
facet_warp 即“缠绕分面”,对数据分类只能应用一个标准,不同组数据获得的小形按从左到右从上到下的“缠绕”顺序进行排列:
levels(d.sub$cut) ## [1] "Fair" "Good" "Very Good" "Premium" "Ideal" g + geom_point() + facet_wrap(~cut)
显然这是对数据进行分组后绘制得到的图形,这类图形对于比较不同数据的趋势非常有帮助。facet_wrap 的参数如下:
# 非运行代码 facet_wrap(facets, nrow = NULL, ncol = NULL, scales = "fixed", shrink = TRUE, as.table = TRUE, drop = TRUE)
facets:分面参数如 ~cut,表示用 cut 变量进行数据分类 nrow:绘制图形的行数 ncol:绘制图形的列数,一般nrow/ncol只设定一个即可 scales:坐标刻度的范围,可以设定四种类型。fixed 表示所有小图均使用统一坐标范围;free表示每个小图按照各自数据范围自由调整坐标刻度范围;free_x为自由调整x轴刻度范围;free_y为自由调整y轴刻度范围。 shrinks:也和坐标轴刻度有关,如果为TRUE(默认值)则按统计后的数据调整刻度范围,否则按统计前的数据设定坐标。 as.table:和小图排列顺序有关的选项。如果为TRUE(默认)则按表格方式排列,即最大值(指分组level值)排在表格最后即右下角,否则排在左上角。 drop:是否丢弃没有数据的分组,如果为TRUE(默认),则空数据组不绘图。
下面看看 scales 的设定效果:
g + geom_point() + facet_wrap(~cut, scales="free") + ggtitle(‘scales="free"‘) g + geom_point() + facet_wrap(~cut, scales="free_y") + ggtitle(‘scales="free_y"‘)
4.7.2网格分面facet_grid
格网分面可以应用多个标准对数据进行分组。还是先看看效果:
qplot(carat, price, data=diamonds, alpha=I(0.2)) + facet_grid(color~cut)
显然参数 color~cut 对数据的分组和小图排列有决定作用,波浪号前为小图分行标准,后面为分列标准。facet_grid 的完整用法为:
# 非运行代码 facet_grid(facets, margins = FALSE, scales = "fixed", space = "fixed", shrink = TRUE, labeller = "label_value", as.table = TRUE, drop = TRUE)
和facet_wrap比较,除不用设置ncol和nrow外(facets公式已经包含)外还有几个参数不同:
- margins
注意:这不是设定图形边界的参数。它是指用于分面的包含每个变量元素所有数据的数据组。
qplot(carat, price, data=diamonds, alpha=I(0.2)) + facet_grid(color~cut, margins=TRUE)
- space
这个参数要配合scales使用,如果为fixed(默认),所有小图的大小都一样,如果为free/free_x/free_y,小图的大小将按照坐标轴的跨度比例进行设置。
qplot(carat, price, data=diamonds, alpha=I(0.2)) + facet_grid(color~cut, space="free_x", scales="free_x")
- labeller
这是设定小图标签的,facet_grid的函数说明档讲得比较明白,参考之。或许会在后面介绍。
下面简单看看2个以上分组标准获得什么样的图:
qplot(carat, price, data=diamonds, alpha=I(0.2)) + facet_grid(color+clarity~cut)
在统计变换一节中,提到如果按切工分组作回归线,显然图会很乱,有了分面功能,我们可以分别作图。
ggplot(newDiamonds, aes(x=carat, y=price))+ geom_point(aes(colour=cut))+ scale_y_log10() + facet_wrap(~cut)+ stat_smooth()
4.8主题(Theme)
通过ggplot画图之后,我们可能还需要对图进行定制,像title, xlab, ylab这些高频需要用到的,自不用说,ggplot2提供了ggtitle(), xlab()和ylab()来实现。
例如:
ggplot(newDiamonds, aes(x=cut, y=price))+ geom_boxplot(aes(fill = color))+ labs(x="Cut",y="Price",title = "Price vs Cut")
但是这个远远满足不了需求,我们需要改变字体,字体大小,坐标轴,背景等各种元素,这需要通过theme()函数来完成。ggplot2提供一些已经写好的主题,比如theme_grey()为默认主题,我经常用的theme_bw()为白色背景的主题,还有theme_classic()主题,和R的基础画图函数较像。
4.8.1主题设置函数源代码
查看主题源代码:
> theme_bw function (base_size = 12, base_family = "") { theme_grey(base_size = base_size, base_family = base_family) %+replace% theme(axis.text = element_text(size = rel(0.8)), axis.ticks = element_line(colour = "black"), legend.key = element_rect(colour = "grey80"), panel.background = element_rect(fill = "white", colour = NA), panel.border = element_rect(fill = NA, colour = "grey50"), panel.grid.major = element_line(colour = "grey90", size = 0.2), panel.grid.minor = element_line(colour = "grey98", size = 0.5), strip.background = element_rect(fill = "grey80", colour = "grey50", size = 0.2)) } <environment: namespace:ggplot2>
就是一个具有两个参数的函数:base_size和base_family。其主题部分直接应用了另外一个函数:theme,它就是ggplot2的主题设置函数。这个theme函数的产生看起来非常简单:
# 函数说明,非运行代码 theme(..., complete = FALSE)
但是其参数却非常复杂。
4.8.2主题设置参数
前面讲到theme设置的参数内容非常丰富,可以设置很多的内容,如下所示:
参数 | 设置内容 | 继承自 |
line | 所有线属性 | |
rect | 所有矩形区域属性 | |
text | 所有文本相关属性 | |
title | 所有标题属性 | |
axis.title | 坐标轴标题 | text |
axis.title.x | x轴属性 | axis.title |
axis.title.y | y轴属性 | axis.title |
axis.text | 坐标轴刻度标签属性 | text |
axis.text.x | 属性和继承和前面类似,不再重复 | |
axis.text.y | ||
axis.ticks | 坐标轴刻度线 | line |
axis.ticks.x | ||
axis.ticks.y | ||
axis.ticks.length | 刻度线长度 | |
axis.ticks.margin | 刻度线和刻度标签之间的间距 | |
axis.line | 坐标轴线 | line |
axis.line.x | ||
axis.line.y | ||
legend.background | 图例背景 | rect |
legend.margin | 图例边界 | |
legend.key | 图例符号 | |
legend.key.size | 图例符号大小 | |
legend.key.height | 图例符号高度 | |
legend.key.width | 图例符号宽度 | |
legend.text | 图例文字标签 | |
legend.text.align | 图例文字标签对齐方式 | 0为左齐,1为右齐 |
legend.title | 图例标题 | text |
legend.title.align | 图例标题对齐方式 | |
legend.position | 图例位置 | left, right, bottom, top, 两数字向量 |
legend.direction | 图例排列方向 | "horizontal" or "vertical" |
legend.justification | 居中方式 | center或两数字向量 |
legend.box | 多图例的排列方式 | "horizontal" or "vertical" |
legend.box.just | 多图例居中方式 | |
panel.background | 绘图区背景 | rect |
panel.border | 绘图区边框 | rect |
panel.margin | 分面绘图区之间的边距 | |
panel.grid | 绘图区网格线 | line |
panel.grid.major | 主网格线 | |
panel.grid.minor | 次网格线 | |
panel.grid.major.x | ||
panel.grid.major.y | ||
panel.grid.minor.x | ||
panel.grid.minor.y | ||
plot.background | 整个图形的背景 | |
plot.title | 图形标题 | |
plot.margin | 图形边距 | top, right, bottom, left |
strip.background | 分面标签背景 | rect |
strip.text | 分面标签文本 | text |
strip.text.x | ||
strip.text.y |
所有元素都在theme函数内使用element_line,element_rect,element_text和element_blank函数设置,使用方法参考这几个函数的参数说明即可,这里不再一一举例说明。text, line, rect和title是最顶层的元素,理论上可以做全局设定,但当前版本ggplot2还没有实现,可以根据情况做一些调整:
x <- LETTERS[1:10]; y <- abs(rnorm(10)) (g <- qplot(x=x, y=y, color=x, fill=x, geom=c(‘line‘,‘point‘), group=1) + labs(title=‘The figure title.‘, xlab=‘Factor‘, ylab=‘Value‘) + theme(text=element_text(color=‘red‘, size=16), line=element_line(color=‘blue‘), rect=element_rect(fill=‘white‘))) g + theme(panel.background=element_rect(fill=‘transparent‘, color=‘gray‘), legend.key=element_rect(fill=‘transparent‘, color=‘transparent‘), axis.text=element_text(color=‘red‘))
4.8.3自定义主题
# 自定义主题 theme_zg <- function(..., bg=‘white‘){ require(grid) theme_classic(...) + theme(rect=element_rect(fill=bg), plot.margin=unit(rep(0.5,4), ‘lines‘), panel.background=element_rect(fill=‘transparent‘, color=‘black‘), panel.border=element_rect(fill=‘transparent‘, color=‘transparent‘), panel.grid=element_blank(), axis.title = element_text(color=‘black‘, vjust=0.1), axis.ticks.length = unit(-0.4,"lines"), axis.ticks = element_line(color=‘black‘), legend.title=element_blank(), legend.key=element_rect(fill=‘transparent‘, color=‘transparent‘)) } g <- qplot(x=x, y=y, color=x, fill=x, geom=c(‘line‘,‘point‘), group=1) + labs(title=‘The figure title.‘, xlab=‘Factor‘, ylab=‘Value‘) g + theme_zg() g + theme_zg(base_size=16, bg=‘gray90‘)
自定义的主题可以编入自己的R语言包中,方便调用。如果觉得你的主题很有代表性,那就发给ggplot2的作者,让他在下一版本中加到ggplot2发行版中。
4.8.4ggtheme包主题选用
别外ggthemes包提供了一些主题可供使用,包括:
theme_economist theme_economist_white theme_wsj theme_excel theme_few theme_foundation theme_igray theme_solarized theme_stata theme_tufte
# install.packages(‘ggthemes‘) require(ggthemes) g <- ggplot(newDiamonds, aes(x=cut, y=price))+ geom_boxplot(aes(fill = color))+ labs(x="Cut",y="Price",title = "Price vs Cut") g + theme_wsj()
g + theme_economist()
4.9统计变换之二维密度图
地理课上,我们经常会看到等高线。在ggplot2中,也有实现一个和等高线差不多的利器——二维密度图,在统计变换中有涉及stat_density2d()
点+等高线:
# The base plot head(faithful) ## eruptions waiting ## 1 3.600 79 ## 2 1.800 54 ## 3 3.333 74 ## 4 2.283 62 ## 5 4.533 85 ## 6 2.883 55 g <- ggplot(faithful, aes(x=eruptions, y=waiting)) g + geom_point() + stat_density2d()
等高线+色度等级:
# Contour lines, with "height" mapped to color g + stat_density2d(aes(colour=..level..))
映射到色度等级(将轮廓contour设为FALSE,几何对象设为光栅raster):
# Map density estimate to fill color g + stat_density2d(aes(fill=..density..), geom="raster", contour=FALSE)
例子:使用diamonds数据集的一个子集,如果使用全集,数据量太大,画出来散点就糊了,这种情况可以使用二维密度力来呈现。
ggplot(diamonds, aes(carat, price))+ stat_density2d(aes(fill = ..level..), geom="polygon")+ scale_fill_continuous(high=‘darkred‘,low=‘darkgreen‘)
4.10标尺scale设置
在图形美化阶段,我们可以通过修改标尺改善图形外观。标尺设置一般不会对数据产生影响,但坐标轴标尺除外。
4.10.1标尺设定函数
ggplot2修改标尺的函数有很多:
library(ggplot2) scalex <- ls("package:ggplot2", pattern="^scale.+") length(scalex) ## [1] 75 scalex ## [1] "scale_alpha" "scale_alpha_continuous" "scale_alpha_discrete" ## [4] "scale_alpha_identity" "scale_alpha_manual" "scale_color_brewer" ## [7] "scale_color_continuous" "scale_color_discrete" "scale_color_distiller" ## [10] "scale_color_gradient" "scale_color_gradient2" "scale_color_gradientn" ## [13] "scale_color_grey" "scale_color_hue" "scale_color_identity" ## [16] "scale_color_manual" "scale_colour_brewer" "scale_colour_continuous" ## [19] "scale_colour_date" "scale_colour_datetime" "scale_colour_discrete" ## [22] "scale_colour_distiller" "scale_colour_gradient" "scale_colour_gradient2" ## [25] "scale_colour_gradientn" "scale_colour_grey" "scale_colour_hue" ## [28] "scale_colour_identity" "scale_colour_manual" "scale_fill_brewer" ## [31] "scale_fill_continuous" "scale_fill_date" "scale_fill_datetime" ## [34] "scale_fill_discrete" "scale_fill_distiller" "scale_fill_gradient" ## [37] "scale_fill_gradient2" "scale_fill_gradientn" "scale_fill_grey" ## [40] "scale_fill_hue" "scale_fill_identity" "scale_fill_manual" ## [43] "scale_linetype" "scale_linetype_continuous" "scale_linetype_discrete" ## [46] "scale_linetype_identity" "scale_linetype_manual" "scale_radius" ## [49] "scale_shape" "scale_shape_continuous" "scale_shape_discrete" ## [52] "scale_shape_identity" "scale_shape_manual" "scale_size" ## [55] "scale_size_area" "scale_size_continuous" "scale_size_date" ## [58] "scale_size_datetime" "scale_size_discrete" "scale_size_identity" ## [61] "scale_size_manual" "scale_x_continuous" "scale_x_date" ## [64] "scale_x_datetime" "scale_x_discrete" "scale_x_log10" ## [67] "scale_x_reverse" "scale_x_sqrt" "scale_y_continuous" ## [70] "scale_y_date" "scale_y_datetime" "scale_y_discrete" ## [73] "scale_y_log10" "scale_y_reverse" "scale_y_sqrt"
提取函数名的第二个字段,对这些函数的作用进行分类:
scalex <- scalex[grep("([^_]+_){2}.+", scalex)] unique(gsub("(([^_]+_){2}).+","\\1***",scalex)) ## [1] "scale_alpha_***" "scale_color_***" "scale_colour_***" ## [4] "scale_fill_***" "scale_linetype_***" "scale_shape_***" ## [7] "scale_size_***" "scale_x_***" "scale_y_***"
可以看到标尺设置的内容有8种(颜色color/colour算一种):线条颜色color/colour、填充色fill、透明度alpha、线型linetype、形状shape、大小size_,x和y轴。标尺设置的内容都有对应的映射设置类型,但映射比标尺多了xmin, xmax, ymin, ymax, xend, yend,group和string等。虽然设置函数很多,但不管是函数用法还是函数名称上都是很有规律的:
# 线条颜色 scalexx <- scalex[grepl("scale_color.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "brewer" "continuous" "discrete" "distiller" "gradient" ## [6] "gradient2" "gradientn" "grey" "hue" "identity" ## [11] "manual" # 填充色 scalexx <- scalex[grepl("scale_fill.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "brewer" "continuous" "date" "datetime" "discrete" ## [6] "distiller" "gradient" "gradient2" "gradientn" "grey" ## [11] "hue" "identity" "manual" # 大小 scalexx <- scalex[grepl("scale_size.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "area" "continuous" "date" "datetime" "discrete" ## [6] "identity" "manual" # 透明度 scalexx <- scalex[grepl("scale_alpha.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "continuous" "discrete" "identity" "manual" # 线型 scalexx <- scalex[grepl("scale_linetype.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "continuous" "discrete" "identity" "manual" # 形状 scalexx <- scalex[grepl("scale_shape.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "continuous" "discrete" "identity" "manual" # x轴 scalexx <- scalex[grepl("scale_x.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "continuous" "date" "datetime" "discrete" "log10" ## [6] "reverse" "sqrt" # y轴 scalexx <- scalex[grepl("scale_y.+", scalex)] unique(gsub("(([^_]+_){2})(.+)","\\3",scalexx)) ## [1] "continuous" "date" "datetime" "discrete" "log10" ## [6] "reverse" "sqrt"
除坐标轴外,其它标尺都有四种基本设置函数:"continuous","discrete","identity"和"manual"。结合标尺的作用和设定方法两个标准,H.W把它们分为4种类型的标尺:位置、颜色、无变换和人工设置类型。颜色设置相关的函数较多,线条颜色和填充色设置的函数类型大致一样,而x轴和y轴设置的函数类型一样。由于标尺函数的命名和用法很有规律,下面仅介绍颜色和坐标轴设置函数的一些用法。
4.10.2颜色标尺设置
连续颜色标尺:
ggplot2提供了13个填充色设置的标尺函数(线条颜色11个):
ls("package:ggplot2", pattern="^scale_fill.+") ## [1] "scale_fill_brewer" "scale_fill_continuous" "scale_fill_date" ## [4] "scale_fill_datetime" "scale_fill_discrete" "scale_fill_distiller" ## [7] "scale_fill_gradient" "scale_fill_gradient2" "scale_fill_gradientn" ## [10] "scale_fill_grey" "scale_fill_hue" "scale_fill_identity" ## [13] "scale_fill_manual"
先看看“continuous”连续标尺的用法。对于数据为非因子型的填充色映射,ggplot2自动使用“continuous”类型颜色标尺表示连续颜色空间。如果要修改默认颜色就要使用scale_fill_continuous函数进行修改,这个函数最有用的参数是low和high,分别表示低端和高端 数据的颜色,中间颜色根据颜色空间space自动计算:
theme_set(theme_bw()) df <- expand.grid(1:30, 1:30) colnames(df) <- c(‘x‘,‘y‘) df$z <- rnorm(900) summary(df) ## x y z ## Min. : 1.0 Min. : 1.0 Min. :-2.80693 ## 1st Qu.: 8.0 1st Qu.: 8.0 1st Qu.:-0.59303 ## Median :15.5 Median :15.5 Median : 0.09599 ## Mean :15.5 Mean :15.5 Mean : 0.05384 ## 3rd Qu.:23.0 3rd Qu.:23.0 3rd Qu.: 0.70772 ## Max. :30.0 Max. :30.0 Max. : 2.61617 g <- ggplot(data=df, aes(x=x, y=y, fill=z)) g + geom_raster() + labs(title = "图一:默认情况") g + geom_raster() + scale_fill_continuous(low="darkgreen", high="orangered", space=‘rgb‘) + labs(title = "图二:修改最低和最高颜色")
颜色可以使用预设颜色名称,也可以使用十六进制表示。颜色空间可以是rgb或Lab,两者差别不是很大:
g + geom_raster() + scale_fill_continuous(low="#000099", high="#FF0000", space=‘rgb‘) + labs(title = "rgb") g + geom_raster() + scale_fill_continuous(low="#000099", high="#FF0000", space=‘Lab‘) + labs(title = "Lab")
连续填充色设置函数还有scale_fill_gradient,scale_fill_gradient2和 scale_fill_gradientn,其中scale_fill_gradient的用法和作用和scale_fill_continuous完全 相同(其实ggplot2早期版本连续颜色标尺默认使用scale_fill_gradient,没有scale_fill_continuous函数; 后者可能是H.W头脑清楚以后加进去的,相当于前者的别名)。scale_fill_gradient2增加了中间点和中间颜色的设置,效果相当不错:
g + geom_raster() + scale_fill_gradient2(low="darkgreen", high="red", mid="yellow") + labs(title = "scale_fill_gradient2中间颜色") g + geom_raster() + scale_fill_gradient2(low="darkgreen", high="red", mid="yellow", midpoint=1) + labs(title = "scale_fill_gradient2中间点")
而scale_fill_gradientn可以使用colours参数设置多个中间颜色,配合其它颜色参数函数使用也很不错:
g + geom_raster() + scale_fill_gradientn(colours=c("blue","green","yellow","red")) + labs(title = "scale_fill_gradientn指定颜色") g + geom_raster() + scale_fill_gradientn(colours=terrain.colors(100)) + labs(title = "scale_fill_gradientn调色板指定颜色数量")
离散(间断)型颜色标尺:
(1)scale_color_discrete或 scale_color_hue
如果数据是因子型的颜色映射,颜色标尺则是离散型的,修改标尺需要使用相应的离散型颜色标尺如scale_color_discrete或 scale_color_hue。这两个函数只是别名函数,早期版本只有scale_color_hue。它们通过设置色调范围(h)、饱和度(c)和亮度(l)获取颜色,不太容易掌握:
set.seed(100) dms <- diamonds[sample(nrow(diamonds),500),] g <- ggplot(data=dms, aes(x=carat, y=price, color=cut)) g + geom_point() + scale_color_discrete() + labs(title = "default") g + geom_point() + scale_color_discrete(h=c(150,350), c=100, l=60) + labs(title = "设置色调范围(h)、饱和度(c)和亮度(l)")
注意:因为映射是color,所以标尺设置也得相应用scale_color而不是scale_fill。
(2)scale_color_manual
scale_color_discrete或scale_color_hue设置颜色不是很直观,如果想要啥来啥,那就用manual类型函数:
library(ggplot2) set.seed(100) dms <- diamonds[sample(nrow(diamonds),500),] g <- ggplot(data=dms, aes(x=carat, y=price, color=cut)) g + geom_point() + scale_color_manual(values=c(‘blue‘,‘cyan‘, ‘yellow‘, ‘orange‘, ‘red‘)) g + geom_point() + scale_color_manual(values=rainbow(5))
(3)scale_color_grey
grey灰度标尺函数是设置离散型颜色的另外一类函数,用法很简单。
g + geom_point() + scale_color_grey(start = 0, end = 0.8)
(4)scale_fill_brewer
brewer类型函数则可以直接使用RColorBrewer包预定义的一些调色板,那些调色板最多能设置8-11种颜色不等,如果超过最大颜色数就不合适了。
library(ggplot2) library(RColorBrewer) x <- sample(LETTERS,13); y <- 1:13 qplot(x, y, fill= x) +geom_bar(stat = "density")+ scale_fill_brewer(palette="YlOrRd") x <- x[1:8]; y=y[1:8] qplot(x, y, fill= x) +geom_bar(stat = "density") + scale_fill_brewer(palette="YlOrRd")
identity标尺:
如果数据本身就是可以用作标尺的取值,那当然可以直接使用:
set.seed(2) (col <- sample(colors(),4)) ## [1] "deepskyblue1" "mediumblue" "indianred4" "darkslategray2" head(colors()) ## [1] "white" "aliceblue" "antiquewhite" ## [4] "antiquewhite1" "antiquewhite2" "antiquewhite3"
开始使用:
val <- abs(rnorm(4))*10 val ## [1] 15.8784533 11.3037567 0.8025176 1.3242028 qplot(x=col, y=val, fill= col) +geom_bar(stat = "density")+ scale_fill_identity() qplot(x=carat, y=price, data=dms, size=x) + scale_size_identity()
设置identity标尺后不再产生对应的图例。
4.10.3坐标轴标尺设置
ggplot2为x或y轴标尺的设置分别提供了7个函数:
ls("package:ggplot2", pattern="^scale_x.+") ## [1] "scale_x_continuous" "scale_x_date" "scale_x_datetime" ## [4] "scale_x_discrete" "scale_x_log10" "scale_x_reverse" ## [7] "scale_x_sqrt"
这些函数最基本的是continuous和discrete两个,通过设置它们的参数可以实现其它函数的效果。
breaks, labels, limits参数:
continuous和discrete坐标轴标尺设定函数中最常用的参数是breaks、labels和limits,分别用于设置刻度位置、刻度标签和坐标轴范围。先看看前两个参数:
g <- ggplot(data=dms, aes(x=carat, y=price)) + geom_point() bks <- pretty(range(dms$price), 10) bks ## [1] 0 2000 4000 6000 8000 10000 12000 14000 16000 18000 20000 g + scale_y_continuous(breaks=bks) bks <- c(0, 2000, 10000, 15500, 18000) bks ## [1] 0 2000 10000 15500 18000 bks/1000 ## [1] 0.0 2.0 10.0 15.5 18.0 g + scale_y_continuous("Price (*1000)", breaks=bks, labels=bks/1000)
如果xy轴都是非因子数据,limits的设置比较顺利,但另外一个坐标轴还不能自动调整,可能需要改进:
g + scale_x_continuous(limits=c(0.5,1.5)) g + scale_y_continuous(limits=c(500,1000))
trans参数:
连续数据的坐标轴可以设置trans参数,它应该是通过调用scales包的相应trans类型实现的,比如scales中有log10_trans,ggplot2中可以直接设置trans=‘log10‘,它其实就是scale_x_log10函数的效果:
g + scale_y_continuous(trans=‘log10‘) + ggtitle("scale_y_continuous(trans=‘log10‘)") g + scale_y_log10() + ggtitle("scale_y_log10()")
同样reverse_trans和sqrt_trans也等价于scale_x_reverse和scale_x_sqrt,它们分别对坐标轴反转和求平方根。scales包中还有其它一些转换函数,但在ggplot中没有对应的设置函数,如果数据合适,有些可以直接用:
g + scale_y_continuous(trans=‘reciprocal‘) + ggtitle("reciprocal_trans") g + scale_x_continuous(trans=‘log1p‘) + ggtitle("log1p_trans")
坐标轴标尺转换与数据映射:
如果你认为坐标轴标尺只是改变了坐标轴的外观那就错了,它还影响到用于建立映射的数据。下面我们分别用坐标轴标尺应用之前和之后的数据获得拟合直线:
g <- ggplot(data=dms, aes(x=carat, y=price)) + geom_point() lmx <- glm(price~carat, data=dms) gs1 <- geom_line(aes(y=lmx$fitted.values), size=3, color=‘red‘) gs2 <- geom_smooth(aes(group=1), method="lm", se=FALSE, size=1.5) g + gs1 + gs2 g + gs1 + gs2 + scale_x_log10()
第一个图没改变坐标轴标尺,所以两个拟合直线是完全重合的;而第二个图中两条先就差别很大,原来红色的直线变成了曲线,而geom_smooth获得的仍然是直线。改变坐标轴范围也是同样的效果:
g + gs1 + gs2 + scale_y_continuous(limits=c(1000,10000)) g + gs1 + gs2 + ylim(limits=c(1000,10000))
也就是说人工设置坐标轴标尺后改变了用于建立映射的数据,或作变换,或取子集(设置limits),这个过程发生在建立映射之前。如果想在ggplot2建立映射后改变坐标轴,应该用coord_xxx类型函数:
g + gs1 + gs2 + coord_cartesian(ylim=c(1000,10000)) g + gs1 + gs2 + coord_trans(x=‘log10‘)
前面用到了ylim函数,同样也有xlim,它们只是辅助函数,实质调用了坐标轴标尺设置函数。柱形图不能用scale类函数调整坐标轴刻度范围,主要原因是:柱形图即直方图,不能改变y轴起始为非0;另外scale设置导致取数据子集,随之直方图 坐标轴范围改变,这些改变多数情况下会和scale的设置冲突。用scale设置柱形图保险不出错的情况是设置的范围比数据范围要大,但没有什么实际意义。
4.10.4标尺函数的通用参数
除前面提到的breaks和labels外,常用的还有name,用于改变所设scale的名称,具体表现是改变坐标轴标题或图例标题。放在第一个参数的位置可以不用写参数名称。
qplot(x=carat, y=price, color=cut, data=dms) + scale_color_hue(‘Diamond Cut‘) qplot(x=carat, y=price, color=cut, data=dms) + scale_y_continuous(‘Diamond Cut‘)
4.10.5SessionInfo
会话信息:
sessionInfo() ## R version 3.3.1 (2016-06-21) ## Platform: x86_64-w64-mingw32/x64 (64-bit) ## Running under: Windows >= 8 x64 (build 9200) ## ## locale: ## [1] LC_COLLATE=Chinese (Simplified)_China.936 LC_CTYPE=Chinese (Simplified)_China.936 ## [3] LC_MONETARY=Chinese (Simplified)_China.936 LC_NUMERIC=C ## [5] LC_TIME=Chinese (Simplified)_China.936 ## ## attached base packages: ## [1] stats graphics grDevices utils datasets methods base ## ## other attached packages: ## [1] RColorBrewer_1.1-2 ggplot2_2.1.0 praise_1.0.0 ## ## loaded via a namespace (and not attached): ## [1] labeling_0.3 colorspace_1.2-6 scales_0.4.0 plyr_1.8.4 rsconnect_0.4.3 ## [6] tools_3.3.1 gtable_0.2.0 Rcpp_0.12.5 grid_3.3.1 digest_0.6.9 ## [11] munsell_0.4.3
参考链接:
R数据可视化之ggplot2 (一):http://www.ppvke.com/Blog/archives/30457
R数据可视化之ggplot2 (二):http://www.ppvke.com/Blog/archives/30489
R数据可视化之ggplot2 (三):http://www.ppvke.com/Blog/archives/30538
R数据可视化之ggplot2 (四):http://www.ppvke.com/Blog/archives/30613
R数据可视化之ggplot2 (五):http://www.ppvke.com/Blog/archives/30681
R数据可视化之ggplot2 (六):http://www.ppvke.com/Blog/archives/30717
R数据可视化之ggplot2 (七): http://www.ppvke.com/Blog/archives/30816
ggplot2:数据分析与图形艺术:https://book.douban.com/subject/24527091/
利用ggplot2画出各种漂亮图片详细教程:http://www.plob.org/article/7264.html
ggplot2 2.1.0文档:http://docs.ggplot2.org/current/
二维密度图:http://www.plob.org/article/9138.html
标尺:http://blog.csdn.net/u014801157/article/details/24372521