【问题标题】:Define a fixed width/height to a bar chart, then set an absolute width to bars, and absolute space between bars, in pixels为条形图定义固定宽度/高度,然后为条形图设置绝对宽度,以及条形图之间的绝对间距,以像素为单位
【发布时间】:2021-04-02 23:58:23
【问题描述】:

我想使用ggplot2 生成将遵循严格标准的条形图:

  • 它们必须具有特定尺寸(宽度和高度)
  • 条形的宽度必须固定(以像素为单位),无论图中碰巧有多少条形
  • 必须以像素为单位固定条之间的空间,无论条数如何

我使用 RStudio,它允许在其查看器中进行响应。这意味着当我扩展查看器的边界时,绘图会相应地拉伸,从而增加条形的宽度和它们之间的空间。相反,缩小查看者的边界会使条形变细并减少它们之间的空间。

同样,在查看器的给定边界内,绘制条形图会产生 6 个条形图的条形宽度与只有 2 个条形图时不同。

演示

library(ggplot2)
library(dplyr)

p_all_bars <- 
  mpg %>%
  ggplot(aes(x = class)) +
  geom_bar()

p_two_bars <-
  mpg %>%
  filter(class == "compact" | class == "suv") %>%
  ggplot(aes(x = class)) +
  geom_bar()
p_all_bars

p_two_bars


如果我保存 both 尺寸为 width = 1000 pixelsheight = 650 pixels 的图,很明显,条宽 条之间的空间都不同于一个图(7 个条) 到另一个(2 个小节)。


底线

如何设置绘图高度和宽度的绝对值(以像素为单位)以及条形的宽度和条形之间的间距(也以像素为单位)——无论绘图中的条数如何?

【问题讨论】:

    标签: r ggplot2 bar-chart


    【解决方案1】:

    ggplot2 能够很好地缩放以适应不同大小的视口,这是它在大多数用例中最重要的资产之一。但是,在这种情况下,您实际上想要在主绘图面板中固定大小的对象,这会使生活变得更加困难。原因是面板尺寸本身不是固定的。相反,它会根据设备尺寸增长和缩小,从而允许绘图的某些其他元素(例如轴元素、文本和标题)保持固定大小。

    这是可能的,但并不容易。为此,您需要:

    1. 修复整体图的大小(以像素为单位)
    2. 将绘图面板的大小固定为总绘图宽度的比例
    3. 根据 x 轴上的项目数自动计算条形宽度。

    如果您认为这一切听起来太麻烦,那么我可能会同意。如果你想制作很多地块,这是值得的。对于这里或那里的奇数,我可能会沿 x 轴添加虚拟因子水平以保持绘图一致,然后使用成像软件切掉轴上的额外空间。

    但是,它可能的,所以对于它的价值,这里有一个使用编程方法将条固定在 51 像素宽和 6 像素间隙的示例:

    library(ggplot2)
    library(dplyr)
    
    p_all_bars <- 
      mpg %>%
      ggplot(aes(x = class)) +
      geom_bar() +
      scale_x_discrete(expand = expansion(0, 1/7))
    
    p_two_bars <-
      mpg %>%
      filter(class == "compact" | class == "suv") %>%
      ggplot(aes(x = class)) +
      geom_bar() +
      scale_x_discrete(expand = expansion(mult = 0, 1/2))
    
    two_bars <- ggplot_gtable(ggplot_build(p_two_bars))
    all_bars <- ggplot_gtable(ggplot_build(p_all_bars))
    
    all_bars$widths[5] <- unit(14, "cm")
    all_bars$widths[1] <- unit(1, "null")
    two_bars$widths[5] <- unit(4, "cm")
    two_bars$widths[1] <- unit(1, "null")
    
    png("twobars.png", width = 500, height = 500)
    plot(two_bars)
    dev.off()
    
    png("allbars.png", width = 500, height = 500)
    plot(all_bars)
    dev.off()
    

    twobars.png


    allbars.png


    编辑

    另一种方法是将面板保持在固定宽度并使用coord_cartesian 来保持条形宽度不变。

    取如下函数:

    library(ggplot2)
    library(dplyr)
    
    fixed_bars <- function(data, var, ncols = 6) {
      ncols   <- ncols + 2
      data    <- mutate(data, {{var}} := as.factor({{var}}))
      levs    <- length(levels(pull(data, {{var}})))
      extra   <- ncols - levs
      x_range <- range(as.numeric(pull(data, {{var}}))) + c(-0.5, 0.5) * extra
    
      ggplot(data, aes(x = {{var}})) +
        geom_bar() +
        coord_cartesian(xlim = x_range)
    }
    

    允许以下行为:

    mpg %>%
      fixed_bars(class)
    

    
    mpg %>%
      filter(class == "compact" | class == "suv") %>%
      fixed_bars(class)
    

    reprex package (v0.3.0) 于 2020 年 12 月 24 日创建

    【讨论】:

    • 谢谢。首先,我很高兴有办法解决这个问题。其次,我非常愿意投入精力,因为我正在构建用于大规模生产可视化的基础设施,而且这些基础设施必须在外观上保持统一。第三,在您的解决方案中,虽然twobars.png 确实是500x500,但绘图区域(即背景、网格和轴)约为allbars.png 的0.28,其余部分为空白。有没有办法让所有背景都与allbars.png 相同,只是在中心有compactsuv 条?
    • @Emman 在这种情况下,为什么不添加带有空白标签且没有刻度的空条?
    • 这将是一个创造性的解决方案。但是,我不确定如何以编程方式实现这一点(也许在函数中?)。我的意思是,我怎么能自动化呢?在一种情况下,我可能要显示 3 个条形图,在其他情况下,我可能要显示 5 个,等等。
    • @Emman 当然,我可以把它放在一个函数中。您只需要知道您需要容纳的最大酒吧数量吗?
    • 谢谢,@Allan! 1 到 6 之间的任意条数。
    猜你喜欢
    • 2014-12-17
    • 2020-08-30
    • 2015-02-16
    • 2012-07-05
    • 2013-11-13
    • 1970-01-01
    • 2017-04-30
    • 2011-10-05
    相关资源
    最近更新 更多