'In ggplot, segregate bar graphs based on value of another column

Using the following data frame:

dat <- structure(list(Model = c("I.E.T", "I.E.T.S", "I.E.T.N", "I.E.T.S.N", 
                                "F.D.E.T", "F.D.E.T.N", "F.D.E.T.S.N", "I.E.T", "I.E.T.S", "I.E.T.N", 
                                "I.E.T.S.N", "F.D.E.T", "F.D.E.T.N", "F.D.E.T.S.N", "I.E.T", 
                                "I.E.T.S", "I.E.T.N", "I.E.T.S.N", "F.D.E.T", "F.D.E.T.N", "F.D.E.T.S.N"), 
                      Errors = c("NO", "NO", "NO", "YES", "NO", "NO", "YES", "NO", 
                                 "NO", "NO", "NO", "NO", "NO", "NO", "NO", "NO", "NO", "YES", 
                                 "NO", "NO", "YES"),                     
                      Type = c("CF", "CF", "CF", "CF", "CF", "CF", 
                                 "CF", "BF", "BF", "BF", "BF", "BF", "BF", "BF", "MBF", "MBF", 
                                 "MBF", "MBF", "MBF", "MBF", "MBF"), 
                      Mean_Loadings = c(0.534, 0.591, 0.554, 0.581, 0.552, 0.569, 0.596, 0.196, 0.39, 0.306, 
                                       0.411, 0.174, 0.343, 0.429, 0.185, 0.248, 0.271, 0.292, 0.21, 
                                       0.343, 0.429)), 
                      class = "data.frame", row.names = c(NA, -21L))

I have created this plot:

dat$Model <- factor(dat$Model)
dat$Errors <- factor(dat$Errors, levels = c("NO", "YES"))
dat$Type <- factor(dat$Type, levels = c("CF", "MBF", "BF"))

ggplot(dat, aes(x = interaction(Model, Errors), y = Mean_Loadings, color = Type, fill = Type)) + 
  geom_rect(data=NULL, aes(xmin=7.5, xmax=Inf, ymin=-Inf, ymax=Inf), fill="#F9EBEA", color = "gray")+
  geom_bar(position = position_dodge2(width = 0.9, preserve = "single")
           , stat="identity")+
  scale_x_discrete(limits = NULL) +
  theme_bw() + 
  labs(title = "",
       y = "Mean Loading",
       x = "Models",
       color = "Model Type",
       fill = "Model Type") +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.title=element_text(size=15),
        text = element_text(size = 14), plot.margin = margin(20, 50, 10, 20),
        axis.text.x=element_text(angle = -25, hjust = 0, size = 10), 
        axis.text.y=element_text(size = 20), axis.text=element_text(size=20)) +
  theme(legend.position = "top")

How can the following be done?

  1. Remove ".NO" and ".YES" from the names of the models that show on the X-Axis. Or is there a better way of doing this whole plot besides x = interaction(Model, Errors)? The end goal is to segregate on the right models that produced errors (as indicated in the Errors column).
  2. Add some text to the top center of the red box on the right. e.g. "With Errors"
  3. Add a text box to the right of the plot.


Solution 1:[1]

First, for removing the no and yes, you could create a simple function to extract the portions that you want for the labels. So, in interaction, I added _ as the separator, then we can just extract the portion proceeding that, which is added in scale_x_discrete as labels = make_labels. Second, for adding text to the red area, you can just use annotate. Third, for outside the area, we can again use annotate, but we want to add an additional line to allow plotting outside using coord_cartesian.

library(tidyverse)

make_labels <- function(labels) {
  result <- str_split(labels, "_")
  unlist(lapply(result, function(x) x[1]))
}


ggplot(dat, aes(x = interaction(Model, Errors, sep = "_"), y = Mean_Loadings, color = Type, fill = Type)) + 
  geom_rect(data=NULL, aes(xmin=7.5, xmax=Inf, ymin=-Inf, ymax=Inf), fill="#F9EBEA", color = "gray")+
  geom_bar(position = position_dodge2(width = 0.9, preserve = "single")
           , stat="identity")+
  scale_x_discrete(labels = make_labels, limits = NULL) +
  theme_bw() + 
  labs(title = "",
       y = "Mean Loading",
       x = "Models",
       color = "Model Type",
       fill = "Model Type") +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.title=element_text(size=15),
        text = element_text(size = 14), plot.margin = margin(20, 80, 10, 20),
        axis.text.x=element_text(angle = -25, hjust = 0, size = 10), 
        axis.text.y=element_text(size = 20), axis.text=element_text(size=20)) +
  theme(legend.position = "top") +
  annotate("text", x=8.5, y=0.65, label= "With Errors",
           family = "", fontface = 2, size=4) + 
  annotate("text", x = 10, y = 0.65, label = "text",
           family = "", fontface = 2, size=4) +
  coord_cartesian(ylim = c(0, 0.7), xlim = c(0, 9), clip = "off")

Output

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AndrewGB