2013-11-21 16 views
14

Mam ggplot gdzie jestem czynniki odwzorowania zarówno wypełnienia i alfa, tak:Zrób prostokątny legendę, z wierszy i kolumn oznaczonych w siatce

set.seed(47) 
the_data <- data.frame(value = rpois(6, lambda=20), 
         cat1 = rep(c("A", "B"), each = 3), 
         cat2 = rep(c("X", "Y", "Z"), 2)) 

ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_alpha_discrete(range = c(0.5, 1)) + 
    theme_bw() 

enter image description here

ludzie, dla których go tworzę, nie uznają legendy alfa za bardzo jasne. Myślę, że dobrym rozwiązaniem byłoby coś takiego (które przerobione w grafice podstawką)

enter image description here

wiem, że nie można wygenerować legendę takiego z poleceniami ggplot wysokiego szczebla, ale mogę zrób to w grid i umieść go na szczycie mojej fabuły?

+2

Najszybszym rozwiązaniem może być po prostu użyć dwóch ** krata** rzutnie do przydzielania oddzielnych regionów dla wykresu i jego legendy, a następnie użyj pakietu ** gridBase **, aby umieścić ręcznie wykonaną legendę w górnej rzutni. ('' vignette ("gridBase") 'daje wprowadzenie lub poszukiwanie' [r] gridBase' tutaj na SO dla dodatkowych przykładów.) –

+0

@ JoshO'Brien Nie wiedziałem o 'gridBase', dzięki za wskaźnik! – Gregor

+0

Tak, czasami okazuje się bardzo przydatny. [Tutaj] (http://stackoverflow.com/questions/11489447/combining- dwa-plots-in-r/11496362#11496362) i [tutaj] (http://stackoverflow.com/questions/9985013/how-do -you-draw-a-line-through-a-multiple-figure-environment-in-r/9985936 # 9985936) to kilka miejsc, w których użyłem go do osiągnięcia innych trudnych efektów. –

Odpowiedz

14

Oto jeden z możliwych punktów wyjścia. Tworzę dwa różne wątki, które mają odpowiednie legendy - "jasne" i "blade". Wyodrębnij legendy z obiektów fabuły. Następnie użyj jednej, a następnie jednej dla każdej legendy, aby połączyć wszystkie elementy.

library(grid) 
library(gtable) 

# create plot with legend with alpha = 1 
g1 <- ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_alpha_discrete(range = c(0.5, 1)) + 
    theme_bw() + 
    guides(fill = guide_legend(title = "A", 
          title.hjust = 0.4), 
     alpha = FALSE) + 
    theme_bw() + 
    theme(legend.text = element_blank()) 

g1 

# grab legend 
legend_g1 <- gtable_filter(ggplot_gtable(ggplot_build(g1)), "guide-box") 


# create plot with 'pale' legend 
g2 <- ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) + 
    geom_bar(stat = "identity", position = "dodge") + 
    scale_alpha_discrete(range = c(0.5, 1)) + 
    guides(fill = guide_legend(override.aes = list(alpha = 0.5), 
          title = "B", 
          title.hjust = 0.3), 
     alpha = FALSE) + 
    theme_bw() 
g2 

# grab legend 
legend_g2 <- gtable_filter(ggplot_gtable(ggplot_build(g2)), "guide-box") 



# arrange plot and legends 

# legends to the right 

# define plotting regions (viewports) 
vp_plot <- viewport(x = 0.4, y = 0.5, 
        width = 0.8, height = 1) 

vp_legend_g1 <- viewport(x = 0.85, y = 0.5, 
          width = 0.4, height = 0.4) 

vp_legend_g2 <- viewport(x = 0.90, y = 0.5, 
          width = 0.4, height = 0.4) 


# clear current device 
grid.newpage() 

# add objects to the viewports 
# plot without legend 
print(g1 + theme(legend.position = "none"), vp = vp_plot) 
upViewport(0) 

pushViewport(vp_legend_g1) 
grid.draw(legend_g1) 
upViewport(0) 

pushViewport(vp_legend_g2) 
grid.draw(legend_g2) 

enter image description here

# legends on top 
vp_plot <- viewport(x = 0.5, y = 0.4, 
        width = 1, height = 0.85) 

vp_legend_g1 <- viewport(x = 0.5, y = 0.9, 
         width = 0.4, height = 0.4) 

vp_legend_g2 <- viewport(x = 0.55, y = 0.9, 
         width = 0.4, height = 0.4) 

grid.newpage() 

print(g1 + theme(legend.position = "none"), vp = vp_plot) 
upViewport(0) 

pushViewport(vp_legend_g1) 
grid.draw(legend_g1) 
upViewport(0) 

pushViewport(vp_legend_g2) 
grid.draw(legend_g2) 

enter image description here

+1

Cóż, po tym wszystkim, na pewno muszę oddać głos, ale strategia Josha wydaje się jeszcze bardziej odpowiednia. –

+0

To jest piękne! Dzięki, Henrik. – Gregor

4

@Henrik

To może być trochę łatwiej,

g1 <- ggplotGrob(p1) 
g2 <- ggplotGrob(p2) 

leg1 <- gtable_filter(g1, "guide-box") 
leg2 <- gtable_filter(g2, "guide-box") 
leg <- gtable:::cbind_gtable(leg1[["grobs"]][[1]], leg2[["grobs"]][[1]], "first") 

g1$grobs[g1$layout$name == "guide-box"][[1]] <- leg 
g1$widths[max(subset(g1$layout, name == "guide-box")[["r"]])] <- list(leg1$width + leg2$width) 

grid.newpage() 
grid.draw(g1) 
Powiązane problemy