0

I am trying to make custom likert style plot. I like the plot but I want to change the order of the legend while keeping the order of the plot.

Data:

df <- structure(list(Benefit = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 
3L, 4L, 4L, 4L, 5L, 5L, 5L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 8L, 8L, 
8L, 9L, 9L, 9L, 9L, 10L, 10L, 10L), .Label = c("Medical: Importance", 
"Medical:Satisfaction", "Dental:  Importance", "Dental: Satisfaction", 
"Vision:  Importance", "Vision: Satisfaction", "401K:    Importance", 
"401K:   Satisfaction", "EAP:     Importance", "EAP:    Satisfaction"
), class = "factor"), value = structure(c(1L, 2L, 5L, 6L, 1L, 
2L, 4L, 5L, 6L, 9L, 1L, 2L, 4L, 5L, 6L, 9L, 1L, 2L, 3L, 4L, 5L, 
6L, 9L, 1L, 2L, 3L, 4L, 5L, 6L, 9L), .Label = c("Very Important", 
"Important", "Not at all Important", "Less Important", "Strongly Satisfied", 
"Satisfied", "Strongly Dissatisfied", "Dissatisified", "N/A"), class = "factor"), 
    Percent = c(-80.7, -19.3, -50, -50, -64.3, -33.9, 1.8, -43.6, 
    -50.9, 5.5, -52.7, -41.8, 5.5, -33.9, -51.8, 14.3, -75, -17.3, 
    5.8, 1.9, -50, -30.8, 19.2, -13.7, -39.2, 5.9, 41.2, -13.2, 
    -45.3, 41.5)), class = "data.frame", row.names = c(4L, 9L, 
24L, 29L, 2L, 7L, 12L, 22L, 27L, 42L, 5L, 10L, 15L, 25L, 30L, 
45L, 1L, 6L, 16L, 11L, 21L, 26L, 41L, 3L, 8L, 18L, 13L, 23L, 
28L, 43L))

Here is the code for ggplot2 to make the plot that I like:

col4 <- c("#81A88D","#ABDDDE","#B40F20","#F4B5BD","orange","#F3DF6C","gray")

p <- ggplot(df, aes(x=Benefit, y = Percent, fill = value, label=abs(Percent))) +
  geom_bar(stat="identity", width = .5, position = position_stack(reverse = TRUE)) +
  geom_col(position = 'stack') +
  scale_x_discrete(limits = rev(levels(df$Benefit))) +
  geom_text(position = position_stack(vjust = 0.5), 
            angle = 45, color="black") +
  coord_flip() +
  scale_fill_manual(values = col4) +
  scale_y_continuous(breaks=(seq(-100,100,25)), labels=abs(seq(-100,100,by=25)), limits=c(-100,100)) +
                theme_minimal() +
                    theme(
                axis.title.y = element_blank(),
                legend.position = c(0.85, 0.8),
                legend.title=element_text(size=14), 
                axis.text=element_text(size=12, face="bold"),
                    legend.text=element_text(size=12),               
                panel.background = element_rect(fill = "transparent",colour = NA),
                    plot.background = element_rect(fill = "transparent",colour = NA),
                    #panel.border=element_blank(),
                    panel.grid.major=element_blank(),
                    panel.grid.minor=element_blank()
                    )+
   labs(fill="") + ylab("") + ylab("Percent") +
   annotate("text", x = 9.5, y = 50, label = "Importance") +
   annotate("text", x = 8.00, y = 50, label = "Satisfaction") 
p

Here's the plot:

enter image description here

The main thing is the order of the legend. For example, for EAP: Importance I have the plot going from, left to right, with "Very Important" -> "Important" -> "Less Important" -> "Not at all Important". But the legend goes Very Important" -> "Important" -> "Not at all Important" -> "Less Important".

I want the legend to match the plot. I've tried fooling around with guides and the various scale functions and can't get it to work. The data is ordered like the legend, but that's the only way I could get the plot to look like I wanted. I need a custom legend!

Thanks in advance for any help!

Edit to remove reference to "med" dataframe, which was an expanded version of df. This should run now.

JeniFav
  • 113
  • 1
  • 9

1 Answers1

1

Unfortunately, I could not reproduce your figure fully as it seems that I'm missing your med data.

However, changing the levels in your data frame accordingly should do the trick. Just do the following before the ggplot() command:

levels(df$value) <- c("Very Important", "Important", "Less Important", 
"Not at all Important", "Strongly Satisfied",    
"Satisfied", "Strongly Dissatisfied", "Dissatisified", "N/A")

Edit

Being able to reproduce your example, I came up with the following, a bit hacky, solution.

p <- ggplot(df, aes(x=Benefit, y = Percent, fill = value, label=abs(Percent))) +
  geom_bar(stat="identity", width = .5, position = position_stack(reverse = TRUE)) +
  geom_col(position = 'stack') +
  scale_x_discrete(limits = rev(levels(df$Benefit))) +
  geom_text(position = position_stack(vjust = 0.5), 
            angle = 45, color="black") +
  coord_flip() +
  scale_fill_manual(labels = c("Very Important", "Important", "Less Important", 
                               "Not at all Important", "Strongly Satisfied",    
                               "Satisfied", "N/A"),values = col4) +
  scale_y_continuous(breaks=(seq(-100,100,25)), labels=abs(seq(-100,100,by=25)), limits=c(-100,100)) +
  theme_minimal() +
  theme(
    axis.title.y = element_blank(),
    legend.position = c(0.85, 0.8),
    legend.title=element_text(size=14), 
    axis.text=element_text(size=12, face="bold"),
    legend.text=element_text(size=12),               
    panel.background = element_rect(fill = "transparent",colour = NA),
    plot.background = element_rect(fill = "transparent",colour = NA),
    #panel.border=element_blank(),
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank()
  )+
  labs(fill="") + ylab("") + ylab("Percent") +
  annotate("text", x = 9.5, y = 50, label = "Importance") +
  annotate("text", x = 8.00, y = 50, label = "Satisfaction") + 
guides(fill = guide_legend(override.aes = list(fill = c("#81A88D","#ABDDDE","#F4B5BD","#B40F20","orange","#F3DF6C","gray")) ) )
p

enter image description here

pascal
  • 1,036
  • 5
  • 15
  • Thanks, I fixed the issue above so you should be able to replicate. Unfortunately, this approach doesn't work. I've tried it before and I tried it just now. It seems I need a solution that doesn't involve formatting the data itself - or at least not formatting "value". The data is currently formatted to give me the graph I want but not the legend I want. I appreciate your response! – JeniFav Oct 22 '21 at 12:41
  • 1
    Your code is running without errors now. Hope my edits help. – pascal Oct 22 '21 at 13:44
  • That works! Sometimes we gotta by a bit hacky to get what we want. I was hacking around for hours yesterday before turning to here. I very much appreciate your help! – JeniFav Oct 22 '21 at 13:52