Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change the fill color of one of the dodged bar in ggplot

Tags:

r

ggplot2

I want to change the order of the bar plot only for the last set, just to highlight it. I used scale_fill_manual(), but it didn't help much.

Here's my code:

 x<-c(rep(c("Type1", "Type2"),4))
     y<-c(4,5,6,7,3,4,5,2)
     time<-c(2010,2010,2011,2011,2012,2012,2013,2013)
     z<-data.frame(type = x, val=y, Time = time)

     ggplot(data = z, aes(x=Time,y=val)) +
       geom_bar(stat = "identity", position = "dodge", aes(fill=type))+
       scale_fill_manual(values = c(rep(c("white", "gray51"),3),"white","red"))

Here's the output:

enter image description here

I want the graph to look like: enter image description here

Is there any way I can do this? I would appreciate any help. I looked at change color of only one bar in ggplot but it doesn't seem to be about grouped data.

like image 643
watchtower Avatar asked Aug 30 '16 19:08

watchtower


3 Answers

My general mantra is that ggplot is very good at plotting the data you give it. If you want it to plot something different, the easiest way is usually to modify your data.

z$type2 = as.character(z$type)
z$type2[z$type == "Type2" & z$Time == 2013] = "Type2 "

I added a sneaky extra space in "Type2 " for the row you want to highlight. It will be a distinct factor level and get its own color (and even be coerced into the a nice order using the alphabetical default). But it will appear the same in the legend label.

ggplot(data = z, aes(x=Time,y=val)) +
    geom_bar(stat = "identity", position = "dodge", aes(fill=type2))+
    scale_fill_manual(values = c("white", "gray50", "red"))

enter image description here

I thought that omitting the red from the legend would be difficult, but this answer showed me that all that is needed is to add breaks = c("Type1", "Type2") as an argument to scale_fill_manual.

like image 192
Gregor Thomas Avatar answered Nov 17 '22 22:11

Gregor Thomas


What about highlighting the bar with a border. For example:

z$hi = with(z, ifelse(type=="Type2" & Time==2013, "Y","N"))

ggplot(data = z, aes(x=Time,y=val)) +
  geom_bar(stat = "identity", position = "dodge", 
           aes(fill=type, colour=hi), size=1) +
  scale_fill_manual(values=c("gray51","white")) +
  scale_colour_manual(values=c(NA,"red")) +
  guides(colour=FALSE)

enter image description here

UPDATE: In response to your comment: I think a line plot makes it easier to see the trends and the relationships between each type. For example:

ggplot(data = z, aes(x=Time,y=val,colour=type)) +
  geom_line() +
  geom_point() +
  geom_point(data=z[z$hi=="Y",], aes(x=Time, y=val), size=4, pch=1, 
             colour=hcl(195,100,40), stroke=1) +
  scale_y_continuous(limits=c(0,max(z$val))) +
  theme_bw()

enter image description here

like image 25
eipi10 Avatar answered Nov 17 '22 23:11

eipi10


Easy to do it with the legend, though you may want to be cautious about throwing users off with the abrupt change in color. Simply add an additional category to your x variable to indicate where you want the highlighting.

x<- xHigh <- c(rep(c("Type1", "Type2"),4))
xHigh[length(xHigh)] <- "Type2_highlight"

myHighlight <- rep("No",length(x))
myHighlight[length(myHighlight)] <- "Yes"
y<-c(4,5,6,7,3,4,5,2)
time<-c(2010,2010,2011,2011,2012,2012,2013,2013)
z<-data.frame(type = x, xHigh = xHigh, val=y, Time = time, myHighlight = myHighlight)

ggplot(data = z, aes(x=Time,y=val)) +
  geom_bar(stat = "identity", position = "dodge", aes(fill=xHigh))+
  scale_fill_manual(values = c(Type1 = "white", Type2 = "gray51", Type2_highlight = "red"))

enter image description here

Another potential option for highlighting a particular bar is to draw a box around it, like so:

ggplot(data = z, aes(x=Time,y=val)) +
  geom_bar(stat = "identity", position = "dodge", aes(fill=type))+
  scale_fill_manual(values = c(Type1 = "white", Type2 = "gray51")) +
  geom_bar(aes(linetype = xHigh)
           , fill = NA
           , stat = "identity", position = "dodge"
           , col = "red"
           , show.legend = FALSE) +
  scale_linetype_manual(values = c(Type1 = 0
                                   , Type2 = 0
                                   , Type2_highlight = 1))

enter image description here

Hope that helps.

like image 21
Mark Peterson Avatar answered Nov 18 '22 00:11

Mark Peterson