ggplot2 - außerhalb des Plots mit Anmerkungen versehen

73

Ich möchte Stichprobengrößenwerte mit Punkten in einem Diagramm verknüpfen. Ich kann geom_textdie Zahlen in der Nähe der Punkte positionieren, aber das ist chaotisch. Es wäre viel sauberer, sie am äußeren Rand des Grundstücks auszurichten.

Zum Beispiel habe ich:

df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))

ggplot(df,aes(x=x,y=y,label=n))+geom_point()+geom_text(size=8,hjust=-0.5)

Welches produziert diese Handlung: Geben Sie hier die Bildbeschreibung ein

Ich würde so etwas bevorzugen: Geben Sie hier die Bildbeschreibung ein

Ich weiß, dass ich ein zweites Diagramm erstellen und verwenden kann grid.arrange(a la this post ), aber es wäre mühsam, den Abstand der textGrobs zu bestimmen, um mit der y-Achse übereinzustimmen. Gibt es einen einfacheren Weg, dies zu tun? Vielen Dank!

jslefche
quelle
1
Dies könnte mit der Sekundärachse geschehen, von der ich denke, dass sie sich in der Entwicklung befindet. Aber wenn Sie es versuchen möchten, folgen Sie diesem Link groups.google.com/forum/?fromgroups=#!topic/ggplot2/_3Pm-JEoCqE
Luciano Selzer
Hmm interessant ... Ich habe mich gefragt, ob Hadley dies umsetzen würde. Beim Laden werden jedoch einige seltsame Fehler angezeigt devtools: call: if (!version_match) { error: argument is of length zero.
jslefche
Ich kann nur sagen, dass devtools für mich funktioniert. Sie sollten versuchen, eine Frage zu stellen, wenn Sie sie nicht lösen können.
Luciano Selzer
Ich habe es umgangen, indem ich ggplot2 0.9.2.1 von der .zip-Datei auf CRAN installiert habe. Jetzt wird der im Link von @LucianoSelzer bereitgestellte Code nicht ausgeführt (mehrere Argumente für die guide_axis). Vielleicht zu viel für heute Nacht? Ich werde darauf schlafen und sehen, ob ich es am Morgen nicht herausfinden kann
jslefche

Antworten:

62

Sie müssen kein zweites Diagramm zeichnen. Sie können annotation_customGrobs überall innerhalb oder außerhalb des Plotbereichs positionieren. Die Positionierung der Grobs erfolgt anhand der Datenkoordinaten. Unter der Annahme, dass "5", "10", "15" mit "cat1", "cat2", "cat3" übereinstimmen, wird für die vertikale Positionierung der textGrobs gesorgt - die y-Koordinaten Ihrer drei textGrobs werden durch die angegeben y-Koordinaten der drei Datenpunkte. Standardmäßig werden ggplot2Clips in den Plotbereich eingefügt, der Ausschnitt kann jedoch überschrieben werden. Der relevante Spielraum muss erweitert werden, um Platz für den Grob zu schaffen. Das Folgende (unter Verwendung von ggplot2 0.9.2) ergibt ein Diagramm, das Ihrem zweiten Diagramm ähnlich ist:

library (ggplot2)
library(grid)

df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))

p <- ggplot(df, aes(x,y)) + geom_point() +            # Base plot
     theme(plot.margin = unit(c(1,3,1,1), "lines"))   # Make room for the grob

for (i in 1:length(df$n))  {
p <- p + annotation_custom(
      grob = textGrob(label = df$n[i], hjust = 0, gp = gpar(cex = 1.5)),
      ymin = df$y[i],      # Vertical position of the textGrob
      ymax = df$y[i],
      xmin = 14.3,         # Note: The grobs are positioned outside the plot area
      xmax = 14.3)
 }    

# Code to override clipping
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)

Geben Sie hier die Bildbeschreibung ein

Sandy Muspratt
quelle
9
Ist es nicht einfacher, eine geom_text-Ebene bei x = Inf, hjust> = 1 zu haben und das Abschneiden zu deaktivieren?
baptiste
14
@jslefche, Sie sollten beachten, dass die von @baptiste angebotene Lösung viel einfacher ist. p = p + geom_text(aes(label = n, x = Inf, y = y), hjust = -1). Schalten Sie dann den Ausschnitt aus. Obwohl die Ausrichtung leicht abweichen kann.
Sandy Muspratt
2
und wie schaltet man das Clipping aus?
Thomas Browne
1
@ThomasBrowne Informationen zum Deaktivieren des Clippings finden Sie in den letzten drei Codezeilen oben.
Sandy Muspratt
2
Leider ändert sich die x-Position, an der Sie den Text positionieren müssen, mit dem Bereich der x-Achse. Sie müssen also einen Wert von x verwenden, der relativ zum Achsenbereich ist. Hier ist meine Lösung. Ich erhalte den berechneten Achsenbereich x ggplot mit xlim.range <- ggplot_build(plot)$panel$ranges[[1]]$x.range. Dann benutze ich dies als x Position: x = xlim.range[1] - diff(xlim.range)/10 und es funktioniert!
Bakaburg
62

Dies ist jetzt mit ggplot2 3.0.0 unkompliziert, da das Ausschneiden jetzt in Plots deaktiviert werden kann, indem das clip = 'off'Argument in Koordinatenfunktionen wie coord_cartesian(clip = 'off')oder verwendet wird coord_fixed(clip = 'off'). Hier ist ein Beispiel unten.

    # Generate data
    df <- data.frame(y=c("cat1","cat2","cat3"),
                     x=c(12,10,14),
                     n=c(5,15,20))

    # Create the plot
    ggplot(df,aes(x=x,y=y,label=n)) +
      geom_point()+
      geom_text(x = 14.25, # Set the position of the text to always be at '14.25'
                hjust = 0,
                size = 8) +
      coord_cartesian(xlim = c(10, 14), # This focuses the x-axis on the range of interest
                      clip = 'off') +   # This keeps the labels from disappearing
      theme(plot.margin = unit(c(1,3,1,1), "lines")) # This widens the right margin

Geben Sie hier die Bildbeschreibung ein

bschneidr
quelle
Wie können Sie dies für die x-Achse eines Box-Plots tun?
Ktyagi
1
Dies ist definitiv die einfachste Option, danke! @ktyagi vielleicht haben Sie dies jetzt sortiert, aber Sie würden genau das gleiche Argument verwenden, aber ylimstattdessen xlim
angeben
2
Der Vollständigkeit halber clip = offkann auch @ genannt werden coord_flip(und ich nehme auch coord_ x an). Das Hinzufügen coord_cartesian(clip = 'off')war für mich keine Lösung, wie ich es brauchte coord_flip.
Leroy Tyrone
Das ist ein guter Punkt, danke @LeroyTyrone. Ich habe gerade die Antwort aktualisiert, um dies widerzuspiegeln.
Bschneidr
Es ist erwähnenswert, dass dies nicht zu funktionieren scheintcoord_polar
MokeEire
5

Einfachere Lösung basierend auf grid

require(grid)

df = data.frame(y = c("cat1", "cat2", "cat3"), x = c(12, 10, 14), n = c(5, 15, 20))

p <- ggplot(df, aes(x, y)) + geom_point() + # Base plot
theme(plot.margin = unit(c(1, 3, 1, 1), "lines"))

p

grid.text("20", x = unit(0.91, "npc"), y = unit(0.80, "npc"))
grid.text("15", x = unit(0.91, "npc"), y = unit(0.56, "npc"))
grid.text("5", x = unit(0.91, "npc"), y = unit(0.31, "npc"))
Stepan S. Sushko
quelle
5
Auf den ersten Blick viel einfacher, aber ... die Schriftart stimmt nicht mit den Standardeinstellungen von ggplot2 überein, sodass Sie mit diesen Einstellungen herumspielen müssen und es aufgrund der Verwendung von NPC-Einheiten schwieriger ist, den Text zu positionieren. Wahrscheinlich genauso komplex.
Mooks