如何在具有对数刻度和离散值的ggplot直方图中改善外观

14

我试图改善离散值的直方图,需要用对数刻度来表示,并提高其清晰度和美观性。

请看以下MWE:

set.seed(99)
data <- data.frame(dist = as.integer(rlnorm(1000, sdlog = 2)))
class(data$dist)
ggplot(data, aes(x=dist)) + geom_histogram()

生产出

enter image description here

然后

ggplot(data, aes(x=dist)) + geom_line() + scale_x_log10(breaks=c(1,2,3,4,5,10,100))

这可能会更糟

图片描述

因为现在给人的印象是在“1”和“2”之间缺少某些内容,而且也不完全清楚哪个柱子的值是“1”(柱子在刻度的右侧)以及哪个柱子的值是“2”(柱子在刻度的左侧)。

我知道从技术上讲ggplot为对数比例尺提供了“正确”的视觉答案。但作为观察者,我在理解上有些问题。

有什么方法可以改善吗?

编辑:

当我将Jaap的解决方案应用于我的实际数据时,就会发生这种情况

图片描述

x=0和x=1之间以及x=1和x=2之间的跌落是怎么回事?我的值是离散的,但是为什么图也将x=1.5和x=2.5映射了出来?


这可能很琐碎,但是尝试减少箱数吧? - Koundy
@koundy 在我看来,那并没有真正帮助到问题。请参考我的回答中的示例。 - Jaap
4个回答

14

首先想到的是玩弄binwidth,但这也不能提供一个很好的解决方案:

ggplot(data, aes(x=dist)) +
  geom_histogram(binwidth=10) +
  scale_x_continuous(expand=c(0,0)) +
  scale_y_continuous(expand=c(0.015,0)) +
  theme_bw()

提供:

enter image description here

在这种情况下,最好使用密度图。然而,当你使用scale_x_log10时,你将得到一个警告信息(Removed 524 rows containing non-finite values (stat_density))。可以通过使用对数加一变换来解决这个问题。

以下是代码:

library(ggplot2)
library(scales)

ggplot(data, aes(x=dist)) +
  stat_density(aes(y=..count..), color="black", fill="blue", alpha=0.3) +
  scale_x_continuous(breaks=c(0,1,2,3,4,5,10,30,100,300,1000), trans="log1p", expand=c(0,0)) +
  scale_y_continuous(breaks=c(0,125,250,375,500,625,750), expand=c(0,0)) +
  theme_bw()

将会得到这个结果: 在此输入图片描述


由于某种奇怪的原因,在我的真实数据上使用您的解决方案,我在x=0和x=1之间以及x=1和x=2之间有一个下降。为什么?由于像MWE中一样,我的值是离散的,因此在0和1之间没有值可映射。(添加了图片) - CptNemo
由于你提供的样本数据也是离散的,所以那可能不是问题所在。从你的图表看来,可能与你的 y 轴定义有关。在 y 轴底部,刻度线非常拥挤,这很奇怪。你可以分享一下你使用的确切代码和数据的 dput(或足够大的一部分数据)吗?没有这些信息,很难确定这种行为的确切原因。 - Jaap
log1p,不错,我之前不知道这个! - Eduardo

5

我在想,如果y轴被缩放而不是x轴,会怎样呢?这将导致一些警告出现在值为0的地方,但可能能够达到你的目的。

set.seed(99)
data <- data.frame(dist = as.integer(rlnorm(1000, sdlog = 2)))
class(data$dist)
ggplot(data, aes(x=dist)) + geom_histogram() + scale_y_log10()

基础图表

此外,您可能希望将频率显示为数据标签,因为人们可能会忽略y轴刻度,并且需要一些时间才能意识到y轴刻度是对数。

ggplot(data, aes(x=dist)) + geom_histogram(fill = 'skyblue', color = 'grey30') + scale_y_log10() +
  stat_bin(geom="text", size=3.5, aes(label=..count.., y=0.8*(..count..)))

enter image description here


4

解决方法可能是将您的数据转换为因子:

library(ggplot2)
set.seed(99)
data <- data.frame(dist = as.integer(rlnorm(1000, sdlog = 2)))
ggplot(data, aes(x=factor(dist))) + 
    geom_histogram(stat = "count") + 
    theme(axis.text.x = element_text(angle = 90, hjust = 1))

导致结果如下图所示: enter image description here

2
你不需要事先这样做,你也可以在ggplot函数内将其转换为因子变量:ggplot(data, aes(x=factor(dist))) + geom_histogram() - Jaap

0

我曾经遇到过同样的问题,受@Jaap答案的启发,我调整了直方图条宽,使用对数比例尺调整x轴。

如果你使用binwidth = 0.201,则柱状图将按预期并置。但是,这意味着您在两个x坐标之间最多只能拥有五个条形图。

set.seed(99)
data <- data.frame(dist = as.integer(rlnorm(1000, sdlog = 2)))
class(data$dist)
ggplot(data, aes(x=dist)) + 
   geom_histogram(binwidth = 0.201, color = 'red') + 
   scale_x_log10()

结果:

enter image description here


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