ggplot2 2.0新stat_function:设定给定美学的默认比例

时间:2016-01-08 15:43:28

标签: r plot ggplot2 ggproto

我尝试在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_默认执行 ...

enter image description here

所以我猜问题是: 如何阻止ggplot在此处设置离散比例,并在理想情况下在我的新stat_函数的调用中设置默认比例。

2 个答案:

答案 0 :(得分:2)

显然,在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()

按预期生产:

The result of stat_topo

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

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

答案 1 :(得分:1)

好吧,睡觉了,并有了一个想法,我认为这可能会做你想要的。在stat_topo图层功能而不是ggproto中,我返回了一个列表,将其作为第一个元素,然后通过调用ggproto将另一个scale_fill_continuous()添加到该列表中。< / p>

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()

产生与上面相同的图片。