I often work with ggplot2
that makes gradients nice (click here for an example). I have a need to work in base and I think scales
can be used there to create color gradients as well but I'm severely off the mark on how. The basic goal is generate a palette of n colors that ranges from x color to y color. The solution needs to work in base though. This was a starting point but there's no place to input an n.
scale_colour_gradientn(colours=c("red", "blue"))
I am well aware of:
brewer.pal(8, "Spectral")
from RColorBrewer
. I'm looking more for the approach similar to how ggplot2
handles gradients that says I have these two colors and I want 15 colors along the way. How can I do that?
base
specifically, but I find colourvalues
(also on CRAN) particularly convenient for mapping values to a gradient. It's also pretty lightweight (depends on Rcpp
).
colorRampPalette
could be your friend here:
colfunc <- colorRampPalette(c("black", "white"))
colfunc(10)
# [1] "#000000" "#1C1C1C" "#383838" "#555555" "#717171" "#8D8D8D" "#AAAAAA"
# [8] "#C6C6C6" "#E2E2E2" "#FFFFFF"
And just to show it works:
plot(rep(1,10),col=colfunc(10),pch=19,cex=3)
https://i.stack.imgur.com/dGQU0.png
Just to expand on the previous answer colorRampPalette
can handle more than two colors.
So for a more expanded "heat map" type look you can....
colfunc<-colorRampPalette(c("red","yellow","springgreen","royalblue"))
plot(rep(1,50),col=(colfunc(50)), pch=19,cex=2)
The resulting image:
https://i.stack.imgur.com/28xXQ.png
Try the following:
color.gradient <- function(x, colors=c("red","yellow","green"), colsteps=100) {
return( colorRampPalette(colors) (colsteps) [ findInterval(x, seq(min(x),max(x), length.out=colsteps)) ] )
}
x <- c((1:100)^2, (100:1)^2)
plot(x,col=color.gradient(x), pch=19,cex=2)
https://i.stack.imgur.com/9HJJN.png
The above answer is useful but in graphs, it is difficult to distinguish between darker gradients of black. One alternative I found is to use gradients of gray colors as follows
palette(gray.colors(10, 0.9, 0.4))
plot(rep(1,10),col=1:10,pch=19,cex=3))
More info on gray scale here.
Added
When I used the code above for different colours like blue and black, the gradients were not that clear. heat.colors()
seems more useful.
This document has more detailed information and options. pdf
An alternative approach (not necessarily better than the previous answers!) is to use the viridis
package. As explained here, it allows for a variety of color gradients that are based on more than two colors.
The package is pretty easy to use - you just need to replace the ggplot2
scale fill function (e.g., scale_fill_gradient(low = "skyblue", high = "dodgerblue4")
) with the equivalent viridis
function.
So, change the code for this plot:
ggplot(mtcars, aes(wt*1000, mpg)) +
geom_point(size = 4, aes(colour = hp)) +
xlab("Weight (pounds)") + ylab("Miles per gallon (MPG)") + labs(color='Horse power') +
scale_x_continuous(limits = c(1000, 6000),
breaks = c(seq(1000,6000,1000)),
labels = c("1,000", "2,000", "3,000", "4,000", "5,000", "6,000")) +
scale_fill_gradient(low = "skyblue", high = "dodgerblue4") +
theme_classic()
Which produces:
https://i.stack.imgur.com/HnREA.jpg
To this, which uses viridis
:
ggplot(mtcars, aes(wt*1000, mpg)) +
geom_point(size = 4, aes(colour = factor(cyl))) +
xlab("Weight (pounds)") + ylab("Miles per gallon (MPG)") + labs(color='Number\nof cylinders') +
scale_x_continuous(limits = c(1000, 6000),
breaks = c(seq(1000,6000,1000)),
labels = c("1,000", "2,000", "3,000", "4,000", "5,000", "6,000")) +
scale_color_viridis(discrete = TRUE) +
theme_classic()
The only difference is in the second to last line: scale_color_viridis(discrete = TRUE)
.
This is the plot that is produced using viridis
:
https://i.stack.imgur.com/md2Lv.jpg
Hoping someone finds this useful, as its the solution I ended up using after coming to this question.
Success story sharing
brewer.pal(8, "Spectral")
, you can give the resulting vector of colours tocolorRampPalette
to generate more colours along that ramp. For example:colorRampPalette(brewer.pal(8, "Spectral"))
.