直方图:在 ggplot2 中组合连续值和离散值

Posted

技术标签:

【中文标题】直方图:在 ggplot2 中组合连续值和离散值【英文标题】:Histogram: Combine continuous and discrete values in ggplot2 【发布时间】:2020-10-28 03:29:15 【问题描述】:

我想在直方图上绘制一组时间。 玩具示例:

df <- data.frame(time = c(1,2,2,3,4,5,5,5,6,7,7,7,9,9, ">10"))

问题在于,一个值是“>10”,指的是观察到超过 10 秒的次数。其他时间点均为数字,指的是实际时间。现在,我想创建一个直方图,将所有数字视为数字,并在适当的时候将它们组合在箱中,同时在分布的一侧绘制“>10”的计数,但不在单独的图中。我曾尝试调用 geom_histogram 两次,一次使用连续数据,一次使用单独列中的离散数据,但这给了我以下错误:

Error: Discrete value supplied to continuous scale

很高兴听到建议!

【问题讨论】:

你需要df %&gt;% count(time) %&gt;% ggplot(aes(x = time, y = n)) + geom_col() 但我想在正常直方图中使用 bin。或者您是否建议事先将这些箱合并为一个值,然后像这样绘制 geom_col?听起来可行,但相对不切实际。还有其他方法可以利用 geom_histogram 吗? 您可以将字符值替换为数值,将其转换为数值。但是,我并不完全清楚 感谢您的回复!假设我将 >10 转换为数字:那么它将任意成为直方图中最后一个 bin 的一部分,这是我不想要的。换句话说:我想在 binwidth 2 处有一个所有值 0-10 的直方图。在同一个图上,就在它旁边,我想添加一个条形图来显示值 >10 的计数。 【参考方案1】:

这是一种涉及的解决方案,但我相信它最好地回答了您的问题,即您希望在典型直方图旁边放置一个表示“>10”值(或非数字值)的条形图)。 至关重要的是,您要确保保持与直方图关联的“分箱”,这意味着您不希望简单地使您的比例尺成为离散比例尺并用典型的条形图表示直方图。

数据

由于您想保留直方图特征,我将使用一个示例数据集,该示例数据集比您提供给我们的要复杂一些。我只是要指定一个均匀分布(n=100),其中包含 20 个“>10”个值。

set.seed(123)
df<- data.frame(time=c(runif(100,0,10), rep(">10",20)))

正如准备的那样,df$time 是一个字符向量,但对于直方图,我们需要它是数字的。我们只是将其强制为数字并接受“>10”值将被强制为 NA。这很好,因为最后我们将计算那些 NA 值并用条形表示它们。在此过程中,我正在创建 df 的一个子集,该子集将用于使用 count() 函数创建代表我们的 NA (">10") 的条形,该函数返回一个由一行和列:df$n = 20 在这种情况下。

library(dplyr)
df$time <- as.numeric(df$time)  #force numeric and get NA for everything else
df_na <- count(subset(df, is.na(time)))

情节

对于实际绘图,您要求创建 (1) 直方图和 (2) 条形图的组合。这些不是同一个图,但更重要的是,它们不能共享相同的轴,因为根据定义,直方图需要一个连续轴和“NA”值或“>10”不是数字/连续值。这里的解决方案是制作两个单独的图,然后通过cowplot 将它们与一点魔法结合起来。

直方图很容易创建。稍后我将保存垃圾箱的数量以用于演示目的。这是基本情节:

bin_num <- 12  # using this later

p1 <- ggplot(df, aes(x=time)) + theme_classic() +
  geom_histogram(color='gray25', fill='blue', alpha=0.3, bins=bin_num)

由于之前的子集,NA 值的条形图也很容易:

p2 <- ggplot(df_na, aes(x=">10", y=n)) + theme_classic() +
  geom_col(color='gray25', fill='red', alpha=0.3)

哎呀!这看起来很可怕,但要有耐心。

将它们拼接在一起

您可以简单地运行 plot_grid(p1, p2) 并得到一些可行的东西......但它还有很多不足之处:

这里有问题。我将列举它们,然后向您展示我如何处理它们的最终代码:

    需要从 NA 条形图中删除一些元素。也就是说,完全是 y 轴和 x 轴的标题(但它不能是 NULL 或者 x 轴不会正确排列)。这些是theme() 元素,可以通过ggplot 轻松删除。

    NA 条形图占用了太多空间。需要减少宽度。我们通过访问plot_grid()rel_widths= 参数来解决这个问题。轻松愉快。

    我们如何知道如何设置 y 比例上限?这有点复杂,因为它将取决于p1..count.. stat 以及 NA 值的数量。您可以使用ggplot_build() 来access the maximum count for a histogram,它是ggplot2 的一部分。

因此,最终代码需要创建基本的 p1p2 图,然后添加到它们以修复限制。我还在p1 中添加了 bin 数量的注释,以便我们可以跟踪上限设置的工作情况。这是代码和一些示例图,其中bin_num 分别设置为 12 和 5:

# basic plots
p1 <- ggplot(df, aes(x=time)) + theme_classic() +
  geom_histogram(color='gray25', fill='blue', alpha=0.3, bins=bin_num)

p2 <- ggplot(df_na, aes(x=">10", y=n)) + theme_classic() +
  geom_col(color='gray25', fill='red', alpha=0.3) +
  labs(x="") +  theme(axis.line.y=element_blank(), axis.text.y=element_blank(),
    axis.title.y=element_blank(), axis.ticks.y=element_blank()
  ) +
  scale_x_discrete(expand=expansion(add=1))

#set upper y scale limit
max_count <- max(c(max(ggplot_build(p1)$data[[1]]$count), df_na$n))

# fix limits for plots
p1 <- p1 + scale_y_continuous(limits=c(0,max_count), expand=expansion(mult=c(0,0.15))) +
  annotate('text', x=0, y=max_count, label=paste('Bins:', bin_num))  # for demo purposes
p2 <- p2 + scale_y_continuous(limits=c(0,max_count), expand=expansion(mult=c(0,0.15)))

plot_grid(p1, p2, rel_widths=c(1,0.2))

所以,我们的上限修复工作。玩定位等和plot_grid() 函数可能会非常疯狂,但我认为这种方式效果很好。

【讨论】:

感谢您的出色回答。接受了这个答案,因为它更通用并且解决了更多的案例;最后,我决定使用@YBS '答案的修改实现。 这肯定更简单,但如果你有需要使用stat_bin提供的分箱的情况,那么你就不得不求助于这样的东西了。【参考方案2】:

也许,这就是你要找的:

df1 <- data.frame(x=sample(1:12,50,rep=T))

df2 <- df1 %>%  group_by(x) %>% 
        dplyr::summarise(y=n()) %>% subset(x<11)

df3 <- subset(df1, x>10) %>% dplyr::summarise(y=n()) %>% mutate(x=11)

df <- rbind(df2,df3 )
label <- ifelse((df$x<11),as.character(df$x),">10")
  
p <- ggplot(df, aes(x=x,y=y,color=x,fill=x)) + 
  geom_bar(stat="identity", position = "dodge") +
  scale_x_continuous(breaks=df$x,labels=label) 
p

你会得到以下输出:

请注意,有时您可能会丢失某些条形,具体取决于样本。

【讨论】:

谢谢@YBS,这几乎是我计划要做的实现。我最后做了一些更改:(1)将 >10 定义为 '11' 以连续比例绘制它。 (2) 使用geom_histogram。 (3) 使用 scale_x_continuous 将标签“11”重命名为“>10”。显然,在分配 (1) 中的值时必须小心,但它在特定用例中效果很好。

以上是关于直方图:在 ggplot2 中组合连续值和离散值的主要内容,如果未能解决你的问题,请参考以下文章

使用 ggplot2 组合箱线图和直方图

R语言ggplot2可视化:可视化离散(分类)变量的堆叠的直方图自定义堆叠直方图中不同分组条形的色彩(Histogram for Categorical Variable)自定义轴标签旋转的角度

提供给离散比例ggplot2的连续值

ggplot2:方面的连续和离散比例

用ggplot2直方图中另一个连续变量的平均值填充条形颜色

ggplot2多边形->错误:提供给连续比例的离散值