O que hjust e vjust fazem ao criar um gráfico usando ggplot?

159

Toda vez que faço um gráfico usando ggplot, passo um pouco tentando valores diferentes para hjust e vjust em uma linha como

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

para alinhar os rótulos dos eixos onde os rótulos dos eixos quase tocam o eixo e ficam nivelados contra ele (justificados pelo eixo, por assim dizer). No entanto, eu realmente não entendo o que está acontecendo. Freqüentemente, hjust = 0.5dá resultados tão dramaticamente diferentes de hjust = 0.6, por exemplo, que eu não consegui descobrir isso apenas brincando com valores diferentes.

Alguém pode me indicar uma explicação abrangente de como as opções hjust e vjust funcionam?

William Gunn
fonte
1
Dei um exemplo específico nos comentários da primeira resposta. Aparentemente, usar números fora de 0-1 é indefinido, o que, se não está explicando por que hjust = -1 tem comportamento bizarro, pelo menos explica que o bizarro é esperado.
William Gunn

Respostas:

277

O valor de hjuste vjusté definido apenas entre 0 e 1:

  • 0 significa justificado à esquerda
  • 1 significa justificado

Fonte: ggplot2, Hadley Wickham, página 196

(Sim, eu sei que na maioria dos casos, você pode usá-lo além desse intervalo, mas não espere que ele se comporte de maneira específica. Isso está fora das especificações.)

hjustcontrola a justificação horizontal e vjustcontrola a justificação vertical.

Um exemplo deve deixar isso claro:

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))

insira a descrição da imagem aqui


Para entender o que acontece quando você altera o hjusttexto do eixo in, é necessário entender que o alinhamento horizontal do texto do eixo é definido em relação não ao eixo x, mas a todo o gráfico (onde isso inclui o texto do eixo y). (Isso é, na minha opinião, infeliz. Seria muito mais útil ter o alinhamento em relação ao eixo.)

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)

insira a descrição da imagem aqui


Para explorar o que acontece com o vjustalinhamento dos rótulos dos eixos:

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)

insira a descrição da imagem aqui

Andrie
fonte
1
Portanto, no caso do ângulo = 45, quando eu tenho rótulos de eixos de comprimento variável, digamos de 25 a 5 caracteres, eles não estão alinhados nem justificados à direita ou à esquerda dos limites da palavra. Dê uma olhada nos eixos aqui. Se eu usasse o ângulo = 45, como eu os faria justificados à direita e nivelados contra o eixo?
William Gunn
Eu tentei isso, e eu recebo Error in grid.Call("L_textBounds", as.graphicsAnnot(x$label), x$x, x$y, : Polygon edge not found (zero-width or zero-height?)por vjust = .72e superior.
William Gunn
1
@WilliamGunn Sugiro que você publique uma nova pergunta com seu código.
Andrie
1
Como opt foi descontinuado, como ajustamos a posição do título do eixo?
Cyrus Mohammadian
1
@CyrusMohammadian, editei esta resposta para trabalhar com a sintaxe atual do ggplot2.
Droplet
16

Provavelmente a mais definitiva é a Figura B.1 (d) do livro ggplot2, cujos apêndices estão disponíveis em http://ggplot2.org/book/appendices.pdf .

insira a descrição da imagem aqui

No entanto, não é tão simples assim. hjuste, vjustcomo descrito, há como funciona geom_texte theme_text(às vezes). Uma maneira de pensar nisso é pensar em uma caixa ao redor do texto, e onde o ponto de referência está em relação a essa caixa, em unidades relativas ao tamanho da caixa (e, portanto, diferente para textos de tamanho diferente). An hjustde 0,5 e a vjustde 0,5 centralizam a caixa no ponto de referência. Reduzir hjustmove a caixa para a direita uma quantidade de vezes a largura da caixa 0.5-hjust. Assim hjust=0, quando a borda esquerda da caixa está no ponto de referência. Aumentar hjustmove a caixa deixada em uma quantidade de vezes a largura da caixa hjust-0.5. Quandohjust=1, a caixa é movida para a metade da largura da esquerda, centralizada, o que coloca a borda direita no ponto de referência. Se hjust=2a borda direita da caixa for a largura da caixa à esquerda do ponto de referência (o centro é a 2-0.5=1.5largura da caixa à esquerda do ponto de referência. Na vertical, menos é para cima e mais é para baixo. Isso é efetivamente o que a Figura B.1 (d ) diz, mas extrapola além de [0,1].

Mas, às vezes isso não funciona. Por exemplo

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))

Os três últimos gráficos são idênticos. Não sei por que é isso. Além disso, se o texto for girado, será mais complicado. Considerar

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))

O primeiro tem os rótulos justificados à esquerda (na parte inferior), o segundo os centraliza em alguma caixa para que seus centros se alinhem e o terceiro os justifica à direita (para que seus lados direito se alinhem ao lado do eixo). O último, bem, não sei explicar de maneira coerente. Tem algo a ver com o tamanho do texto, o tamanho do texto mais amplo, e não tenho certeza do que mais.

Brian Diggs
fonte
Muito obrigado por isso, isso ajuda no caso em que angle = 90, mas o que não entendo é por que a justificativa correta dos rótulos não funciona mais quando, em vez de angle = 90, uso angle = 45. Eu entendo o comportamento do ângulo = 45, hjust = 0, mas o ângulo = 45, hjust = -1 é bizarro.
William Gunn
Seu primeiro exemplo, de fato, funciona. O motivo pelo qual você acha que não funciona é porque todos os seus rótulos têm a mesma altura. Tente novamente com DF <- data.frame(x=c("a\na","b","cdefghijk","l"),y=1:4)- ou seja, com uma \nquebra de linha em um dos títulos.
Andrie
@ William, acho que @Andrie está certo; hjuste vjustsão definidos apenas entre 0 e 1; comportamento fora desse intervalo não precisa fazer sentido.
Brian Diggs
@ Andrew, você está certo. Mas ainda tenho dificuldade em criar um modelo mental coerente no título / texto do eixo. Para o texto do eixo, hjust=0alinha a borda esquerda com o tique; hjust=0.5Centros no tique; hjust=1alinha a borda direita com o tique (caixa móvel em relação ao ponto de referência). Mas vjustalinha dentro de uma caixa o tamanho da etiqueta mais alta.
Brian Diggs
@BrianDiggs No caso dos vjustrótulos dos eixos, todos os rótulos são alinhados simultaneamente. Portanto, todas as arestas superiores se alinham quando vjust=1e da mesma forma todas as arestas inferiores quando vjust=0. Isso faz muito sentido pra mim.
Andrie