只绘制小提琴图的一侧/半边

8

我希望只有小提琴图的一半(类似于由ggridges中的stat_density_ridges创建的图)。下面是一个最小化工作示例:

library(ggplot2)

dframe = data.frame(val = c(), group = c())
for(i in 1:5){
  offset = i - 3
  dframe = rbind(dframe, 
                 data.frame(val = rnorm(n = 50, mean = 0 - offset), group = i)
                 )
}
dframe$group = as.factor(dframe$group)

ggplot(data = dframe, aes(x = group, y = val)) + 
  geom_violin()      

生成的图形如下所示:

enter image description here

但是我希望它看起来像这样:

enter image description here

最好,这些图形也应该按比例缩放到1.5到2倍的宽度。

你卡在哪里了?我猜你已经试过解决这个问题了。 - Roland
2
一个简单的方法是使用geom_density和分面。 - Roland
1
你可能需要修改 geom_violin - Roman Luštrik
1
也许这里的答案会有所帮助:https://dev59.com/8FsV5IYBdhLWcg3w2h0s - erc
非常感谢您的所有评论。在Roland的提示下,我能够复制类似于我想要的东西。然而,PoGibas的答案更接近。 - Exocom
2个回答

11

有一个巧妙的解决方案来自@David Robinson(原始代码来自他的gists,我只做了几个修改)。

他创建了一个新的层(GeomFlatViolin),该层基于改变小提琴图的宽度:

data <- transform(data, 
                  xmaxv = x,
                  xminv = x + violinwidth * (xmin - x))

这个层面还有一个width参数。


示例:

# Using OPs data
# Get wanted width with: geom_flat_violin(width = 1.5)
ggplot(dframe, aes(group, val)) +
    geom_flat_violin()

enter image description here

代码:

library(ggplot2)
library(dplyr)


"%||%" <- function(a, b) {
  if (!is.null(a)) a else b
}

geom_flat_violin <- function(mapping = NULL, data = NULL, stat = "ydensity",
                        position = "dodge", trim = TRUE, scale = "area",
                        show.legend = NA, inherit.aes = TRUE, ...) {
  layer(
    data = data,
    mapping = mapping,
    stat = stat,
    geom = GeomFlatViolin,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      trim = trim,
      scale = scale,
      ...
    )
  )
}

GeomFlatViolin <-
  ggproto("GeomFlatViolin", Geom,
          setup_data = function(data, params) {
            data$width <- data$width %||%
              params$width %||% (resolution(data$x, FALSE) * 0.9)

            # ymin, ymax, xmin, and xmax define the bounding rectangle for each group
            data %>%
              group_by(group) %>%
              mutate(ymin = min(y),
                     ymax = max(y),
                     xmin = x - width / 2,
                     xmax = x)
          },

          draw_group = function(data, panel_scales, coord) {
            # Find the points for the line to go all the way around
            data <- transform(data, 
                              xmaxv = x,
                              xminv = x + violinwidth * (xmin - x))

            # Make sure it's sorted properly to draw the outline
            newdata <- rbind(plyr::arrange(transform(data, x = xminv), y),
                             plyr::arrange(transform(data, x = xmaxv), -y))

            # Close the polygon: set first and last point the same
            # Needed for coord_polar and such
            newdata <- rbind(newdata, newdata[1,])

            ggplot2:::ggname("geom_flat_violin", GeomPolygon$draw_panel(newdata, panel_scales, coord))
          },

          draw_key = draw_key_polygon,

          default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5,
                            alpha = NA, linetype = "solid"),

          required_aes = c("x", "y")
)

这非常接近我想要的。非常感谢。虽然到目前为止我还没有弄清楚如何去掉垂直线,因为我想显示25%和75%的分位数(以便在其中包含箱线图的信息)。我会继续尝试的。与此同时,点应该可以胜任。 - Exocom
Exocom,你有找到保留箱型图信息的方法吗?这正是我也在寻找的内容。 - helen.h
@helen.h 你所说的“箱线图信息”是什么意思? - pogibas
@PoGibas 我正在尝试创建只显示半个轮廓的小提琴图(如上所示),但我仍希望有箱线图覆盖四分位距和中位数线。 - helen.h
1
@helen.h 你可以通过添加一个窄的箱线图 + geom_boxplot(width=0.1) 来获取中位数和四分位距! - postylem
这是一个很好的答案@PoGibas。您是否知道是否有类似的解决方案用于绘制直方图(而不是半小提琴,它们本质上是密度图)? - user436994

4

软件包see还拥有一个函数geom_violinhalf,这个函数似乎完全符合你的要求(见下面的右图)。它的行为大多类似于geom_violin(),不过它没有所有参数geom_violin()有(例如缺少draw_quantiles)。

library(ggplot2)
library(see)


p <- ggplot(mtcars, aes(factor(cyl), mpg))
p1 <- p + geom_violin()+ ggtitle("geom_violin")
p2 <- p + see::geom_violinhalf()+ ggtitle("see::geom_violinhalf")

## show them next to each other
library(patchwork)
p1+p2

这篇文章创建于2020-04-30,使用了 reprex包(版本0.3.0)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接