ggplot2:显示嵌套拆分小提琴的块 [英] ggplot2: display blocks of nested split violins

查看:411
本文介绍了ggplot2:显示嵌套拆分小提琴的块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下数据集:

pre $ df < - data.frame(dens = rnorm(5000),
split = as.factor(sample(1:2,5000,replace = T)),
method = as.factor(sample(c(A,B),5000,replace = T )),
counts = sample(c(1,10,100,1000,10000),5000,replace = T))

我想要做的是在组A和组B中针对每个计数对分组1和组2分割小提琴图(这将在对数分布中,但对于此并不重要)例)。每个设置我们都有四个组,但是它有一个嵌套的方面。



所以,我可以这样做:

  df $ key <  -  factor(paste(df $ split,df $ method))

然后:

  library(ggplot2)
ggplot(df,aes(x = factor(counts),y = dens,fill = split ))+
geom_violin(aes(fill = key),scale =width,draw_quantiles = c(0.25,0.5,0.75))+ scale_fill_manual(values = cbPalette)+ theme_bw()

这给了我下面的图:



但是我想要的是浅蓝色和深蓝色是分裂小提琴情节的两半,浅绿色和深绿色是另一个小提琴情节的两半,这些情节应该聚在一起。我也希望不同的计数能够彼此更加分离,但我觉得我可以弄清楚。



请注意,此问题与我列出的问题不同或



可以看出,绿色图像位于蓝调之上。我如何解决这个问题?谢谢!

编辑:Axeman的建议,我几乎在那里:

 <$ c $ (df,aes(x =交互作用(拆分,计数),y = 1) )+ + theme_light()+ theme_light()+ theme_light()+ theme_light()+ theme_light() (legend.position =bottom)+ scale_x_discrete(interaction(df $ split,df $ counts)[ -  length(interaction(df $ split,df $ counts))],drop = FALSE)




我仍然需要将计数值放在x轴上,位于两个图之间。 解析方案 div>

我认为这个问题太长了,这个问题的基本部分已经回答了。我已经提出了一个关于如何改变离散比例的新问题。希望有人知道!无论如何,这是这个问题的答案(谢谢,Ax!)。这是在我的问题的编辑版本。

  library(ggplot2)
df< - data.frame( dens = rnorm(5000),
split = factor(sample(1:2,5000,replace = T)),
method = factor(sample(c(A,B 5000,replace = T)),
counts = factor(sample(c(1,10,100,1000,10000),5000,replace = T)))

df $ key < - factor(paste(df $ split,df $ method))

levels(df $ split)< - factor(0:2)
library(ggplot2)

ggplot(df,aes(x = interaction(split,counts),y = dens,fill = key))+
geom_split_violin(draw_quantiles = c(0.25,0.5,0.75))+
scale_fill_manual(values = RColorBrewer :: brewer.pal(name =Paired,n = 4))+
theme_light()+
theme(legend.position =bottom)+
scale_x_discrete(
limits = levels(交互(df $ split,df $ counts))[ - 长度(水平(交互作用(df $ split,df $ counts)))],
drop = FALSE ,
name =Counts


I have the following dataset:

df <- data.frame(dens = rnorm(5000),
             split = as.factor(sample(1:2, 5000, replace = T)),
             method = as.factor(sample(c("A","B"), 5000, replace = T)),
             counts = sample(c(1, 10, 100, 1000, 10000), 5000, replace = T))

What i am wanting to do is to do split violin plots for splits 1 and 2 within groups A and B for each count (which would be in the logscale, but that is not important for this example). We have four groups for each setting but there is a nested aspect to it.

So, I can do the following:

df$key <- factor(paste(df$split, df$method))

and then:

library(ggplot2)
ggplot(df, aes(x = factor(counts), y = dens, fill = split)) +
geom_violin(aes(fill = key), scale = "width", draw_quantiles = c(0.25, 0.5, 0.75)) + scale_fill_manual(values = cbPalette) + theme_bw()

which gives me the following plot:

But what I want is really the light blue and the dark blue to be the two halves of a split violin plot and the light green and the dark green to be the two halves of another split violin plot and these plots should be bunched together. I would also like the different counts to be more separated from each other, but i feel that I can figure that out.

Note that this question is different than the one I have listed or Split violin plot with ggplot2 because we are bunching two different levels of nested split violin plots for each "Counts".

I was trying to follow enter link description here but I can not tell how to add such a nested groups setting to the code there and am looking for some advice.

Here is what I have tried:

GeomSplitViolin <- ggproto("GeomSplitViolin", GeomViolin, 
  draw_group = function(self, data, ..., draw_quantiles = NULL){
    # By @YAK: https://stackoverflow.com/questions/35717353/split-violin-plot-with-ggplot2
    data <- transform(data, xminv = x - violinwidth * (x - xmin), xmaxv = x + violinwidth * (xmax - x))
    grp <- data[1,'group']
    newdata <- plyr::arrange(transform(data, x = if(grp%%2==1) xminv else xmaxv), if(grp%%2==1) y else -y)
    newdata <- rbind(newdata[1, ], newdata, newdata[nrow(newdata), ], newdata[1, ])
    newdata[c(1,nrow(newdata)-1,nrow(newdata)), 'x'] <- round(newdata[1, 'x']) 
    if (length(draw_quantiles) > 0 & !scales::zero_range(range(data$y))) {
      stopifnot(all(draw_quantiles >= 0), all(draw_quantiles <= 1))
      quantiles <- create_quantile_segment_frame(data, draw_quantiles, split = TRUE, grp = grp)
      aesthetics <- data[rep(1, nrow(quantiles)), setdiff(names(data), c("x", "y")), drop = FALSE]
      aesthetics$alpha <- rep(1, nrow(quantiles))
      both <- cbind(quantiles, aesthetics)
      quantile_grob <- GeomPath$draw_panel(both, ...)
      ggplot2:::ggname("geom_split_violin", grid::grobTree(GeomPolygon$draw_panel(newdata, ...), quantile_grob))
    }
    else {
      ggplot2:::ggname("geom_split_violin", GeomPolygon$draw_panel(newdata, ...))
    }
  }
)

create_quantile_segment_frame <- function (data, draw_quantiles, split = FALSE, grp = NULL) {
  dens <- cumsum(data$density)/sum(data$density)
  ecdf <- stats::approxfun(dens, data$y)
  ys <- ecdf(draw_quantiles)
  violin.xminvs <- (stats::approxfun(data$y, data$xminv))(ys)
  violin.xmaxvs <- (stats::approxfun(data$y, data$xmaxv))(ys)
  violin.xs <- (stats::approxfun(data$y, data$x))(ys)
  if (grp %% 2 == 0) {
    data.frame(x = ggplot2:::interleave(violin.xs, violin.xmaxvs), 
               y = rep(ys, each = 2), group = rep(ys, each = 2)) 
  } else {
    data.frame(x = ggplot2:::interleave(violin.xminvs, violin.xs), 
               y = rep(ys, each = 2), group = rep(ys, each = 2)) 
  }
}



geom_split_violin <- function (mapping = NULL, data = NULL, stat = "ydensity", position = "identity", ..., draw_quantiles = NULL, trim = TRUE, scale = "area", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
  layer(data = data, mapping = mapping, stat = stat, geom = GeomSplitViolin, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list(trim = trim, scale = scale, draw_quantiles = draw_quantiles, na.rm = na.rm, ...))
}

library(ggplot2)
ggplot(df, aes(x = factor(counts), y = dens, fill = interaction(split,method))) +
           geom_split_violin(draw_quantiles = c(0.25, 0.5, 0.75)) + scale_fill_manual(values=RColorBrewer::brewer.pal(name="Paired",n=4)) + theme_light() + theme(legend.position="bottom")

And here is what I get:

As can be seen, the green images are on top of the blues. How do I get around this? Thanks!

EDIT: Folllowing Axeman's suggestion, I am almost there:

   levels(df$split) <- factor(0:3)

   library(ggplot2)
   ggplot(df, aes(x = interaction(split, counts), y = dens, fill = key)) + geom_split_violin(draw_quantiles = c(0.25, 0.5, 0.75)) + scale_fill_manual(values=RColorBrewer::brewer.pal(name="Paired",n=4)) + theme_light() + theme(legend.position="bottom") + scale_x_discrete(interaction(df$split,df$counts)[-length(interaction(df$split,df$counts))], drop = FALSE)

So almost there!

Would like two fixes: the white space arising from the last interaction between split and counts, and the scale to only have counts for each bunch. Wonder if these should be separate questions on Stackoverflow.

Almost there!

library(ggplot2)
ggplot(df, aes(x = interaction(split, counts), y = dens, fill = key)) + geom_split_violin(draw_quantiles = c(0.25, 0.5, 0.75)) +scale_fill_manual(values=RColorBrewer::brewer.pal(name="Paired",n=4)) + theme_light() + theme(legend.position="bottom") + scale_x_discrete(limits=levels(interaction(df$split,df$counts))[-length(levels(interaction(df$split,df$counts)))],drop = FALSE)

This yields:

I still need to place the value of counts on the x-axis, in between the two plots.

解决方案

I think that this question has become too long and the basic parts of this question have been answered. I have put up a new question on how to change the discrete scale. Hopefully, someone will know! Anyway, here is the answer to this question (thanks, Axe!). It is in the edited version of my question.

library(ggplot2)
df <- data.frame(dens = rnorm(5000),
             split = factor(sample(1:2, 5000, replace = T)),
             method = factor(sample(c("A","B"), 5000, replace = T)),
             counts = factor(sample(c(1, 10, 100, 1000, 10000), 5000, replace = T)))

df$key <- factor(paste(df$split, df$method))

levels(df$split) <- factor(0:2)
library(ggplot2)

ggplot(df, aes(x = interaction(split, counts), y = dens, fill = key)) +
  geom_split_violin(draw_quantiles = c(0.25, 0.5, 0.75)) +
  scale_fill_manual(values=RColorBrewer::brewer.pal(name="Paired",n=4)) + 
  theme_light() + 
  theme(legend.position="bottom") + 
  scale_x_discrete(
    limits = levels(interaction(df$split,df$counts))[-length(levels(interaction(df$split,df$counts)))],
    drop = FALSE, 
    name = "Counts"
  )

这篇关于ggplot2:显示嵌套拆分小提琴的块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆