【问题标题】:Jitter dots without overlap无重叠的抖动点
【发布时间】:2017-04-29 17:00:16
【问题描述】:

我的数据:

a <- sample(1:5, 100, replace = TRUE)
b <- sample(1:5, 100, replace = TRUE)
c <- sample(1:10, 100, replace = TRUE)
d <- sample(1:40, 100, replace = TRUE)
df <- data.frame(a, b, c, d)

使用ggplot2,我在x = a 和y = b 上创建了散点图,二维加权(colour = csize = d)。请注意,x 和 y 是有意为 1:5

很明显,不同大小和颜色的点因此重叠,所以我尝试了jitter以避免重叠:

ggplot(df, aes(a, b, colour = c, size = d)) + 
  geom_point(position = position_jitter())

现在我想让这些点更紧密地聚集在一起,所以我尝试了几个 heightwidth 的组合用于抖动功能,例如

ggplot(df, aes(a, b, colour = c, size = d)) + 
  geom_point(position = position_jitter(width = 0.2, height = 0.2))

抖动使点仍然重叠,并将它们随机分布在给定区域上。

有没有办法让点完全不重叠,但尽可能紧密地聚集在一起,甚至可能接触,也不“并排”或堆叠? (在某种程度上,创造了一种带有小点的气泡)?

谢谢!

【问题讨论】:

  • 您尝试过使用geom_dotplot 吗?我一直在玩它几分钟,但不能让它做你想做的事。但这通常是我制作堆叠点图的方式
  • @Reilstein:感谢您的帮助!不幸的是,geom_dotplot 不断将点堆叠成一条线,我也没有得到不同的点大小......
  • 是的,我遇到了同样的问题。我能够将点放在正确的位置,但无法将颜色和大小映射到它们。看起来 ggbeeswarm 可能是适合您的方式。

标签: r plot ggplot2 overlap scatter


【解决方案1】:

根据@Tjebo 的建议,我在“堆”中排列了点。

set.seed(1234)
n <- 100
a <- sample(1:5,n,rep=TRUE)
b <- sample(1:5,n,rep=TRUE)
c <- sample(1:10,n,rep=TRUE)
d <- sample(1:40,n,rep=TRUE)
df0 <- data.frame(a,b,c,d)

# These parameters need carefully tuning
minr <- 0.05
maxr <- 0.2
# Order circles by dimension
ord <- FALSE

df1 <- df0
df1$d <- minr+(maxr-minr)*(df1$d-min(df1$d))/(max(df1$d)-min(df1$d))
avals <- unique(df1$a)
bvals <- unique(df1$b)

for (k1 in seq_along(avals)) {
  for (k2 in seq_along(bvals)) {
  print(paste(k1,k2))
    subk <- (df1$a==avals[k1] & df1$b==bvals[k2])
    if (sum(subk)>1) {
      subdfk <- df1[subk,]
      if (ord) {
        idx <- order(subdfk$d)
        subdfk <- subdfk[idx,]
      }
      subdfk.mod <- subdfk
      posmx <- which.max(subdfk$d)   
      subdfk1 <- subdfk[posmx,]
      subdfk2  <- subdfk[-posmx,]
      angsk <- seq(0,2*pi,length.out=nrow(subdfk2)+1)
      subdfk2$a <- subdfk2$a+cos(angsk[-length(angsk)])*(subdfk1$d+subdfk2$d)/2
      subdfk2$b <- subdfk2$b+sin(angsk[-length(angsk)])*(subdfk1$d+subdfk2$d)/2
      subdfk.mod[posmx,] <- subdfk1
      subdfk.mod[-posmx,] <- subdfk2
      df1[subk,] <- subdfk.mod
    }
  }
}

library(ggplot2)
library(ggforce)
ggplot(df1, aes()) + 
  geom_circle(aes(x0=a, y0=b, r=d/2, fill=c), alpha=0.7)+ coord_fixed()

【讨论】:

  • 是的!这是最神奇的!正是我的意思!非常感谢!
【解决方案2】:

一个有趣的可视化工具是 beeswarm 图。
在 R 中,beeswarmggbeeswarm 包实现了这种情节。

这是ggbeeswarm 的示例:

set.seed(1234)
a <- sample(1:5,100,rep=TRUE)
b <- sample(1:5,100,rep=TRUE)
c <- sample(1:10,100,rep=TRUE)
d <- sample(1:40,100,rep=TRUE)
df <- data.frame(a,b,c,d)
library(ggbeeswarm)
ggplot(aes(x=a, y=b, col=c, size=d),  data = df)+
  geom_beeswarm(priority='random',cex=3.5, groupOnX=T)+coord_flip()

希望对你有帮助。

【讨论】:

  • 感谢您的建议。我在 ggbeeswarm 和 beeswarm 中尝试了几个参数,但是这些点一直垂直或水平堆叠,就像你的例子一样。我想这是由于我的数据的性质(x 和 y 都是 c(1:5)。使用 geom_jitter 或 geom_jitterdodge,整个事情已经非常接近我想要的了,但是点重叠并且有些抖动很远从其他点。
  • *position_jitterdodge,道歉
【解决方案3】:

这是@Tjebo 抖动问题的另一个可能解决方案。
参数dst 需要调整。

set.seed(1234)
a <- sample(1:5,100,rep=TRUE)
b <- sample(1:5,100,rep=TRUE)
c <- sample(1:10,100,rep=TRUE)
d <- sample(1:40,100,rep=TRUE)
df <- data.frame(a,b,c,d)

dst <- .2

df.mod <- df
avals <- unique(df$a)
bvals <- unique(df$b)
for (k1 in seq_along(avals)) {
  for (k2 in seq_along(bvals)) {
    subk <- (df$a==avals[k1] & df$b==bvals[k2])
    if (sum(subk)>1) {
      subdf <- df[subk,]
      angsk <- seq(0,2*pi,length.out=nrow(subdf)+1)
      ak <- subdf$a+cos(angsk[-1])*dst
      bk <- subdf$b+sin(angsk[-1])*dst
      df.mod[subk,c("a","b")] <- cbind(ak,bk)
    }
  }
}

library(ggplot2)
ggplot(df.mod, aes(a, b, colour = c, size = d)) + geom_point()

【讨论】:

  • 非常感谢您提供这个惊人的解决方案!这很有效,看起来很棒!您是否认为可能有一种方法可以将点更紧密地打包在一起,即不是按圆圈排列,而是按“堆”排列?我想我需要使用 cos/sin/dst 参数(?),但不幸的是我不太了解你的功能,我太初学者了:/
猜你喜欢
  • 1970-01-01
  • 2017-03-25
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
相关资源
最近更新 更多