【问题标题】:Avoiding axis tick label collision in faceted ggplots避免多面 ggplots 中的轴刻度标签冲突
【发布时间】:2017-01-10 17:42:28
【问题描述】:

在多面板/多面绘图中,我喜欢将面板挤压在一起并且它们之间没有空间的情况,例如使用theme(panel.spacing=grid::unit(0,"lines"))(Edward Tufte 说这很好,因为面板间的空间会产生分散注意力的视觉效果,以及浪费数据空间,而且我已经喝了这个特殊的 Kool-Aid。)

问题在于,根据分面行/列中值的精确范围,相邻分面的轴标签可能重叠。例如,在此图中,顶部面板中的底部刻度标签与中间面板中的顶部刻度标签之间存在冲突。

dd <- data.frame(x=rep(1:3,3),
                 y=c(0.1,0.2,0.3,
                     0.1,0.4,0.6,
                     1,2,3),
                 f=factor(rep(letters[1:3],each=3)))
library(ggplot2)
ggplot(dd,aes(x,y))+
   facet_grid(f~.,scale="free")+
   geom_point()+
   theme_bw(base_size=24)+
   theme(panel.spacing=grid::unit(0,"lines"))
ggsave("tmp1.png",width=4,height=6)

我想为这个问题构建一个通用的、方便的解决方案 - 将每个方面的限制扩展适当的量(每个方面都会有所不同,因为范围是异构的)但抑制(至少)标签和(可能)极值的刻度线。我过去通过在scale_y_continuous 中设置一个特殊用途的breaks 函数以一种超级hacky 的方式做到了这一点。我可能已经想到了一些其他方法来做到这一点(如果我能让它们工作,我会将它们作为答案发布),但我正在寻找(a)相当强大的通用函数来指定 labels 和/或breaks

这与 Automate tick max and min in faceted ggplot 不同,后者只需要分面的最大值/最小值。

这通常很难做到,并且可能无法完全解决;我曾想过只删除极端标签,但如果只有两个或三个刻度标签,那将失败。 expand_limits() 可能有一个解决方案,但跨方面很难做到...

【问题讨论】:

  • 也应该将此作为问题提交到 ggplot2 的 github 存储库中。
  • 也许检查范围的中断并与标签 cex 进行比较以找到触发抑制极端标签的不可接受的最小比率?甚至可能触发您以前的黑客攻击的更通用版本
  • 我知道这没什么用,但是......真的很遗憾,使用 ggplot2,你必须学习一个全新(一次性)的基础知识OO系统只是为了修改这样的小细节。使用 lattice,您只需放入自定义的 prepanel()yscale.components() 函数即可完成。我确实期待人们在这里提出的任何解决方案。
  • @JoshO'Brien ,我认为通过scale_y_continuousbreakslabels 参数有可能获得合理的解决方案。更多的是放在那里的问题(就像prepanel() ...)

标签: r ggplot2 axis-labels


【解决方案1】:

编辑更新到 ggplot2 ver 3.0.0

一种可能是修改构建数据。可以采用原始图的限制,并应用乘法扩展因子。主要和次要突破的相对位置也需要调整。请注意,该函数允许选择要应用扩展的面板。

这与在scale_y_continuous 中使用expand 有什么区别(除了能够选择面板)?此功能将中断(以及刻度线和网格线)保留为原始状态。只是它们占用的空间更少。 expand,然而,会压缩比例,但如果可以的话,ggplot 会添加新的标签、网格线和刻度线。

破坏该功能并不需要太多 - 众所周知,ggplot 在最近的版本中可以更改构建数据元素的名称。

dd <- data.frame(x=rep(1:3,3),
                 y=c(0.1,0.2,0.3,
                     0.1,0.4,0.6,
                     1,2,3),
                 f=factor(rep(letters[1:3],each=3)))
library(ggplot2)


p = ggplot(dd,aes(x,y))+
   facet_grid(f~.,scale="free")+
   geom_point()+
   theme_bw(base_size=24)+
   theme(panel.spacing=grid::unit(0,"lines"))


expand = function(plot, mult = 0.1, applyTo) {
# Get the build data
gd = ggplot_build(plot)

# Get the original limits,
# and calculate the new limits,
# expanded according to the multiplicative factor
limits <- sapply(gd$layout$panel_params, "[[", "y.range")    # Original limits
fac = mult*(limits[2,] - limits[1, ])  
newlimits = rbind(limits[1, ] - fac, limits[2, ] + fac)

# The range for the new limits
range = newlimits[2, ] - newlimits[1, ]

# Calculate the new y.major and y.minor relative positions
# and put them along with the new limits back into the build data

N = dim(gd$layout$panel_params)[1]  # Number of panels

for(i in applyTo) {
y.major = (gd$layout$panel_params[[i]]$y.major_source - newlimits[1, i]) / range[i]
y.minor = (gd$layout$panel_params[[i]]$y.minor_source - newlimits[1, i]) / range[i]

gd$layout$panel_params[[i]]$y.range = newlimits[, i]

gd$layout$panel_params[[i]]$y.major = y.major
gd$layout$panel_params[[i]]$y.minor = y.minor
}

# Get the gtable
ggplot_gtable(gd)
}


# Plot it
grid::grid.draw(expand(p, mult = 0.1, applyTo = 1:2))

原创

已修改

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-24
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多