Search code examples
ggplot2bar-chartword-wrapstringrcolumn-chart

How to wrap lengthy labels in multiple panels in grouped bar charts


This question pertains to how to wrap lengthy labels in clustered column/bar chart to have the labels appear on multiple lines (or rows) in multiple panels. Consider the data below

df  <- data.frame(group=c("Treated very satisfied", "Treated very satisfied",
                           "Treated not satisfied","Treated not satisfied",
                           "Untreated very satisfied","Untreated very satisfied", 
                            "Untreated not satisfied","Untreated not satisfied"), 
                  cost=c("low","high","low","high","low","high","low","high"),     
                  treatment=c("treated","treated","treated","treated",
                            "untreated","untreated","untreated","untreated") ,
                  value=c(2.3,5.7,4.0,3.1,9.4,3.1,2.0,-1.6)) 

We use group as the x axis and value as the y axis. From this data set, the following code is used generate the subsequent chart

#REORDER
df$group <- factor(df$group, levels = c("Treated very satisfied", 
                            "Treated not satisfied",
                            "Untreated very satisfied",
                            "Untreated not satisfied"))

ggplot(data=df,aes(y = value, x = group, fill = cost)) +
geom_bar(stat="identity",position='stack') + ylab("Y label") +
theme(legend.direction = "horizontal",legend.position = "bottom",
    legend.spacing.x = unit(0.1, 'cm'))+
theme(legend.title=element_blank())+
geom_text(aes(label = ifelse(value !=0, value, "")), 
         position = position_stack(vjust=0.5))+
facet_grid( ~ treatment)    

enter image description here

On the x axis, I expect to see "Treated very satisfied" and "Treated not satisfied" in panel 1 and
"Untreated very satisfied" and "Untreated not satisfied" in panel 2. As shown, these texts overlap, so they cannot be seen clearly. I am looking for a way to format/wrap the texts (not rotate), each into multiple lines (i.e. three lines per each) along the x axis, for example, Treated\n very\n satisfied for all labels in both panels.

I have considered several attempts to resolve this, example using function "str_wrap" in package "stringr" (from Auto wrapping of labels via labeller=label_wrap in ggplot2). However, this does not work due to the panels/clusters in the plot. I would appreciate any help on this.


Solution

  • First I would recommend using scales = "free_x" in facet_grid to show only the categories used in each panel. Second. Using the solution in the linked post worked fine for me to wrap the labels.

    library(ggplot2)
    library(stringr)
    
    df  <- data.frame(group=c("Treated very satisfied", "Treated very satisfied",
                              "Treated not satisfied","Treated not satisfied",
                              "Untreated very satisfied","Untreated very satisfied", 
                              "Untreated not satisfied","Untreated not satisfied"), 
                      cost=c("low","high","low","high","low","high","low","high"),     
                      treatment=c("treated","treated","treated","treated",
                                  "untreated","untreated","untreated","untreated") ,
                      value=c(2.3,5.7,4.0,3.1,9.4,3.1,2.0,-1.6))
    
    #REORDER
    df$group <- factor(df$group, levels = c("Treated very satisfied", 
                                            "Treated not satisfied",
                                            "Untreated very satisfied",
                                            "Untreated not satisfied"))
    
    ggplot(data=df,aes(y = value, x = group, fill = cost)) +
      geom_bar(stat="identity",position='stack') + ylab("Y label") +
      theme(legend.direction = "horizontal",legend.position = "bottom",
            legend.spacing.x = unit(0.1, 'cm'))+
      theme(legend.title=element_blank())+
      geom_text(aes(label = ifelse(value !=0, value, "")), 
                position = position_stack(vjust=0.5))+
      scale_x_discrete(labels = function(x) str_wrap(x, width = 10)) +
      facet_grid( ~ treatment, scales = "free_x")    
    

    Created on 2020-06-08 by the reprex package (v0.3.0)