所有的ggplot2对象都建立自"ggproto"这套面向对象编程系统,因此想要创建出自己的一套图层,而不是简单的对已有图层进行累加,那么就需要学习"ggproto"。

创建新的stat

最简单的stat

我们会从一个最简单的stat开始: 根据已有的一组点,用一个凸壳(convex hull)包围他。

第一步,我们创建一个继承自Stat的"ggproto"对象

StatChull <- ggproto("StatChull", Stat,
                     compute_group = function(data, scales){
                       data[chull(data$x, data$y), , drop=FALSE]
                     },
                     required_aes = c("x","y")
)

在"ggproto"函数中,前两个是固定项,分别是类名和继承的"ggproto"类。而后续内容则是和你继承的类相关,例如compute_group()方法负责计算,required_aes则列出哪些美学属性(aesthetics)必须要存在,这两个都继承自Stat,可以用?Stat查看更多信息。。

第二步,我们开始写一个图层。由于历史设计原因,Hadley将其称作stat_()geom_()。但实际上,Hadley认为layer_()可能更准确些,毕竟每一个图层都或多或少的有"stat"和"geom"。

所有的图层都遵循相同的格式,即你在function中声明默认参数,然后调用layer()函数,将...传递给params参数。在...的参数既可以是"geom"的参数(如果你要做一个stat封装),或者是"stat"的参数(如果你要做geom的封装),或者是将要设置的美学属性. layer()会小心的将不同的参数分开并确保它们存储在正确的位置:

stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
                       position = "identity", na.rm = TRUE, show.legend = NA,
                       inherit.aes = TRUE, ...){
  layer(
    stat = StatChull, data = data, mapping = mapping, geom = geom,
    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
    params = list(na.rm = na.rm, ...)
    
  )
}

(, 在写R包的时候要注意用ggplot2::layer()或在命名空间中导入layer(), 否则会因找到函数而报错)

当我们写好了图层函数后,我们就可以尝试这个新的"stat"了

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  stat_chull(fill = NA, colour= "black")





go proto 结合grpc_html


simple-stat


(后续我们会学习如何通过设置"geom"的默认值,来避免声明fill=NA)

一旦我们构建了这种基本的对象,ggplot2将会给我们带来极大的自由。举个例子,ggplot2自动保留每组中不变的美学属性,也就是说你可以分组绘制一个凸壳:

ggplot(mpg, aes(displ, hwy, colour = drv)) + 
  geom_point() + 
  stat_chull(fill = NA)



go proto 结合grpc_封装_02


add group chull


我们还可以覆盖默认的图层,来以不同的形式展现凸壳:

ggplot(mpg, aes(displ, hwy)) +
  stat_chull(geom = "point", size = 4, colour = "red") +
  geom_point()



go proto 结合grpc_图层_03


different chull