使用ggplot绘图时,hjust和vjust分别是做什么用的?

214

每次我使用ggplot绘制图形时,我都会花一些时间尝试在像下面这样的行中改变hjust和vjust的值

+ opts(axis.text.x = theme_text(hjust = 0.5))

我希望让坐标轴标签与坐标轴紧密对齐(即所谓的“与坐标轴对齐”),以便它们几乎接触到坐标轴并且完全贴合坐标轴。然而,我实际上并不理解发生了什么。通常情况下,hjust = 0.5hjust = 0.6 相比产生截然不同的结果,例如,我无法通过尝试不同的值来弄清楚问题。

有人能向我指出 hjust 和 vjust 选项是如何工作的详细解释吗?


1
我在第一个答案的评论中给出了一个具体的例子。显然,在0-1之外使用数字是未定义的,这至少解释了为什么hjust=-1会有奇怪的行为。 - William Gunn
2个回答

369

hjustvjust的值只在0到1之间有定义:

  • 0表示左对齐
  • 1表示右对齐

来源:ggplot2,Hadley Wickham,第196页

(是的,我知道在大多数情况下,您可以将其用于超出此范围,但不要指望它以任何特定方式运行。这超出了规范。)

hjust控制水平对齐,vjust控制垂直对齐。

一个例子应该能够说明问题:

td <- expand.grid(
    hjust=c(0, 0.5, 1),
    vjust=c(0, 0.5, 1),
    angle=c(0, 45, 90),
    text="text"
)

ggplot(td, aes(x=hjust, y=vjust)) + 
    geom_point() +
    geom_text(aes(label=text, angle=angle, hjust=hjust, vjust=vjust)) + 
    facet_grid(~angle) +
    scale_x_continuous(breaks=c(0, 0.5, 1), expand=c(0, 0.2)) +
    scale_y_continuous(breaks=c(0, 0.5, 1), expand=c(0, 0.2))

enter image description here


为了理解在更改轴文本中的hjust时会发生什么,您需要了解轴文本的水平对齐方式是相对于整个图形而不是x轴定义的(其中包括y轴文本)。 (在我看来,这很不幸。 相对于轴进行对齐会更有用。)
DF <- data.frame(x=LETTERS[1:3],y=1:3)
p <- ggplot(DF, aes(x,y)) + geom_point() + 
    ylab("Very long label for y") +
    theme(axis.title.y=element_text(angle=0))


p1 <- p + theme(axis.title.x=element_text(hjust=0)) + xlab("X-axis at hjust=0")
p2 <- p + theme(axis.title.x=element_text(hjust=0.5)) + xlab("X-axis at hjust=0.5")
p3 <- p + theme(axis.title.x=element_text(hjust=1)) + xlab("X-axis at hjust=1")

library(ggExtra)
align.plots(p1, p2, p3)

enter image description here


为了探索轴标签的vjust对齐方式会发生什么:

DF <- data.frame(x=c("a\na","b","cdefghijk","l"),y=1:4)
p <- ggplot(DF, aes(x,y)) + geom_point()

p1 <- p + theme(axis.text.x=element_text(vjust=0, colour="red")) + 
        xlab("X-axis labels aligned with vjust=0")
p2 <- p + theme(axis.text.x=element_text(vjust=0.5, colour="red")) + 
        xlab("X-axis labels aligned with vjust=0.5")
p3 <- p + theme(axis.text.x=element_text(vjust=1, colour="red")) + 
        xlab("X-axis labels aligned with vjust=1")


library(ggExtra)
align.plots(p1, p2, p3)

enter image description here


1
对于角度为45度的情况,当我的轴标签长度不同,比如从25到5个字符时,它们既不靠左也不靠右对齐单词边界。请看这里的轴。如果我要使用角度=45度,我该如何使它们靠右对齐并与轴对齐? - William Gunn
1
@WilliamGunn 我建议您发布一个带有您的代码的新问题。 - Andrie
1
由于 opt 已被弃用,我们该如何调整轴标题的位置? - Cyrus Mohammadian
我只想说第一张图表是一个优秀且信息量丰富的可视化。谢谢! - Adam_G
1
@CyrusMohammadian,我已经编辑了这个答案,使其与当前的ggplot2语法兼容。 - Droplet
显示剩余6条评论

21

可能最具有代表性的是 ggplot2 书籍第一版的图 B.1(d)

Image capture of Figure B.1 from page 197 of the first edition of "ggplot2: Elegant Graphics for Data Analysis"

注意:https://ggplot2-book.org/ 上提供的第三版书籍似乎没有这些附录和此图。

然而,事情并不是那么简单。如上所述的hjustvjust是在geom_texttheme_text中的工作方式(有时候)。一种思考方式是将一个框围绕文本,并确定参考点相对于该框的位置,单位为框的大小(因此对于不同大小的文本而言,这个单位也是不同的)。hjust为0.5,vjust为0.5会使框居中于参考点。减小hjust会将框向右移动一个框宽乘以0.5-hjust的距离。因此,当hjust=0时,框的左边缘位于参考点处。增加hjust会将框向左移动一个框宽乘以hjust-0.5的距离。当hjust=1时,框向左移动半个框宽,使右边缘位于参考点处。如果hjust=2,则框的右边缘位于参考点左侧一个框宽的距离(中心点位于参考点左侧2-0.5=1.5个框宽的距离)。对于垂直方向,越小表示向上,越大表示向下。这实际上就是B.1(d)图所说的,但它超出了[0,1]的范围。

但是,有时候这并不起作用。例如

DF <- data.frame(x=c("a","b","cdefghijk","l"),y=1:4)
p <- ggplot(DF, aes(x,y)) + geom_point()

p + opts(axis.text.x=theme_text(vjust=0))
p + opts(axis.text.x=theme_text(vjust=1))
p + opts(axis.text.x=theme_text(vjust=2))

后三个图是相同的。我不知道为什么会这样。而且,如果文本被旋转了,那就更复杂了。考虑一下:

p + opts(axis.text.x=theme_text(hjust=0, angle=90))
p + opts(axis.text.x=theme_text(hjust=0.5 angle=90))
p + opts(axis.text.x=theme_text(hjust=1, angle=90))
p + opts(axis.text.x=theme_text(hjust=2, angle=90))

第一个是将标签左对齐(与底部对齐),第二个是将它们居中于某些框内,使它们的中心线对齐,第三个是将它们右对齐(使它们的右侧与坐标轴相邻)。最后一个呢,我无法以一种连贯的方式解释。它与文本大小、最宽文本的大小有关,还有其他我不确定的因素。


非常感谢这个,这对于角度等于90的情况很有帮助,但我不明白的是,为什么标签的右对齐在角度不再是90而是45时就不起作用了。我理解角度等于45,hjust=0的行为,但角度等于45,hjust=-1就很奇怪。 - William Gunn
@William,我认为@Andrie说得对;hjustvjust仅在0到1之间定义;超出该范围的行为无需有意义。 - Brian Diggs
@Andrie,你说得对。但是我仍然很难在轴标题/文本情况下形成一个连贯的心理模型。对于轴文本,hjust=0将左边缘与刻度线对齐;hjust=0.5居中于刻度线上;hjust=1将右边缘与刻度线对齐(相对于参考点移动框)。但是vjust在一个大小为最高标签的框内对齐。 - Brian Diggs
在轴标签的vjust情况下,所有标签同时对齐。 因此,当vjust = 1时,所有顶部边缘对齐,类似地,当vjust = 0时,所有底部边缘对齐。 这对我来说很有意义。 - Andrie
1
@BrianDiggs 我在我的答案底部添加了另一个图以演示vjust的效果。很抱歉,我不理解你的评论。边界框仍然保持不变 - 只有标签在框内移动。 - Andrie
显示剩余2条评论

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