简体   繁体   中英

Combine redundant legend items in ggplot2

Here's my data:

# Data:
mydf <- data.frame(
  Species = rep(c("Ungulate","Ungulate","Elk","Elk","Rodent","Rodent","Deer","Deer"), 
                times = 3),
  Space = rep(c("W", "C", "E"), each = 8),
  Age = rep(c("Adult", "Juvenile"), times = 12), 
  value = c(0.03,0.17,0.02,0.23,0.33,0.00,0.05,0.12,0.04,0.28,0.09,0.23,0.17,0.00,0.13,
            0.17,0.02,0.14,0.01,0.23,0.29,0.00,0.06,0.13))

mydf$spaceage <- as.factor(paste(mydf$Space, mydf$Age))
mydf

myPalette <- c("#f4a582", "#b2182b", "#92c5de", "#2166ac", "#a6dba0", "#1b7837")

For my plot:

example <- ggplot(mydf, 
                  aes(x = factor(Space, levels = c("W", "C", "E")), 
                      y = value, 
                      fill = factor(spaceage))) +
  geom_bar(stat = 'identity', position = 'stack') + 
  facet_grid(~ Species) +
  scale_fill_manual(values = myPalette, name = "Age") + #legend
  labs(x="") +
  theme_bw()

example

Returns: 在此输入图像描述

Is it possible to combine redundant legend items , so dark and light shades are combined, to produce something like this? (couldn't get very even sizes using paint):

在此输入图像描述

I'm open to other ideas for making this legend more concise. Thanks for any advice!

You can assign "" as legend label to some legend entries in order to achieve the effect.

However, I would first of all caution to be very careful with the manual fill scale first, as you want to make sure each colour corresponds to the correct spaceage value before obscuring its label.

Here's an implementation:

# ensure correct mapping between colour & label
names(myPalette) <- levels(mydf$spaceage)

ggplot(mydf, 
       aes(x = factor(Space, levels = c("W", "C", "E")), 
           y = value, 
           fill = factor(spaceage))) +

  # minor point, but geom_col() is equivalent to geom_bar(position = "identity"),
  # and position = "stack" is default in both cases.
  geom_col() + 

  facet_grid(~ Species) +

  scale_fill_manual(values = myPalette, name = "Age",

                    # ensures colour order follows x-axis order
                    breaks = c("W Adult", "W Juvenile", "C Adult", "C Juvenile", 
                               "E Adult", "E Juvenile"),

                    # comment out this line to verify that right colour
                    # is mapped to the right label
                    labels = c("", "", "", "", "Adult", "Juvenile"),

                    # specify 2 rows for legends
                    guide = guide_legend(nrow = 2, byrow = FALSE)) +

  labs(x = "") +
  theme_bw() 

情节

Create the legend, which is actually a ggplot2.

library(ggplot2)
ds_palette <- tibble::tibble(
  fill          = c("#a6dba0", "#1b7837", "#f4a582", "#b2182b", "#92c5de", "#2166ac"),
  x             = c(2, 1, 2, 1, 2, 1),
  y             = c(3, 3, 2, 2, 1, 1),
  text          = c("W", "W", "C", "C", "E", "E"),
  text_color    = c("black", "white", "black", "white", "black", "white")
)

legend_inset <- ggplot(ds_palette, aes(x=x, y=y, fill=fill)) +
  geom_tile() +
  geom_text(aes(label=text, color=text_color)) +
  annotate("text", x=1, y=3.6, label="Juvenile", vjust=0) +
  annotate("text", x=2, y=3.6, label="Adult", vjust=0) +
  scale_color_identity() +
  scale_fill_identity() +
  coord_cartesian(ylim=c(0.5, 4), expand = F) +
  theme_void() +
  labs(x="")

Then put it all together. The objects in vpList define the proportions of the partitioned areas.

grid.newpage()
plot_width <- .8
tree <- vpTree(
  viewport(w=1, h=1, name="A"),
  vpList(
    viewport(x=0, y=0 , w=  plot_width, h=1  , just=c("left", "bottom"), name="bar_graph"),
    viewport(x=1, y=.5, w=1-plot_width, h=0.3, just=c("right", "top")  , name="legend")
  )
)
pushViewport(tree)

print(example     , vp = "bar_graph")
print(legend_inset, vp = "legend")

在此输入图像描述

I rotated your 2x3 legend so the words would be more space-efficient.

You can add labels and change the position of your legend as the code below.

  example<-ggplot(mydf, aes(x = factor(Space, levels=c("W", "C", "E")), y = value, fill = factor(spaceage))) +
  geom_bar(stat = 'identity', position = 'stack') + facet_grid(~ Species) +
  scale_fill_manual(values = myPalette,name = "Age",labels=c("Adult","Juvenile","Adult","Juvenile","Adult","Juvenile")) + #legend
  labs(x="") +
  theme(legend.position = "top") 

example

The result looks like below. 在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM