ggplot2:y 轴标签在绘图区域内左对齐

And*_*gan 5 r ggplot2

我正在寻找一种自动移动 y 轴刻度标签的方法,以便它们实际绘图区域内左对齐。我喜欢 ggplot 中主题组件的总体灵活性,但在尝试找到通用方法来实现此目的时遇到了困难。

我知道给出负右边距 (*gag*)axis.text.y的组合hjust=0可以实现此效果,但必须手动设置负边距以匹配最长 y 轴刻度标签的宽度。

作为示例,请考虑以下代码:

library(ggplot2)

set.seed(0)
dat <- data.frame(x = 1:100, y = (1:100) + runif(100, -10, 10))

p1 <- ggplot(dat, aes(x, y)) + 
  geom_line() +
  scale_y_continuous("", breaks = c(0, 30, 60, 90),
                     labels = c(0, 30, 60, "90 units of something")) +
  theme(axis.text.y = element_text(hjust = 0,
                                   margin = margin(0, -3.1, 0, 0, 'cm')))
Run Code Online (Sandbox Code Playgroud)

我认为它优雅地将 y 轴标签(例如"units of something")合并到图的主体中,但为了实现它,-3.1必须手动找到最后一行中的 (通过反复试验),这雪上加霜:我不仅使用负边距将文本拉到不想要的地方——我还添加了一些神秘的、脆弱的、硬编码的魔法数字。

有谁知道我可以在哪里找到一个更通用和优雅的解决方案来解决这个问题?

Z.L*_*Lin 4

这是使用 grobs 的 hack,它将 y 轴标签从其原始位置移开以重叠绘图区域。

虽然我不认为它非常优雅(ggplotGrob毕竟这是一个需要转换的黑客),但定位不是硬编码的,并且您可以在转换ggplot() 之前指定您想要的任何主题控件。

配置:

library(ggplot2)
library(grid)
library(gtable)

# sample data
set.seed(0)
dat <- data.frame(x=1:100, y=(1:100) + runif(100, -10, 10))

# create ggplot object
p <- ggplot(dat, aes(x, y)) + 
  geom_line() +
  scale_y_continuous("", 
                     breaks = c(0, 30, 60, 90),
                     labels = c(0, 30, 60, "90 units of something")) +
  # left-align y-axis labels
  # you can also specify other theme parameters as desired
  theme(axis.text.y = element_text(hjust = 0))
Run Code Online (Sandbox Code Playgroud)

侵入怪物:

# convert from ggplot to grob object
gp <- ggplotGrob(p)

# locate the grob that corresponds to y-axis labels
y.label.grob <- gp$grobs[[which(gp$layout$name == "axis-l")]]$children$axis    

# remove y-axis labels from the plot, & shrink the space occupied by them
gp$grobs[[which(gp$layout$name == "axis-l")]] <- zeroGrob()
gp$widths[gp$layout$l[which(gp$layout$name == "axis-l")]] <- unit(0, "cm")
Run Code Online (Sandbox Code Playgroud)

为 y 轴刻度/标签定义一个新的 grob,其水平顺序为 [ticks][labels][buffer space]:

# create new gtable
new.y.label.grob <- gtable(heights = unit(1, "npc"))

# place axis ticks in the first column
new.y.label.grob <- gtable_add_cols(new.y.label.grob,
                                    widths = y.label.grob[["widths"]][2])
new.y.label.grob <- gtable_add_grob(new.y.label.grob,
                                    y.label.grob[["grobs"]][[2]],
                                    t = 1, l = 1)

# place axis labels in the second column
new.y.label.grob <- gtable_add_cols(new.y.label.grob,
                                    widths = y.label.grob[["widths"]][1])
new.y.label.grob <- gtable_add_grob(new.y.label.grob,
                                    y.label.grob[["grobs"]][[1]],
                                    t = 1, l = 2)

# add third column that takes up all the remaining space
new.y.label.grob <- gtable_add_cols(new.y.label.grob,
                                    widths = unit(1, "null"))
Run Code Online (Sandbox Code Playgroud)

将新定义的 y 轴标签 grob 添加回绘图 grob,与绘图区域位于同一位置:

gp <- gtable_add_grob(gp,
                      new.y.label.grob,
                      t = gp$layout$t[which(gp$layout$name == "panel")],
                      l = gp$layout$l[which(gp$layout$name == "panel")])
Run Code Online (Sandbox Code Playgroud)

检查结果:

grid.draw(gp)
Run Code Online (Sandbox Code Playgroud)

结果