use unidades npc em annotate ()

Sep 04 2020

Eu tenho um objeto ggplot. Gostaria de adicionar algum texto com annotate()e gostaria de especificar as coordenadas do texto em unidades npc. Isso é possível?

Este exemplo mínimo demonstra como o texto é normalmente posicionado com annotate():

library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + annotate("text", x = 30, y = 4.5, label = "hello")

Gostaria de obter o mesmo efeito, mas em vez de especificar xe yem coordenadas nativas, gostaria de especificá-las com coordenadas npc. Para o propósito deste exemplo, não estou preocupado em traduzir exatamente x = 30e y = 4.5em unidades npc. Eu só quero saber se as unidades npc podem ser usadas em annotate()tudo.

Existem duas estratégias relacionadas, mas não são totalmente satisfatórias:

  1. Pode-se usar unidades npc especificando-as como, digamos grid::textGrob(),. E pode-se então colocar o grob com annotation_custom(), como nesta resposta de @baptiste . Mas essa solução é um pouco mais complicada do que eu gostaria.

  2. O pacote "ggpmisc" inclui geom_text_npc(). Mas ainda não funciona com annotate(). Ou seja, annotate("text_npc", ...)não parece funcionar. [Editar: agora funciona. Veja a mensagem de Pedro Aphalo abaixo.]

Existem também muitas postagens relacionadas. Em particular, Greg Snow sugeriu o uso de grade para criar uma janela de visualização com as dimensões pe, a seguir, anotando essa janela de visualização. E @teunbrand sugeriu um método que envolve a conversão pem um objeto "gtable" (com ggplotGrob()) e, em seguida, o desenho desse objeto "gtable". Qualquer uma dessas estratégias provavelmente pode ser adaptada aos meus propósitos. Mas existe uma maneira mais direta de usar coordenadas npc com annotate()?

Respostas

6 AllanCameron Sep 04 2020 at 20:31

Pessoalmente, eu usaria o método de Baptiste, mas envolvido em uma função personalizada para torná-lo menos desajeitado:

annotate_npc <- function(label, x, y, ...)
{
  ggplot2::annotation_custom(grid::textGrob(
    x = unit(x, "npc"), y = unit(y, "npc"), label = label, ...))
}

O que permite que você faça:

p + annotate_npc("hello", 0.5, 0.5)

Observe que isso sempre desenhará sua anotação no espaço npc da janela de visualização de cada painel no gráfico (ou seja, em relação à área sombreada em cinza ao invés de toda a janela de plotagem), o que o torna útil para facetas. Se você deseja desenhar sua anotação em coordenadas npc absolutas (para ter a opção de plotar fora da janela de visualização do painel), suas duas opções são:

  1. Desative o recorte coord_cartesian(clip = "off")e faça engenharia reversa das coordenadas x, y a partir das coordenadas npc fornecidas antes de usar annotate. Isso é complicado, mas possível
  2. Desenhe diretamente usando grid. Isso é muito mais fácil, mas tem a desvantagem de que a anotação deve ser desenhada sobre o enredo em vez de fazer parte do próprio enredo. Você poderia fazer isso assim:
annotate_npc_abs <- function(label, x, y, ...) 
{
  grid::grid.draw(grid::textGrob(
    label, x = unit(x, "npc"), y = unit(y, "npc"), ...))
}

E a sintaxe seria um pouco diferente:

p 
annotate_npc_abs("hello", 0.05, 0.75)

1 PedroAphalo Sep 11 2020 at 00:20

A partir de 'ggpmisc' (> = 0.3.6), o código a seguir funciona conforme o esperado (no CRAN a partir de 2020-09-10).

library(ggpmisc)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
# default justification is "inward"
p + annotate("text_npc", npcx = 0.8, npcy = 0.75, label = "hello")
# same justification as default for "geom_text()"
p + annotate("text_npc", npcx = 0.8, npcy = 0.75, label = "hello",
             hjust = "center", vjust = "middle")