użyj jednostek NPC w annotate ()

Sep 04 2020

Mam obiekt ggplot. Chciałbym dodać tekst z annotate(), a współrzędne tekstu chciałbym określić w jednostkach NPC. czy to możliwe?

Ten minimalny przykład pokazuje, jak tekst jest zwykle pozycjonowany za pomocą annotate():

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

Chciałbym osiągnąć ten sam efekt, ale zamiast określać xi ywe współrzędnych natywnych, chciałbym określić je za pomocą współrzędnych NPC. Na potrzeby tego przykładu nie przejmuję się dokładnym tłumaczeniem x = 30i y = 4.5na jednostki NPC. Chcę tylko wiedzieć, czy annotate()w ogóle można używać jednostek NPC .

Istnieją dwie powiązane strategie, ale nie są one całkowicie satysfakcjonujące:

  1. Można używać jednostek NPC, określając je, mówią grid::textGrob(). I wtedy można umieścić groba za pomocą annotation_custom(), jak w tej odpowiedzi @baptiste . Ale to rozwiązanie jest nieco bardziej uciążliwe, niż bym chciał.

  2. Pakiet "ggpmisc" zawiera geom_text_npc(). Ale to jeszcze nie działa z annotate(). Oznacza to, annotate("text_npc", ...)że nie wydaje się działać. [Edytuj: teraz działa. Zobacz wiadomość Pedro Aphalo poniżej.]

Istnieje również wiele powiązanych postów. W szczególności Greg Snow zasugerował użycie siatki do utworzenia rzutni z wymiarami, pa następnie opisania tej rzutni. I @teunbrand zaproponował metodę, która pociąga za sobą konwersji pdo „gtable” obiektu (z ggplotGrob()), a następnie rysunek, który „gtable” obiekt. Każdą z tych strategii można prawdopodobnie dostosować do moich celów. Ale czy istnieje prostszy sposób używania współrzędnych NPC z annotate()?

Odpowiedzi

6 AllanCameron Sep 04 2020 at 20:31

Osobiście użyłbym metody Baptiste, ale owiniętej w niestandardową funkcję, aby była mniej niezgrabna:

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

Co pozwala ci:

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

Zauważ, że zawsze będzie to narysować twoją adnotację w przestrzeni NPC w rzutni każdego panelu na wykresie (tj. Względem szarego zacieniowanego obszaru, a nie całego okna kreślenia), co sprawia, że ​​jest to przydatne dla aspektów. Jeśli chcesz narysować swoją adnotację w bezwzględnych współrzędnych NPC (więc masz możliwość kreślenia poza rzutnią panelu), masz dwie opcje:

  1. Wyłącz obcinanie za pomocą coord_cartesian(clip = "off")i dokonaj inżynierii wstecznej współrzędnych x, y z podanych współrzędnych NPC przed użyciem annotate. To skomplikowane, ale możliwe
  2. Narysuj go prosto za pomocą grid. Jest to o wiele łatwiejsze, ale ma tę wadę, że adnotacja musi być narysowana na fabule, a nie być częścią samej fabuły. Możesz to zrobić w ten sposób:
annotate_npc_abs <- function(label, x, y, ...) 
{
  grid::grid.draw(grid::textGrob(
    label, x = unit(x, "npc"), y = unit(y, "npc"), ...))
}

A składnia byłaby trochę inna:

p 
annotate_npc_abs("hello", 0.05, 0.75)

1 PedroAphalo Sep 11 2020 at 00:20

Od „ggpmisc” (> = 0.3.6) następujący kod działa zgodnie z oczekiwaniami (w CRAN od 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")