Что делают hjust и vjust при создании графика с использованием ggplot?

159

Каждый раз, когда я строю график с использованием ggplot, я трачу немного времени, пробуя разные значения для hjust и vjust в такой строке, как

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

чтобы метки оси выровнялись так, чтобы метки оси почти касались оси, и находились на одном уровне с ней (так сказать, по оси). Тем не менее, я не очень понимаю, что происходит. Часто hjust = 0.5дает такие резко отличающиеся результаты от hjust = 0.6, например, что я не смог понять это, просто поиграв с разными значениями.

Кто-нибудь может дать мне исчерпывающее объяснение того, как работают варианты hjust и vjust?

Уильям Ганн
источник
1
Я дал конкретный пример в комментариях к первому ответу. Очевидно, использование чисел вне 0-1 не определено, что, если не объяснить, почему hjust = -1 ведет себя странно, по крайней мере, объясняет, что следует ожидать странного поведения.
Уильям Ганн

Ответы:

277

Значение hjustи vjustопределяется только от 0 до 1:

  • 0 означает выравнивание по левому краю
  • 1 означает правильное выравнивание

Источник: ggplot2, Хэдли Уикхем, стр. 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))

введите описание изображения здесь


Чтобы понять, что происходит при изменении 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)

введите описание изображения здесь


Чтобы узнать, что происходит с 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)

введите описание изображения здесь

Andrie
источник
1
Таким образом, в случае угла = 45, когда у меня есть метки оси различной длины, скажем, от 25 до 5 символов, они не выровнены по правому или левому краю слова. Посмотрите на оси здесь. Если бы я использовал угол = 45, как бы я сделал их правильными и выровненными по оси?
Уильям Ганн
Я попробовал это, и я получаю Error in grid.Call("L_textBounds", as.graphicsAnnot(x$label), x$x, x$y, : Polygon edge not found (zero-width or zero-height?)за vjust = .72и выше.
Уильям Ганн
1
@WilliamGunn Я предлагаю вам опубликовать новый вопрос с вашим кодом.
Андри
1
поскольку opt устарела, как мы можем отрегулировать положение заголовка оси?
Кир Мухаммедян
1
@CyrusMohammadian, я отредактировал этот ответ для работы с текущим синтаксисом ggplot2.
Капелька
16

Вероятно, наиболее точным является рисунок B.1 (d) книги ggplot2, приложения к которой доступны по адресу http://ggplot2.org/book/appendices.pdf .

введите описание изображения здесь

Однако не все так просто. hjustи vjustкак описано там, как это работает geom_textи theme_text(иногда). Один из способов думать об этом - думать о рамке вокруг текста и о том, где контрольная точка находится относительно этой рамки, в единицах относительно размера рамки (и, таким образом, отличается для текстов разного размера). hjust0,5 и vjust0,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 просто странно.
Уильям Ганн
Ваш первый пример действительно работает. Вы думаете, что это не работает, потому что все ваши метки имеют одинаковую высоту. Попробуйте еще раз с DF <- data.frame(x=c("a\na","b","cdefghijk","l"),y=1:4)- то есть с \nпереносом строки в одном из названий.
Андри
@ Уильям, я думаю, что @ Андри правильно понял; hjustи vjustопределены только между 0 и 1; поведение вне этого диапазона не должно иметь смысла.
Брайан Диггс
@ Андрей, ты прав. Но мне все еще трудно создать целостную мысленную модель в заголовке оси / текстовом случае. Для текста оси hjust=0выравнивание левого края по метке; hjust=0.5центры на тике; hjust=1выравнивает правый край с меткой (перемещение блока относительно контрольной точки). Но vjustвыровняйте внутри коробки размер самого высокого ярлыка.
Брайан Диггс
@BrianDiggs В случае vjustметок оси все метки одновременно выровнены друг с другом. Таким образом, все верхние края выравниваются, когда, vjust=1а также все нижние края, когда vjust=0. Это имеет смысл для меня.
Андри