@K1999
2016-07-05T05:28:38.000000Z
字数 7764
阅读 11862
R
数据可视化
ggplot2修改标尺的函数有一大堆:
> library(ggplot2)
> scalex <- ls("package:ggplot2", pattern = "^scale.+")
> length(scalex)
[1] 75
提取函数名的第二个字段,对这些函数的作用进行分类:
> 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算一种):线条颜色、填充色、透明度、线型、形状、大小,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" "gradient2"
[7] "gradientn" "grey" "hue" "identity" "manual"
### 填充色
> scalexx <- scalex[grepl("scale_fill.+", scalex)]
> unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
[1] "brewer" "continuous" "date" "datetime" "discrete" "distiller"
[7] "gradient" "gradient2" "gradientn" "grey" "hue" "identity"
[13] "manual"
### 大小
> scalexx <- scalex[grepl("scale_size.+", scalex)]
> unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
[1] "area" "continuous" "date" "datetime" "discrete" "identity"
[7] "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" "reverse"
[7] "sqrt"
### y轴
> scalexx <- scalex[grepl("scale_y.+", scalex)]
> unique(gsub("(([^_]+_){2})(.+)", "\\3", scalexx))
[1] "continuous" "date" "datetime" "discrete" "log10" "reverse"
[7] "sqrt"
除坐标轴外,其它标尺都有四种基本设置函数: "continuous","discrete","identity"和"manual"。结合标尺的作用和设定方法两个标准,H.W把它们分为4种类型的标尺:位置、颜色、无变换和人工设置类型(说实话,他的分类思维有点乱)。颜色设置相关的函数较多,线条颜色和填充色设置的函数类型一样,而x轴和y轴设置的函数类型也一样。
由于标尺函数的命名和用法很有规律,下面仅介绍颜色和坐标轴设置函数的一些用法。
当前版本的ggplot2提供了13个填充色设置的标尺函数(线条颜色也一样):
> 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)
p <- ggplot(data = df, aes(x = x, y = y, fill = z))
p + geom_raster()
p + geom_raster() + scale_fill_continuous(low = "darkgreen", high = "orangered", space = "rgb")
颜色可以使用预设颜色名称,也可以使用十六进制表示。颜色空间可以是rgb或Lab,两者差别还比较大(rgb已经弃用):
p + geom_raster() + scale_fill_continuous(low = "#000099", high = "#FF0000", space = "rgb")
p + geom_raster() + scale_fill_continuous(low = "#000099", high = "#FF0000", space = "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增加了中间点和中间颜色的设置,效果相当不错:
p + geom_raster() + scale_fill_gradient2(low = "darkgreen", high = "red", mid = "yellow")
p + geom_raster() + scale_fill_gradient2(low = "darkgreen", high = "red", mid = "yellow", midpoint = 1)
而scale_fill_gradientn可以使用colours参数设置多个中间颜色,配合其它颜色参数函数使用也很不错:
p + geom_raster() + scale_fill_gradientn(colours = c("blue", "green", "yellow", "red"))
p + geom_raster() + scale_fill_gradientn(colours = terrain.colors(100))
注意参数名称为colours,不是colors,米国人民可能不习惯,不过问题不大。
如果数据是因子型的颜色映射,颜色标尺则是离散型的,修改标尺需要使用相应的离散型颜色标尺如scale_color_discrete或scale_color_hue。这两个函数只是别名函数,早期版本只有scale_color_hue。它们通过设置色调范围(h)、饱和度(c)和亮 度(l)获取颜色,不太容易掌握:
set.seed(100)
dt <- diamonds[sample(nrow(diamonds), 500), ]
p <- ggplot(data = dt, aes(x = carat, y = price, color = cut))
p + geom_point() + scale_color_discrete()
p + geom_point() + scale_color_discrete(h = c(150, 350), c = 100, l = 60)
注意:因为映射是color,所以标尺设置也得相应用scale_color而不是scale_fill。
scale_color_discrete或scale_color_hue设置颜色不是很直观,如果想要啥来啥,那就用manual类型函数:
p + geom_point() + scale_color_manual(values = c("blue", "cyan", "yellow", "orange", "red"))
p + geom_point() + scale_color_manual(values = rainbow(5))
grey灰度标尺函数是设置离散型颜色的另外一类函数,用法很简单。
p + geom_point() + scale_color_grey(start = 0, end = 0.8)
brewer类型函数则可以直接使用RColorBrewer包预定义的一些调色板,那些调色板最多能设置8-11种颜色不等,如果超过最大颜色数就不合适了。
x <- sample(LETTERS, 13)
y <- 1:13 qplot(x = x, y = y, fill = x, geom = "bar") + scale_fill_brewer(palette = "YlOrRd")
x <- x[1:8] y = y[1:8] qplot(x = x, y = y, fill = x, geom = "bar") + scale_fill_brewer(palette = "YlOrRd")
与其去记那些调色板名称,还不如用manual可以设置自己需要的颜色(可参考本博客的文章《R语言进阶之一:颜色设置》)。
查看scale_fill_gradientn等函数的说明发现很多用于连续颜色设置的函数都有palette参数选项,似乎连续型和离散型颜色在函数上没有严格区别,但实际使用时会出错,或许这些功能只是H.W做的TODO list。
如果数据本身就是可以用作标尺的取值,那当然可以直接使用:
> set.seed(2)
> (col <- sample(colors(), 4))
"deepskyblue1" "mediumblue" "indianred4" "darkslategray2"
val <- abs(rnorm(4)) * 10
qplot(x = col, y = val, fill = col, geom = "bar") + scale_fill_identity()
qplot(x = carat, y = price, data = dt, size = x) + scale_size_identity()
设置identity标尺后不再产生对应的图例。
ggplot2为x或y轴标尺的设置分别提供了7个函数:
> ls("package:ggplot2", pattern = "^scale_x.+")
"scale_x_continuous" "scale_x_date" "scale_x_datetime" "scale_x_discrete" "scale_x_log10" "scale_x_reverse" "scale_x_sqrt"
这些函数最基本的是continuous和discrete两个,通过设置它们的参数可以实现其它函数的效果。
continuous和discrete坐标轴标尺设定函数中最常用的参数是breaks、labels和limits,分别用于设置刻度位置、刻度标签和坐标轴范围。先看看前两个参数:
p <- ggplot(data = dt, aes(x = carat, y = price)) + geom_point()
bks <- pretty(range(dt$price), 10)
p + scale_y_continuous(breaks = bks)
bks <- c(0, 2000, 10000, 15500, 18000)
p + scale_y_continuous("Price (*1000)", breaks = bks, labels = bks/1000)
如果xy轴都是非因子数据,limits的设置比较顺利,但另外一个坐标轴还不能自动调整,可能需要改进:
p + scale_x_continuous(limits = c(0.5, 1.5))
p + scale_y_continuous(limits = c(500, 1000))
用limits参数设置因子型数据轴还有意外的效果:既能选择要显示的数据子集,还能调整它们在图形上的显示顺序:
qplot(x = x, y = y, geom = "bar") + scale_x_discrete(limits = c("W", "D", "F"))
3.2 trans参数
连续数据的坐标轴可以设置trans参数,它应该是通过调用scales包的相应trans类型实现的,比如scales中有log10_trans,ggplot2中可以直接设置trans='log10',它其实就是scale_x_log10函数的效果:
p + scale_y_continuous(trans = "log10") + ggtitle("scale_y_continuous(trans='log10')")
p + scale_y_log10() + ggtitle("scale_y_log10()")
同样reverse_trans和sqrt_trans也等价于scale_x_reverse和scale_x_sqrt,它们分别对坐标轴反转和求平方根。日期相关的转换函数scale_x_date和scale_x_datetime我没用过,就不说来。scales包中还有其它一些转换函数,但在 ggplot中没有对应的设置函数,如果数据合适,有些可以直接用:
p + scale_y_continuous(trans = "reciprocal") + ggtitle("reciprocal_trans")
p + scale_x_continuous(trans = "log1p") + ggtitle("log1p_trans")
如果你认为坐标轴标尺只是改变了坐标轴的外观那就错了,它还影响到用于建立映射的数据。下面我们分别用坐标轴标尺应用之前和之后的数据获得拟合直线:
lmx <- lm(dt$price ~ dt$carat)
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)
p + gs1 + gs2 p + gs1 + gs2 + scale_x_log10()
第一个图没改变坐标轴标尺,所以两个拟合直线是完全重合的;而第二个图中两条先就差别很大,原来红色的直线变成了曲线,而geom_smooth获得的仍然是直线。改变坐标轴范围也是同样的效果:
p + gs1 + gs2 + scale_y_continuous(limits = c(1000, 10000))
p + gs1 + gs2 + ylim(limits = c(1000, 10000))
也就是说人工设置坐标轴标尺后改变了用于建立映射的数据,或作变换,或取子集(设置limits),这个过程发生在建立映射之前。如果想在ggplot2建立映射后改变坐标轴,应该用coord_xxx类型函数:
p + gs1 + gs2 + coord_cartesian(ylim = c(1000, 10000))
p + gs1 + gs2 + coord_trans(xtrans = "log10")
前面用到了ylim函数,同样也有xlim,它们只是辅助函数,实质调用了坐标轴标尺设置函数。在映射一文我们还提到柱形图不能用scale类函数调整坐标轴刻度范围,主要原因是:柱形图即直方图,不能改变y轴起始为非0;另外scale设置导致取数据子集,随之直方图坐标轴范围改变,这些改变多数情况下会和scale的设置冲突。用scale设置柱形图保险不出错的情况是设置的范围比数据范围要大,但没有什么实际意义:
qplot(x = x, y = y, geom = "bar") qplot(x = x, y = y, geom = "bar") + ylim(limits = c(-10, 10))
除前面提到的breaks和labels外,常用的还有name,用于改变所设scale的名称,具体表现是改变坐标轴标题或图例标题。放在第一个参数的位置可以不用写参数名称。
qplot(x = carat, y = price, color = cut, data = dt) + scale_color_hue("Diamond Cut")
qplot(x = carat, y = price, color = cut, data = dt) + scale_y_continuous("Diamond Cut")