R: ggplot better gradient color

15,851

Solution 1

Thanks @zelite and @SimonO101 for your help. This is simpler version of what both of you proposed. Adding here for the completeness.

library(ggplot2)
library(reshape2)
library(RColorBrewer)

getColors<-function(n){
   mypal<-colorRampPalette(brewer.pal(12, "Paired"))
   sample(mypal(n), n, replace=FALSE)
}

PropBarPlot<-function(df, mytitle=""){
   melteddf<-melt(df, id=names(df)[1], na.rm=T)
   n<-length(levels(factor(melteddf$variable)))

   ggplot(melteddf, aes_string(x=names(df)[1], y="value", fill="variable")) + 
      geom_bar(position="fill") + 
      scale_fill_manual(values=getColors(n)) + 
      theme(axis.text.x = element_text(angle=90, vjust=1)) + 
      labs(title=mytitle)
}

df <- data.frame(id=letters[1:3],
             val0=1:3,
             val1=4:6,
             val2=7:9, 
             val3=2:4, 
             val4=1:3, 
             val5=4:6, 
             val6=10:12, 
             val7=12:14)

print(PropBarPlot(df))

Thanks.

Solution 2

How about using scale_fill_brewer which makes use of colour palettes from the ColorBrewer website, implemented by the package RColorBrewer?

ggplot(diamonds, aes(clarity, fill=cut) ) +
geom_bar( ) +
scale_fill_brewer( type = "div" , palette = "RdBu" )

enter image description here

There are a number of different diverging palettes you can choose from.

require(RColorBrewer)
?brewer.pal

If you need more colours you can use the colorRampPalette features to interpolate between some colours (and I would use a brewer.pal palette for this). You can do this like so:

# Create a function to interpolate between some colours
mypal <- colorRampPalette( brewer.pal( 6 , "RdBu" ) )
# Run function asking for 19 colours
mypal(19)
 [1] "#B2182B" "#C2373A" "#D35749" "#E47658" "#F0936D" "#F4A989" "#F8BFA5"
 [8] "#FCD6C1" "#F3DDD0" "#E7E0DB" "#DAE2E6" "#CBE1EE" "#ADD1E5" "#90C0DB"
 [15] "#72AFD2" "#5B9DC9" "#478BBF" "#3478B5" "#2166AC"

In your example which requires 8 colours you an use it like this with scale_fill_manual():

PropBarPlot<-function(df, mytitle=""){
   melteddf<-melt(df, id=names(df)[1], na.rm=T)
   ggplot(melteddf, aes_string(x=names(df)[1], y="value", fill="variable")) + 
     geom_bar(position="fill") + 
     theme(axis.text.x = element_text(angle=90, vjust=1)) + 
     labs(title=mytitle)+
    scale_fill_manual( values = mypal(8) )
}

print(PropBarPlot(df))

Solution 3

Borrowing some code from @SimonO101

library(ggplot2)
library(reshape2)
library(RColorBrewer)
mypal <- colorRampPalette( brewer.pal( 9 , "Set1" ) ) #you can try using different palete instead
#of "Set1" until it looks good to you

intercalate <- function(n){ #my crude attempt to shuffle the colors
  c(rbind(1:(n/2), n:(n/2+1))) #it will only work for even numbers
}

PropBarPlot<-function(df, mytitle=""){
  melteddf<-melt(df, id=names(df)[1], na.rm=T)
  ggplot(melteddf, aes_string(x=names(df)[1], y="value", fill="variable")) + 
    geom_bar(position="fill") + 
    theme(axis.text.x = element_text(angle=90, vjust=1)) + 
    labs(title=mytitle)+
    scale_fill_manual( values = mypal(8)[intercalate(8)] )
  #better would be to calculate the different number of categories
  #you have and put that instead of the number 8
}

df <- data.frame(id=letters[1:3],
                 val0=1:3,
                 val1=4:6,
                 val2=7:9, 
                 val3=2:4, 
                 val4=1:3, 
                 val5=4:6, 
                 val6=10:12, 
                 val7=12:14)

print(PropBarPlot(df))

See if that works better for your needs.

Share:
15,851
Rachit Agrawal
Author by

Rachit Agrawal

Love coding.

Updated on June 16, 2022

Comments

  • Rachit Agrawal
    Rachit Agrawal about 2 years

    I am using ggplot to plot Proportional Stacked Bar plot. And the Plot I am getting is something like this: enter image description here

    And this is the self written function I am using:

    df <- data.frame(id=letters[1:3],val0=1:3,val1=4:6,val2=7:9, val3=2:4, val4=1:3, val5=4:6, val6=10:12, val7=12:14)
    
    PropBarPlot<-function(df, mytitle=""){
       melteddf<-melt(df, id=names(df)[1], na.rm=T)
       ggplot(melteddf, aes_string(x=names(df)[1], y="value", fill="variable")) + 
         geom_bar(position="fill") + 
         theme(axis.text.x = element_text(angle=90, vjust=1)) + 
         labs(title=mytitle)
    }
    
    print(PropBarPlot(df))
    

    Here val4 and val5 are not very different.

    But due to colors some of them are not distinguishable. Can someone tell me how to choose better colors so that they are differentiable?

    Thanks.

  • Rachit Agrawal
    Rachit Agrawal about 11 years
    I checked the different palettes, the best I get is a max of 12 variation, whereas in my case I need at-least 19 colors. With all the palettes, it is having problem.
  • Simon O'Hanlon
    Simon O'Hanlon about 11 years
    @RachitAgrawal ok, I updated to something which might work for you. Check the edit.
  • Rachit Agrawal
    Rachit Agrawal about 11 years
    Suffers from the same problem mentioned above. Some of them cannot be distinguished.
  • Simon O'Hanlon
    Simon O'Hanlon about 11 years
    Then you have too many colour categories in a single plot! The palettes have a maximum number of colours for a reason. Consider splitting your plot using facet_wrap or facet_ grid.
  • zelite
    zelite about 11 years
    Maybe it would work better if adjacent colors in the plot would be from oposite parts of the palete? In the example you have blues close to blues, and reds close to reds. If they alternate then it would be better distinguished? But I agree with SimonO101: if there's problem distinguishing so many colors, maybe you're plotting too much in one single plot.
  • Rachit Agrawal
    Rachit Agrawal about 11 years
    I have come up with a simpler solution to mix the colors. Added below. Thanks for the help.