Writing ggplot2 extensions
New themes
新的themes 是最简单的扩展套件,基本上就是ggplot2 的theme的参数叠加,需要注意的是参数: complete = TRUE。
print(theme_grey):从0开始构建新的theme(所需参数非常多)。
print(theme_bw):以theme_grey 为基础,通过%+replace%替换theme_grey 中的一些参数,形成新的主题。
function (base_size = 11, base_family = "", base_line_size = base_size/22, base_rect_size = base_size/22)
{
theme_grey(base_size = base_size, base_family = base_family, base_line_size = base_line_size, base_rect_size = base_rect_size) %+replace%
theme(panel.background = element_rect(fill = "white",
colour = NA), panel.border = element_rect(fill = NA,
colour = "grey20"), panel.grid = element_line(colour = "grey92"),
panel.grid.minor = element_line(size = rel(0.5)),
strip.background = element_rect(fill = "grey85",
colour = "grey20"), legend.key = element_rect(fill = "white",
colour = NA), complete = TRUE)
}
print(theme_minimal):以theme_bw 为基础,修改一些关键点生成。
ggplot2-ggproto
ggproto 是一个基于原型的OO( object-oriented)系统,该系统灵感源于proto包。它模糊了类和实例(classes and instances)之间的界限,干净利落地支持跨包继承(Inherits),使之具有更快的性能。所有ggplot2对象都是使用ggproto 系统构建的,它维护了ggplot2 所需的proto features。换句话说,如果需要创建新的统计Stat、Geom、Position、Scale或者主题系统,就需要了解ggproto 这个OO system。
Person <- ggproto("Person", NULL,
first = "",
last = "",
birthdate = NA,
full_name = function(self) {
paste(self$first, self$last)
},
age = function(self) {
days_old <- Sys.Date() - self$birthdate
floor(as.integer(days_old) / 365.25)
},
description = function(self) {
paste(self$full_name(), "is", self$age(), "old")
}
)
在这个ggproto 系统中,"Person"是该ggproto对象的class name,NULL 表示没有父对象(从0开始创建),接着是一系列参数和function。参数self 调用。
Me <- ggproto(NULL, Person,
first = "Thomas Lin",
last = "Pedersen",
birthdate = as.Date("1985/10/12")
)
此时,ggproto对象Me继承自Person 对象,Me 里面的参数可以调用Person 对象的function。
Me$description()
# "Thomas Lin Pedersen is 34 old"
Me$full_name()
#"Thomas Lin Pedersen"
Me$birthdate
"1985-10-12"
延伸阅读,ggproto_parent() function。
ggplot2 中的ggproto 系统是stateless的,换句话说,ggproto类别对象建立后就是稳定不变的,它们类似于量产的零件,我们在ggplot2 基础上进行构建时,只需要调用不同的零件就行了。
例如,在创建GeomErrorbar这个系统时,调用或者继承了GeomLinerange中的setup_params。
GeomErrorbar <- ggproto(
# ...
setup_params = function(data, params) {
GeomLinerange$setup_params(data, params)
}
# ...
}
一般来说,如果需要创建一个新的ggplot2的统计变换(stat),只需要创建一个ggproto,并申明它继承(Inherits)于Stat就可以了,如ggproto("StatChull", Stat...)。创建新的geom也一样:ggproto("GeomSimplePoint", Geom...)。
创建新的stat
Stat 主要封装了compute_layer(), compute_panel(), and compute_group()等一连串的call 。一般来说,compute_layer() 通过compute_panel() 中的panel 分割纵列,而compute_panel() 通过compute_group() 中的group 分割数据纵列,最终将计算结果重新组装。
setup_params() 接受构建layer data时规定的参数,返回的是一个参数名与compute_中的参数名相同的参数 list,用于设定需要计算的数据和参数信息。当setup_params() 设定后,setup_data() 会运行一次,用于接受修改好的layer data,返回的是一个layer data。
StatChull <- ggproto("StatChull", Stat,
required_aes = c("x", "y"),
compute_group = function(data, scales) {
data[chull(data$x, data$y), , drop = FALSE]
}
)
上面的代码创建了一个简单的stat,前两个参数是它的名字和来源(继承自什么,Stat—也是一个ggproto系统),第三个是需要的美学参数(需要做统计变换的列),第四个是统计变换。data就是data frame, scales 是包含x,y的scales。chull(){grDevices} 函数返回位于凸壳位置的点的列索引,索引按顺时针方向排列;drop将数据降低一个维度(data.frame — list)。
<setup_params() 接受构建layer data时规定的参数,返回的是一个参数名与compute_中的参数名相同的参数 list。
setup_data() 接受修改好的layer data,返回的是一个layer data。
layer可以用list包起来,一次可以添加多个layer>