Is it possible to desaturate a ggplot
easily?
In principle, there could be two possible strategies.
First, apply some function to a ggplot
object (or, possibly, Grob
object) to desaturate all colors. Second, some trick to print ggplot
desaturated while rendering a .rmd
file. Both strategies would be ok for me, but first one is, of course, more promissing.
Creating ggplot
in greys from the beginning is not a good option as the idea is to have the same plot as if it was printed in shades of grey.
There were some similar questions and remarkably good answers on how to perform desaturation in R. Here is a convenient way to desaturate color palette. And here is the way of desaturating a raster image. What I'm looking for, is a simple way of desaturating the whole ggplot
.
Just came across this question. The experimental package colorblindr (written by Claire McWhite and myself) contains a function that can do this in a generic way. I'm using the example figure from @hrbrmstr:
library(ggplot2)
library(viridis)
gg <- ggplot(mtcars) +
geom_point(aes(x=mpg, y=wt, fill=factor(cyl), size=factor(carb)),
color="black", shape=21) +
scale_fill_viridis(discrete = TRUE) +
scale_size_manual(values = c(3, 6, 9, 12, 15, 18)) +
facet_wrap(~am)
gg
Now let's desaturate this plot, using the edit_colors()
function from colorblindr:
library(colorblindr) # devtools::install_github("clauswilke/colorblindr")
library(colorspace) # install.packages("colorspace", repos = "http://R-Forge.R-project.org") --- colorblindr requires the development version
# need also install cowplot; current version on CRAN is fine.
gg_des <- edit_colors(gg, desaturate)
cowplot::ggdraw(gg_des)
The function edit_colors()
takes a ggplot2 object or grob and applies a color transformation function (here desaturate
) to all colors in the grob.
We can provide additional arguments to the transformation function, e.g. to do partial desaturation:
gg_des <- edit_colors(gg, desaturate, amount = 0.7)
cowplot::ggdraw(gg_des)
We can also do other transformations, e.g. color-blind simulations:
gg_des <- edit_colors(gg, deutan)
cowplot::ggdraw(gg_des)
Finally, we can manipulate line colors and fill colors separately. E.g., we could make all filled areas blue. (Not sure this is useful, but whatever.)
gg_des <- edit_colors(gg, fillfun = function(x) "lightblue")
cowplot::ggdraw(gg_des)
As per my comment above, this might be the quickest/dirtiest way to achieve the desaturation for a ggplot2
object:
library(ggplot2)
set.seed(1)
p <- qplot(rnorm(50), rnorm(50), col="Class")
print(p)
pdf(file="p.pdf", colormodel="grey")
print(p)
dev.off()
I tried this with the new viridis color palette since it desaturates well (i.e. it should be noticeable between the colored & non-colored plots):
library(ggplot2)
library(grid)
library(colorspace)
library(viridis) # devtools::install_github("sjmgarnier/viridis") for scale_fill_viridis
gg <- ggplot(mtcars) +
geom_point(aes(x=mpg, y=wt, fill=factor(cyl), size=factor(carb)),
color="black", shape=21) +
scale_fill_viridis(discrete = TRUE) +
scale_size_manual(values = c(3, 6, 9, 12, 15, 18)) +
facet_wrap(~am)
gb <- ggplot_build(gg)
gb$data[[1]]$colour <- desaturate(gb$data[[1]]$colour)
gb$data[[1]]$fill <- desaturate(gb$data[[1]]$fill)
gt <- ggplot_gtable(gb)
grid.newpage()
grid.draw(gt)
You end up having to manipulate on the grob level.
Here's the plot pre-desaturate:
and here's the plot post-desature:
I'm trying to figure out why the legend got skipped and this may miss other highly customized ggplot aesthetics & components, so even while it's not a complete answer, perhaps it might be useful (and perhaps someone else can tack on to it or expand on it in another answer). It should just be a matter of replacing the right bits in either the gb
object or gt
object.
UPDATE I managed to find the right grob element for the legend:
gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[4]]$gp$fill <-
desaturate(gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[4]]$gp$fill)
gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[6]]$gp$fill <-
desaturate(gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[6]]$gp$fill)
gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[8]]$gp$fill <-
desaturate(gt$grobs[[12]][[1]][["99_9c27fc5147adbe9a3bdf887b25d29587"]]$grobs[[8]]$gp$fill)
grid.newpage()
grid.draw(gt)
The machinations to find the other gp
elements that need desaturation aren't too bad either.