Jak ustawić dwie legendy niezależnie w ggplot

Tytuł całkiem dobrze to zakrywa.

Mam dwie legendy, odnoszące się do rozmiaru i koloru, i chciałbym mieć jedną, powiedzmy, na górze i jedną w grafie.

Czy jest to możliwe, a jeśli tak, to jak

TIA

Author: Sandy Muspratt, 2012-10-30

3 answers

Z mojego zrozumienia, w zasadzie jest bardzo ograniczona kontrola nad legendami w ggplot2. Oto akapit z Księgi Hadleya (strona 111):

ggplot2 stara się wykorzystać jak najmniejszą liczbę Legend, które dokładnie oddają estetykę użytą w fabule. Robi to poprzez łączenie Legend, jeśli zmienna jest używana z więcej niż jedną estetyką. Rysunek 6.14 pokazuje przykład tego dla punktów geom: jeśli zarówno kolor, jak i kształt są odwzorowane do tej samej zmiennej, to tylko potrzebna jest pojedyncza legenda. Aby legendy mogły zostać połączone, muszą mieć taką samą nazwę (ten sam tytuł legendy). Z tego powodu, jeśli zmienisz nazwę jednej ze scalonych Legend, będziesz musiał zmienić ją dla wszystkich z nich.

 4
Author: alittleboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 07:00:01

Można to zrobić poprzez wyodrębnienie osobnych legend z działek, a następnie ułożenie Legend W odpowiedniej działce. Kod tutaj używa funkcji z pakietu gtable do ekstrakcji, a następnie funkcji z pakietu gridExtra do aranżacji. Celem jest posiadanie fabuły, która zawiera legendę koloru i legendę rozmiaru. Najpierw wyodrębnij legendę koloru z fabuły, która zawiera tylko legendę koloru. Po drugie, wyodrębnij legendę rozmiaru z wykresu, który zawiera tylko legendę rozmiaru. Po trzecie, narysuj fabuła, która nie zawiera legendy. Po czwarte, ułóż fabułę i dwie legendy w jedną nową fabułę.

# 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)

Tutaj wpisz opis obrazka

Tutaj wpisz opis obrazka

 29
Author: Sandy Muspratt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-02 05:05:21

Oto inne rozwiązanie wykorzystujące Pakiety ggplot2 i cowplot (=Rozszerzenie ggplot2).

Podejście jest podobne do Sandys one, ponieważ wyjmuje legendę jako osobne obiekty i pozwala na samodzielne umieszczanie. Pierwotnie był przeznaczony dla wielu legend, które należą do dwóch lub więcej działek w siatce działek.

Funkcja g_legend, która jest używana herby, została zaczerpnięta z odpowiedzi .

Idea jest następująca:

  1. Utwórz Plot1, Plot2,.., PlotX bez legendy
  2. Utwórz Plot1, Plot2,..., PlotX with legends
  3. Wyodrębnij legendy z kroku 2 do oddzielnych obiektów
  4. Skonfiguruj siatkę legend i uporządkuj legendy w taki sposób, w jaki chcesz]}
  5. tworzenie siatki łączącej wątki i legendy

Wydaje się to dość skomplikowane i czas / Kod comsuming ale skonfigurować raz, można dostosować i używać go do każdego rodzaju fabuły/dostosowanie legendy.

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))

Przykłady:

Przykład http://i65.tinypic.com/jl1lef.png

Zmiana kolejności ostatniego wywołaniaplot_grid() przenosi legendy w prawo:

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

Przykład2 http://i68.tinypic.com/314yn9i.png

 6
Author: pat-s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:25