utiliser des unités PNJ dans annotate ()
J'ai un objet ggplot. Je voudrais ajouter du texte avec annotate(), et je voudrais spécifier les coordonnées du texte en unités npc. Est-ce possible?
Cet exemple minimal montre comment le texte est généralement positionné avec annotate():
library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + annotate("text", x = 30, y = 4.5, label = "hello")
Je voudrais obtenir le même effet, mais au lieu de spécifier xet yen coordonnées natives, je voudrais les spécifier avec des coordonnées npc. Pour les besoins de cet exemple, je ne suis pas préoccupé par la traduction exacte x = 30et y = 4.5en unités PNJ. Je veux juste savoir si les unités PNJ peuvent être utilisées annotate().
Il existe deux stratégies liées, mais elles ne sont pas entièrement satisfaisantes:
On peut utiliser des unités de npc en les spécifiant, disons,
grid::textGrob(). Et on peut ensuite placer le grob avecannotation_custom(), comme dans cette réponse de @baptiste . Mais cette solution est un peu plus lourde que je ne le souhaiterais.Le package "ggpmisc" comprend
geom_text_npc(). Mais cela ne fonctionne pas encore avecannotate(). Autrement dit,annotate("text_npc", ...)ne semble pas fonctionner. [Modifier: cela fonctionne maintenant. Voir le message de Pedro Aphalo ci-dessous.]
Il existe également de nombreux articles connexes. En particulier, Greg Snow a suggéré d' utiliser la grille pour créer une fenêtre avec les dimensions de pcette fenêtre, puis l'annoter. Et @teunbrand a suggéré une méthode qui implique la conversion pen un objet "gtable" (avec ggplotGrob()), puis le dessin de cet objet "gtable". L'une ou l'autre de ces stratégies peut probablement être adaptée à mes objectifs. Mais existe-t-il un moyen plus simple d'utiliser les coordonnées PNJ avec annotate()?
Réponses
Personnellement, j'utiliserais la méthode de Baptiste mais enveloppée dans une fonction personnalisée pour la rendre moins maladroite:
annotate_npc <- function(label, x, y, ...)
{
ggplot2::annotation_custom(grid::textGrob(
x = unit(x, "npc"), y = unit(y, "npc"), label = label, ...))
}
Ce qui vous permet de faire:
p + annotate_npc("hello", 0.5, 0.5)
Notez que cela dessinera toujours votre annotation dans l'espace npc de la fenêtre de chaque panneau dans le tracé, (c'est-à-dire par rapport à la zone grise plutôt qu'à l'ensemble de la fenêtre de traçage), ce qui le rend pratique pour les facettes. Si vous souhaitez dessiner votre annotation en coordonnées PNJ absolues (vous avez donc la possibilité de tracer en dehors de la fenêtre du panneau), vos deux options sont:
- Désactivez le découpage avec
coord_cartesian(clip = "off")et rétroconcevez les coordonnées x, y des coordonnées PNJ données avant de les utiliserannotate. C'est compliqué mais possible - Dessinez-le directement en utilisant
grid. C'est beaucoup plus facile, mais présente l'inconvénient que l'annotation doit être dessinée sur le tracé plutôt que de faire partie du tracé lui-même. Vous pouvez faire cela comme ceci:
annotate_npc_abs <- function(label, x, y, ...)
{
grid::grid.draw(grid::textGrob(
label, x = unit(x, "npc"), y = unit(y, "npc"), ...))
}
Et la syntaxe serait un peu différente:
p
annotate_npc_abs("hello", 0.05, 0.75)
À partir de 'ggpmisc' (> = 0.3.6), le code suivant fonctionne comme prévu (dans CRAN à partir du 10/09/2020).
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")