小伙伴提出了上面的问题,点不能够打到violin里面去,即使加了aes(group=color)强行分组也不行。这个照理第一感觉都会觉得可以,但试一下都会发现不行。

library(ggplot2)
d = subset(diamonds, color %in% c("D", "E"))
ggplot(d, aes(cut, carat, fill=color, color=color)) + 
    geom_violin(alpha=.3) + geom_jitter(width=.05, alpha=.5)

然后我就看到大家各种猜,所谓talk is cheap show me the code,我看一下代码:

GeomPoint <- ggproto("GeomPoint", Geom,
  required_aes = c("x", "y"),
  non_missing_aes = c("size", "shape", "colour"),
  default_aes = aes(
    shape = 19, colour = "black", size = 1.5, fill = NA,
    alpha = NA, stroke = 0.5
  ),

  draw_panel = function(data, panel_params, coord, na.rm = FALSE) {
    coords <- coord$transform(data, panel_params)
    ggname("geom_point",
      pointsGrob(
        coords$x, coords$y,
        pch = coords$shape,
        gp = gpar(
          col = alpha(coords$colour, coords$alpha),
          fill = alpha(coords$fill, coords$alpha),
          # Stroke is added around the outside of the point
          fontsize = coords$size * .pt + coords$stroke * .stroke / 2,
          lwd = coords$stroke * .stroke / 2
        )
      )
    )
  },

  draw_key = draw_key_point
)

这显而易见,必须是不行了。因为GeomPoint并没有计算分组。你可能会觉得这显而易见的需求,怎么会不支持!写软件要考虑的因素很多的。

首先打点你为什么能够分组?必须是离散型的变量,你设想一下,连续型变量你能够分组一些点画左边,一些点画右边吗?那x轴怎么搞?所以必须是离散型变量,像上面需求的例子这种。而如果你实现了上面这种需求,那么你怎么能阻止用户不把它应用于连续型变量,所以这种功能不能实现!不是说它不可能实现,我都可以改GeomPoint改到它可以有这个功能,但不能这么做!教育用户、避免用户做错误的事情是更为重要的事情。你应该理解为什么hadley不实现了,而我也不能去实现它。

难道就不能分组了吗?显然可以的,请记住分面即分组!你可以通过分面来实现。所以不是不行,而是有一套哲学在里面,以一种不会出错的机制来实现。它可能不是所有人想要的,但它是不允许用户出错的方法。

ggplot(d, aes(cut, carat, fill=color, color=color)) + 
    geom_violin(alpha=.3) + geom_jitter(width=.05, alpha=.5) + 
    facet_grid(.~color)

可能用户还是不爽,因为用户可能想把同样的cut放在一起来比较,像最初的图一样。又所谓活人不能让尿憋死,难道你不能变通一下吗?我们可以把x轴的变量换掉,同时考虑原先x轴的变量和分组变量。强行自己分组。

d$cut_color <- paste(d$cut, d$color, sep="_")
ggplot(d, aes(cut_color, carat, fill=color, color=color)) + 
    geom_violin(alpha=.3) + geom_jitter(width=.05, alpha=.5)

活人不能让尿憋死

要说到变通,你还能够乾坤大挪移,我就想按照原来的代码来画,又想把点挪到violin上,那就挪点呗,只要你懂得变通!凡事皆有可能:

d$xpos = as.numeric(factor(d$cut)) + c(-.22, .22)[as.numeric(factor(d$color))]
ggplot(d, aes(cut, carat, fill=color, color=color)) + 
    geom_violin(alpha=.3) + 
    geom_jitter(aes(x=xpos), width=.05, alpha=.5)

专业解决ggplot2画图疑难杂症