ggplot2: boxplot with colors and text labels mapped to combination of two categorical variables

强颜欢笑 提交于 2019-11-30 20:48:06

Here are three progressively more involved options for adding text in the way you describe in your question, followed by a different approach using faceting:

Set-up

First, create a couple of utility values we'll use later:

# Color vectors
LocPosCol = c(hcl(0,100,c(50,80)), hcl(240,100,c(50,80)))
LocCol = c(hcl(c(0,240),100,65))

# Dodge width
pd = position_dodge(0.7)

Now create a basic boxplot. We use the interaction function to create a fill aesthetic based on all combinations of location and position:

p = ggplot(densityAGRLKA, 
           aes(species, density, 
               fill=interaction(location, position, sep="-", lex.order=TRUE))) + 
  geom_boxplot(width=0.7, position=pd) + 
  theme_bw() +
  scale_fill_manual(values=LocPosCol)

Now here are five variations on that boxplot. Three based on the request in your question and two alternatives based on faceting:

With legend along bottom

p + labs(fill="Location-Position") +
  theme(legend.position="bottom")

With text identifiers under the boxes

library(dplyr)

p + geom_text(data=densityAGRLKA %>% group_by(species, location, position) %>%
                     summarise(value=unique(paste(location, position, sep="-"))),
              aes(label=value, y=0.29, 
                  color=interaction(location, position, sep="-", lex.order=TRUE)),
              position=pd, size=3.3, fontface="bold") +
  scale_color_manual(values=LocPosCol) +
  guides(color=FALSE, fill=FALSE)

With two levels of text identifiers under the boxes

p + geom_text(data=densityAGRLKA %>% group_by(species, location) %>% 
                     summarise %>% mutate(position=NA),
              aes(label=location, color=location, y=0.29),
              position=pd, size=4.2, fontface="bold") +
    geom_text(data=densityAGRLKA %>% group_by(species, position, location) %>% 
                     summarise,
              aes(label=position, 
                  color=interaction(location, position, sep="-", lex.order=TRUE),
                  y=0.28),
              position=pd, size=3.7, fontface="bold") +
  scale_color_manual(values=c(LocCol[1],LocPosCol[1:2],LocCol[2],LocPosCol[3:4])) +
  guides(color=FALSE, fill=FALSE)

Faceting with standard ggplot facet labels

The code below is relatively straightforward, but I'm not wild about the way faceting results in repeating of labels, rather than using a single spanning label when the same level is repeated two or four times in consecutive facets. Below is the "standard" ggplot faceting. Following that is an example of the (somewhat painful) process of changing the facet labels to span multiple facets.

ggplot(densityAGRLKA, aes("", density)) + 
  geom_boxplot(width=0.7, position=pd) + 
  theme_bw() +
  facet_grid(. ~ species + location +  position) +
  theme(panel.margin=unit(0,"lines"),
        panel.border=element_rect(color="grey90"),
        axis.ticks.x=element_blank()) +
  labs(x="")

Faceting with a single facet label spanning a given category

To change the facet labels so that a single label spans a given category (rather than having the same label repeated for each facet) requires going outside of ggplot and using lower level grid functions to change the facet strip label grobs. Here's an example:

library(gtable)
library(grid)

p=ggplot(densityAGRLKA, aes("", density)) + 
  geom_boxplot(width=0.7, position=pd) + 
  theme_bw() +
  facet_grid(. ~ species + location +  position) +
  theme(panel.margin=unit(0,"lines"),
        strip.background=element_rect(color="grey30", fill="grey90"),
        panel.border=element_rect(color="grey90"),
        axis.ticks.x=element_blank()) +
  labs(x="")

pg = ggplotGrob(p)

# Add spanning strip labels for species
pos = c(4,11)    
for (i in 1:2) {
  pg <- gtable_add_grob(pg, 
                        list(rectGrob(gp=gpar(col="grey50", fill="grey90")),
                             textGrob(unique(densityAGRLKA$species)[i], 
                                      gp=gpar(cex=0.8))), 3,pos[i],3,pos[i]+7,
                        name=c("a","b"))
}

# Add spanning strip labels for location
pos=c(4,7,11,15)
for (i in 1:4) {
    pg = gtable_add_grob(pg, 
                         list(rectGrob(gp = gpar(col="grey50", fill="grey90")),
                              textGrob(rep(unique(densityAGRLKA$location),2)[i], 
                                       gp=gpar(cex=0.8))), 4,pos[i],4,pos[i]+3, 
                         name = c("c", "d"))
}

plot(pg)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!