2012-10-30 15 views
15

Titel ziemlich gut deckt es.Wie positioniere ich zwei Legenden unabhängig in ggplot

Ich habe zwei Legenden, die sich auf die Größe und Farbe beziehen, und möchte einen, sagen wir, oben und einen innerhalb des Graphen haben.

Ist dies möglich, und wenn ja, wie

TIA

+0

Ich denke nicht, dass es möglich ist (wo die Legenden platziert werden, wird durch das Thema gesteuert, und die Teile, die die Legendenposition definieren, nehmen nur einen einzigen Wert an). Ich bin mir aber nicht so sicher, dass es nicht möglich ist, eine Antwort zu geben. –

+0

Raten Sie, wenn es war, wäre einer der Experten jetzt auf – pssguy

+0

@pssguy gewesen, es kann mit etwas Fiedeln getan werden. Um die Legenden steuern zu können, müssen Sie separate Legenden extrahieren, die dann in einem Diagramm angeordnet werden können, das anfangs keine Legende enthält. –

Antwort

3

Von meinem Verständnis, im Grunde gibt es über Legenden in ggplot2 sehr begrenzte Kontrolle. Hier ist ein Absatz aus dem Buch von Hadley (Seite 111):

ggplot2 versucht, die kleinstmögliche Anzahl von Legenden zu verwenden, die die in der Handlung verwendete Ästhetik genau wiedergeben. Dazu werden Legenden kombiniert, wenn eine Variable mit mehr als einer Ästhetik verwendet wird. Abbildung 6.14 zeigt ein Beispiel für die Punkte geom: Wenn sowohl Farbe als auch Form der gleichen Variablen zugeordnet sind, ist nur eine einzige Legende erforderlich. Damit Legenden zusammengeführt werden können, müssen sie denselben Namen haben (den gleichen Legendentitel). Wenn Sie den Namen einer der zusammengeführten Legenden ändern, müssen Sie sie daher für alle Legenden ändern.

+0

Danke für den Auszug. Alle Beispiele zeigen Legenden in der gleichen Position – pssguy

28

Dies kann durch Extrahieren separater Legenden aus Plots und anschließendes Arrangieren der Legenden in der entsprechenden Plot erfolgen. Der Code hier verwendet Funktionen aus dem gtable-Paket, um die Extraktion zu tun, dann Funktionen aus dem gridExtra Paket, um das Arrangieren zu tun. Ziel ist es, ein Diagramm zu erstellen, das eine Farblegende und eine Größenlegende enthält. Extrahieren Sie zuerst die Farblegende aus einem Diagramm, das nur die Farblegende enthält. Zweitens, extrahieren Sie die Größenlegende aus einem Diagramm, das nur die Größenlegende enthält. Zeichnen Sie drittens ein Diagramm, das keine Legende enthält. Viertens, ordnen Sie die Handlung und die zwei Legenden zu einer neuen Handlung zusammen.

# Some data 
df <- data.frame(
    x = 1:10, 
    y = 1:10, 
    colour = factor(sample(1:3, 10, replace = TRUE)), 
    size = factor(sample(1:3, 10, replace = TRUE))) 

library(ggplot2) 
library(gridExtra) 
library(gtable) 
library(grid) 

    ### Step 1 
# Draw a plot with the colour legend 
(p1 <- ggplot(data = df, aes(x=x, y=y)) + 
    geom_point(aes(colour = colour)) + 
    theme_bw() + 
    theme(legend.position = "top")) 

# Extract the colour legend - leg1 
leg1 <- gtable_filter(ggplot_gtable(ggplot_build(p1)), "guide-box") 

    ### Step 2 
# Draw a plot with the size legend 
(p2 <- ggplot(data = df, aes(x=x, y=y)) + 
    geom_point(aes(size = size)) + 
    theme_bw()) 

# Extract the size legend - leg2 
leg2 <- gtable_filter(ggplot_gtable(ggplot_build(p2)), "guide-box") 

    # Step 3 
# Draw a plot with no legends - plot 
(plot <- ggplot(data = df, aes(x=x, y=y)) + 
    geom_point(aes(size = size, colour = colour)) + 
    theme_bw() + 
    theme(legend.position = "none")) 

    ### Step 4 
# Arrange the three components (plot, leg1, leg2) 
# The two legends are positioned outside the plot: 
# one at the top and the other to the side. 
plotNew <- arrangeGrob(leg1, plot, 
     heights = unit.c(leg1$height, unit(1, "npc") - leg1$height), ncol = 1) 

plotNew <- arrangeGrob(plotNew, leg2, 
      widths = unit.c(unit(1, "npc") - leg2$width, leg2$width), nrow = 1) 

grid.newpage() 
grid.draw(plotNew) 

# OR, arrange one legend at the top and the other inside the plot. 
plotNew <- plot + 
     annotation_custom(grob = leg2, xmin = 7, xmax = 10, ymin = 0, ymax = 4) 

plotNew <- arrangeGrob(leg1, plotNew, 
    heights = unit.c(leg1$height, unit(1, "npc") - leg1$height), ncol = 1) 

grid.newpage() 
grid.draw(plotNew) 

enter image description here

enter image description here

+0

Hallo Sandy. Dies ist ein eindrucksvolles Beispiel. Können Sie die Logik für die Verwendung des 'heights'-Arguments auf' arrangeGrob' abbrechen, zum Beispiel in 'plotNew <- arrayGrob (leg1, plot, heights = unit.c (leg1 $ height, unit (1," npc ") - leg1 $ height), ncol = 1) '? Ich bekomme, dass "Höhen" als Argument an "Grid.layout" übergeben wird, aber ich habe Probleme zu sehen, wie es hier verwendet wird. Vielen Dank. –

+0

Hi @Faheem, Es gibt zwei Diagramme, die vertikal angeordnet werden: 'leg1' und' plot'; und daher zwei Höhen in der Funktion 'unit.c()'. 'leg1' hat eine absolute Höhe und ist gegeben durch' leg1 $ height'. Die zweite Höhe, "Einheit (1," npc ") - leg1 $ height", subtrahiert die Legendenhöhe von der Höhe des Geräts, um die verfügbare Höhe für "Plot" zu erhalten. Im ersten Beispiel gilt eine ähnliche Logik für die Breite. Es gibt zwei Grobbilder, die gezeichnet werden sollen: die Handlung und die Legende. Daher zwei Breiten in der Funktion 'unit.c()'; eine für 'plotNew' und die zweite für' leg2'. –

+0

Danke, Sandy. Noch eine Frage - woher weißt du, dass die Höhe des Geräts "Einheit (1," npc ") ist? Es wäre nützlich, wenn Sie einige dieser Informationen zu Ihrer Frage hinzufügen würden. Sie könnten (a) das 'heights'-Argument und' width'-Argumente an 'grid.layout' übergeben, (b) dass' unit (1, "npc") 'die Höhe des Geräts ist und daher (c) z.B 'leg1 $ height' und' unit (1, "npc") - leg1 $ height "sind die Höhen der Legende bzw. des Hauptplots. Ich kann das hinzufügen, wenn Sie möchten. –

6

Hier ist eine andere Lösung ggplot2 und cowplot (= ggplot2 extension) unter Verwendung von Paketen.

Der Ansatz ähnelt Sandys, da er die Legende als separate Objekte entfernt und Sie die Platzierung unabhängig voneinander durchführen können. Es wurde hauptsächlich für mehrere Legenden entworfen, die zu zwei oder mehr Plots in einem Raster von Plots gehören.

Die Funktion g_legend, die herby verwendet wird, wurde aus dieser answer entnommen.

Die Idee ist wie folgt:

  1. erstellen Plot1, Plot2, ..., PlotX ohne Legenden
  2. erstellen Plot1, Plot2, ..., PlotX mit Legenden
  3. Extract Legenden aus Schritt 2 in einzelne Objekte
  4. Legende Gitter einrichten und ordnen Legenden sie so, wie Sie
  5. wollen erstellen Raster Plots und Legenden kombiniert

Es scheint irgendwie kompliziert und zeit-/code-komplex, aber einmal eingerichtet, kannst du es für jede Art von Plot/Legendenanpassung anpassen und verwenden.

library(ggplot2) 
library(cowplot) 

# set up function 
g_legend<-function(a.gplot){ 
    tmp <- ggplot_gtable(ggplot_build(a.gplot)) 
    leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box") 
    legend <- tmp$grobs[[leg]] 
    return(legend) } 

# Some data 
df <- data.frame(
    Name = factor(rep(c("A", "B", "C"), 12)), 
    Month = factor(rep(1:12, each=3)), 
    Temp = sample(0:40, 12), 
    Precip = sample(50:400, 12)) 

# create plot1 
plot1 <- ggplot(df, aes(Month, Temp, fill = Name)) + 
    geom_point(show.legend = F, aes(group = Name, colour = Name), 
     size = 3, shape = 17) + 
    geom_smooth(method = "loess", se = F, 
     aes(group = Name, colour = Name), 
     show.legend = F, size = 0.5, linetype = "dashed") 

# create plot2 
plot2 <- ggplot(df, aes(Month, Precip, fill = Name)) + 
    geom_bar(stat = "identity", position = "dodge", show.legend = F) + 
    geom_smooth(method = "loess", se = F, 
     aes(group = Name, colour = Name), 
     show.legend = F, size = 1, linetype = "dashed") + 
    scale_fill_grey() 

# create legend1 
legend1 <- ggplot(df, aes(Month, Temp)) + 
    geom_point(show.legend = T, aes(group = Name, colour = Name), 
     size = 3, shape = 17) + 
    geom_smooth(method = "loess", se = F,aes(group = Name, colour = Name), 
     show.legend = T, size = 0.5, linetype = "dashed") + 
    labs(colour = "Station") + 
    theme(legend.text=element_text(size=8), 
      legend.title = element_text(face = "italic", 
       angle = -0, size = 10)) 

# create legend2 
legend2 <- ggplot(df, aes(Month, Precip, fill = Name)) + 
    geom_bar(stat = "identity", position = "dodge", show.legend = T) + 
    scale_fill_grey() + 
    guides(fill = 
     guide_legend(title = "", 
       title.theme = element_text(face = "italic", 
        angle = -0, size = 10))) + 
    theme(legend.text=element_text(size=8)) 


# extract "legends only" from ggplot object 
legend1 <- g_legend(legend1) 
legend2 <- g_legend(legend2) 

# setup legends grid 
legend1_grid <- cowplot::plot_grid(legend1, align = "v", nrow = 2) 

# add second legend to grid, specifying its location 
legends <- legend1_grid + 
    ggplot2::annotation_custom(grob = legend2, 
      xmin = 0.5, xmax = 0.5, ymin = 0.55, ymax = 0.55) 

# plot "plots" + "legends" (with legends in between plots) 
cowplot::plot_grid(plot1, legends, plot2, ncol = 3, 
    rel_widths = c(0.45, 0.1, 0.45)) 

Beispiele:

Example http://i65.tinypic.com/jl1lef.png

Ändern der Reihenfolge der endgültigen plot_grid() Anruf bewegt die Legenden nach rechts:

cowplot::plot_grid(plot1, plot2, legends, ncol = 3, 
        rel_widths = c(0.45, 0.45, 0.1)) 

Example2 http://i68.tinypic.com/314yn9i.png

Verwandte Themen