带对数刻度的条形图

43

我在使用ggplot进行缩放时遇到了一个有趣的问题。我的数据集在使用默认线性比例尺时可以很好地绘制图形,但是当我使用scale_y_log10()时,数字就会偏离轨道。以下是一些示例代码和两张图片。请注意,在线性比例尺中的最大值约为700,而对数缩放结果为10 ^ 8。我向您展示,整个数据集仅约为8000项,因此某些地方不正确。

我想象这个问题与我的数据集结构和分箱有关,因为我无法在像“钻石”这样的常见数据集上复制此错误。然而,我不确定要解决问题的最佳方法。

谢谢, zach cp


编辑:bdamarest可以通过以下方式在钻石数据集上重现比例问题:

example_1 = ggplot(diamonds, aes(x=clarity, fill=cut)) + 
  geom_bar() + scale_y_log10(); print(example_1)

#data.melt is the name of my dataset    
> ggplot(data.melt, aes(name, fill= Library)) + geom_bar()  
> ggplot(data.melt, aes(name, fill= Library)) + geom_bar()  + scale_y_log10()
> length(data.melt$name)
[1] 8003 

linear scale log scale

这里有一些示例数据...我认为我看到了问题所在。原始的融合数据集可能有大约10^8行。也许行号被用于统计数据?

> head(data.melt)
       Library         name               group
221938      AB Arthrofactin        glycopeptide
235087      AB   Putisolvin      cyclic peptide
235090      AB   Putisolvin      cyclic peptide
222125      AB Arthrofactin        glycopeptide
311468      AB     Triostin cyclic depsipeptide
92249       AB          CDA         lipopeptide

test2 <- data.frame(
  Library = rep("AB", 6L),
  name = c(
    "Arthrofactin", "Putisolvin", "Putisolvin", "Arthrofactin",
    "Triostin", "CDA"
  ),
  group = c(
    "glycopeptide", "cyclic peptide", "cyclic peptide", "glycopeptide",
    "cyclic depsipeptide", "lipopeptide"
  ),
  row.names = c(221938L, 235087L, 235090L, 222125L, 311468L, 92249L)
)

更新:

行号不是问题。这里使用相同的 aes x 轴和填充颜色绘制了相同的数据图,缩放完全正确:

> ggplot(data.melt, aes(name, fill= name)) + geom_bar()
> ggplot(data.melt, aes(name, fill= name)) + geom_bar() + scale_y_log10()
> length(data.melt$name)
[1] 8003

enter image description here enter image description here


在https://stackoverflow.com/questions/60340491/deal-with-bar-size-and-totals-when-ggplot-position-stack-in-split-charts/61806020#61806020中可能有解决问题的方法。 - Ferroao
作为设计逻辑,将条形图绘制在对数刻度上是一种不好的做法。这是因为条形/线条自然倾向于让人们比较它们的长度,但当比例尺不是线性的,从0开始并导致误导性的解释时,它们就失去了意义。在对数刻度下,条形图唯一有意义的部分是其顶部的位置,因此最好用一个点替换它,并制作一个点图。 不要在条形图上使用对数刻度-https://www.graphpad.com/support/faq/graph-tip-dont-use-a-log-scale-on-a-bar-graph/ 使用点图-http://perceptualedge.com/articles/b-eye/dot_plots.pdf - Prashant Bharadwaj
作为设计逻辑,将条形图绘制在对数刻度上是一种不良实践。这是因为条形/线条自然倾向于让人们比较它们的长度,但当刻度不是线性的、从0开始时,它们失去了意义,导致误导性解释。在对数刻度中,条形图唯一有意义的部分就是其顶部的位置-所以最好用一个点来替代它,并制作一个点图,不是吗?不要在条形图上使用对数刻度-https://www.graphpad.com/support/faq/graph-tip-dont-use-a-log-scale-on-a-bar-graph/ 使用点图- http://perceptualedge.com/articles/b-eye/dot_plots.pdf - Prashant Bharadwaj
2个回答

56
geom_barscale_y_log10(或任何对数刻度)不搭配使用,无法产生预期的结果。
首要问题是条形图会变成0,而在对数刻度上,0会被转换为负无穷大(很难绘制)。通常解决这个问题的方法是从1开始而不是从0开始(因为$\log(1)=0$),如果没有计数则不绘制任何内容,并且不用担心偏差,因为如果需要对数刻度,则可能不关心偏差(不一定正确,但是...)。
我正在使用@dbemarest展示的diamonds示例。
一般来说,要解决这个问题就是要转换坐标,而不是刻度(稍后会详细介绍区别)。
ggplot(diamonds, aes(x=clarity, fill=cut)) +
  geom_bar() +
  coord_trans(ytrans="log10")

但是这会出现错误

Error in if (length(from) == 1 || abs(from[1] - from[2]) < 1e-06) return(mean(to)) : 
  missing value where TRUE/FALSE needed

当您使用比例变换时,变换被应用于数据,然后进行统计和排列,然后在反向变换中标记比例尺(大致如此)。您可以通过自己分解计算来看到正在发生的事情。这起源于负无穷大问题。
DF <- ddply(diamonds, .(clarity, cut), summarise, n=length(clarity))
DF$log10n <- log10(DF$n)

这提供了

> head(DF)
  clarity       cut   n   log10n
1      I1      Fair 210 2.322219
2      I1      Good  96 1.982271
3      I1 Very Good  84 1.924279
4      I1   Premium 205 2.311754
5      I1     Ideal 146 2.164353
6     SI2      Fair 466 2.668386

如果按照正常方式绘制,我们会得到预期的条形图:
ggplot(DF, aes(x=clarity, y=n, fill=cut)) + 
  geom_bar(stat="identity")

enter image description here

缩放y轴会导致与使用未经预汇总的数据相同的问题。

ggplot(DF, aes(x=clarity, y=n, fill=cut)) +
  geom_bar(stat="identity") +
  scale_y_log10()

enter image description here

通过绘制计数的log10()值,我们可以看到问题是如何发生的。

ggplot(DF, aes(x=clarity, y=log10n, fill=cut)) +
  geom_bar(stat="identity")

enter image description here

这个看起来和带有scale_y_log10的那个一样,但标签是0、5、10等,而不是10^0、10^5、10^10等。
因此,使用scale_y_log10将计数转换为对数,堆叠这些对数,然后以反对数形式显示刻度。然而,堆叠日志不是线性变换,所以你要求它做的事情没有任何意义。
底线是,在对数刻度上堆叠条形图没有太多意义,因为它们不能从0开始(条形的底部应该在0),比较条形的部分也不合理,因为它们的大小取决于它们在堆栈中的位置。相反,考虑像这样的东西:
ggplot(diamonds, aes(x=clarity, y=..count.., colour=cut)) + 
  geom_point(stat="bin") +
  scale_y_log10()

enter image description here

如果您真的想要一个通常会给您叠放条形图组的总数,您可以这样做:

ggplot(diamonds, aes(x=clarity, y=..count..)) + 
  geom_point(aes(colour=cut), stat="bin") +
  geom_point(stat="bin", colour="black") +
  scale_y_log10()

enter image description here


4
谢谢Brian,我很感激你详细的说明。你还可以使用geom_bar(position="dodge")(由Winston Chang提供答案)。 - zach
10
为了更好地说明这里正在发生的事情,堆叠条形图通常给你一个高度等于计数总和的条形。然而,sum(log(counts)) 相当于 log(product(counts))。换句话说,您将看到条形的高度,就好像您将计数相乘一样。 - Brian

2
最好的选择是使用facet_wrap来消除bar堆叠(正如@Brian所评论的log(sum(x)) != sum(log(x)))。如果需要,您还可以添加一个面板来表示Total
例如,对于diamonds数据集(根据@Brian Diggs的答案),我们可以绘制以下图形:
diamonds %>%
  bind_rows(                                                  # Adds a
    diamonds %>%                                              # panel to 
    mutate(cut = "Total")                                     # represent
  ) %>%                                                       # the
  mutate(cut = cut %>% fct_relevel("Total", after = Inf)) %>% # Total
  ggplot(aes(x = clarity, fill = clarity)) +
  geom_bar() +
  facet_wrap(~cut) +
  scale_y_log10()

清晰度

或者,

diamonds %>%
  bind_rows(                                                          # Adds a
    diamonds %>%                                                      # panel to
    mutate(clarity = "Total")                                         # represent
  ) %>%                                                               # the
  mutate(clarity = clarity %>% fct_relevel("Total", after = Inf)) %>% # Total
  ggplot(aes(x = cut, fill = cut)) +
  geom_bar() +
  facet_wrap(~clarity) +
  scale_y_log10()

cut


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