【问题标题】:ggplot2 2.0 new stat_ function: setting default scale for given aestheticsggplot2 2.0 新的 stat_ 功能:为给定的美学设置默认比例
【发布时间】:2016-01-08 15:43:27
【问题描述】:

我尝试在 R 中使用 ggplot2 的新功能,它允许创建我们自己的 stat_ 函数。我正在创建一个简单的方法来计算和绘制二维数组上排列的点之间的插值表面。

我想创建一个需要 xyval 美学的 stat_topo(),绘制一个简单的 geom_raster 的插值 val 映射到 fill

library(ggplot2)
library(dplyr)
library(akima)

cpt_grp <- function(data, scales) {
  #interpolate data in 2D
  itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T)
  out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>%
    mutate(fill=as.vector(itrp$z))
  # str(out)
  return(out)
}

StatTopo <- ggproto("StatTopo", Stat,
                    compute_group = cpt_grp,
                    required_aes = c("x","y","val")
)
stat_topo <- function(mapping = NULL, data = NULL, geom = "raster",
                       position = "identity", na.rm = FALSE, show.legend = NA, 
                       inherit.aes = TRUE, ...) {
  layer(
    stat = StatTopo, data = data, mapping = mapping, geom = geom, 
    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
    params = list(na.rm = na.rm, ...)
  )
}

set.seed(1)
nchan <- 30
d <- data.frame(val = rnorm(nchan), # some random values to be mapped to fill color
         x = 1:nchan*cos(1:nchan), # the x and y position of the points to interpolate
         y = 1:nchan*sin(1:nchan))
plot(d$x,d$y)

ggplot(d,aes(x=x,y=y,val=val)) +
  stat_topo() +
  geom_point()

当我运行它时,我收到以下错误:

Error: numerical color values must be >= 0, found -1

我知道这是因为不知何故 fill 美学的规模被设置为离散的。

如果我输入这个:

ggplot(d,aes(x=x,y=y,val=val)) +
  stat_topo() +
  scale_fill_continuous() +
  geom_point()

我得到了我想要的:具有连续色阶的预期光栅,我希望 stat_ 默认执行 ...

所以我想问题是: 如何防止 ggplot 在此处设置离散比例,最好在调用我的新 stat_ 函数时设置默认比例。

【问题讨论】:

  • 我觉得你需要有一个配对的geom 来配合你的统计数据来获得你想要的默认值。

标签: r plot ggplot2 ggproto


【解决方案1】:

显然,当在 stat_ 函数中创建新变量时,需要将其与将要映射到的美学显式关联到 ggproto 定义中的参数 default_aes = aes(fill = ..fill..)

这告诉 ggplot 它是一种经过计算的美学,它会根据数据类型选择一个比例。

所以这里我们需要定义stat_如下:

cpt_grp <- function(data, scales) {
  # interpolate data in 2D
  itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T)
  out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>%
    mutate(fill=as.vector(itrp$z))
  # str(out)
  return(out)
}

StatTopo <- ggproto("StatTopo", Stat,
                    compute_group = cpt_grp,
                    required_aes = c("x","y","val"),
                    default_aes = aes(fill = ..fill..)
)

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

然后是下面的代码:

set.seed(1)
nchan <- 30
d <- data.frame(val = rnorm(nchan),
                x = 1:nchan*cos(1:nchan),
                y = 1:nchan*sin(1:nchan))
ggplot(d,aes(x=x,y=y,val=val)) +
  stat_topo() +
  geom_point()

按预期生产:

无需手动指定scale_,但可以像往常一样轻松调整比例,例如scale_fill_gradient2(low = 'blue',mid='white',high='red')

我在这里得到了这个答案:https://github.com/hadley/ggplot2/issues/1481

【讨论】:

    【解决方案2】:

    好的,睡在上面,有了一个想法,我认为这可能会如你所愿。在您的stat_topo 层函数而不是ggproto 中,我返回了一个列表,其中它作为第一个元素,然后通过调用scale_fill_continuous() 将另一个ggproto 添加到该列表中。

    library(ggplot2)
    library(dplyr)
    library(akima)
    
    cpt_grp <- function(data, scales) {
      #interpolate data in 2D
      itrp <- akima::interp(data$x,data$y,data$val,linear=F,extrap=T)
      out <- expand.grid(x=itrp$x, y=itrp$y,KEEP.OUT.ATTRS = F)%>%
        mutate(fill=as.vector(itrp$z))
      return(out)
    }
    StatTopo <- ggproto("StatTopo", Stat,
                        compute_group = cpt_grp,
                        required_aes = c("x","y","val")
    )
    stat_topo <- function(mapping = NULL, data = NULL, geom = "raster",
                          position = "identity", na.rm = FALSE, show.legend = NA, 
                          inherit.aes = TRUE, ...) {
      list(
        layer(
          stat = StatTopo, data = data, mapping = mapping, geom = geom, 
          position = position, show.legend = show.legend, inherit.aes = inherit.aes,
          params = list(na.rm = na.rm )
        ),
        scale_fill_continuous()
      )
    }
    set.seed(1)
    nchan <- 30
    d <- data.frame(val = rnorm(nchan), # some random values to be mapped to fill color
                    x = 1:nchan*cos(1:nchan), # the x and y position of interp points
                    y = 1:nchan*sin(1:nchan))
     ggplot(d,aes(x=x,y=y,val=val)) +
       stat_topo() +
       geom_point()
    

    产生与上面相同的图片。

    【讨论】:

    • 太好了,谢谢!关键是在 stat_topo 中创建列表。我之前尝试添加它们,但它不想添加。
    • 这里的值映射到fill 美学的方式似乎有些可疑。我在 ggplot github 上提交了一个问题。
    猜你喜欢
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 2014-08-13
    • 1970-01-01
    • 2015-02-13
    相关资源
    最近更新 更多