dfife
dfife

Reputation: 358

Convert ggplot to greyscale with stat_summary

I have an R package as a back-end engine for a GUI (JASP). I want to be able to have people convert their images to greyscale (for publication printing). For most plots, I can use scale_colour_grey(), but that doesn't work when colors are specified within stats_summary. For example:

# simulate data
set.seed(1212)
y = rnorm(100)
g = sample(c("a", "b"), 100, T)
d = data.frame(y=y, g=g)

### create ggplot
plot = ggplot(data=d, aes(x=g, y=y)) +
  geom_jitter() + 
  stat_summary(fun="mean", geom="point", size=3, color="red") +
  stat_summary(geom="errorbar", size=3, color="red") +
  theme_bw()

### converting to greyscale doesn't work
plot + scale_colour_grey()

After some research, I learned you can dissect the ggplot object then rebuilt it:

### can rebuilt ggplot object, but not ideal
q <- ggplot_build(plot)
q$data[[2]]$colour <- "black"
q$data[[3]]$colour <- "black"
q <- ggplot_gtable(q)
plot  = ggplotify::as.ggplot(q)
plot

That works fine, but I try to include as few dependencies in my R packages as possible. Do I really have to resort to another package (ggplotify) in order to modify the color coming from stat_summary?

A few notes: I don't want to have to modify the original stat_summary statement. Let's just pretend that cannot be modified. Also, let's assume I cannot add another package (aside from ggplot2, which is already loaded). Remember, I'm a "guest" in the JASP framework and I don't want to have to add another package to the list of packages they have to store.

Upvotes: 0

Views: 252

Answers (1)

Allan Cameron
Allan Cameron

Reputation: 174516

You can actually get at the ggplot object before it is built, reach into the layer that has the coloured object and change it. Here's a full reprex:

library(ggplot2)

#  simulate data
set.seed(1212)
y = rnorm(100)
g = sample(c("a", "b"), 100, T)
d = data.frame(y=y, g=g)

### create ggplot
p <- ggplot(data=d, aes(x=g, y=y)) +
  geom_jitter() + 
  stat_summary(fun="mean", geom="point", size=3, color="red") +
  stat_summary(geom="errorbar", size=3, color="red") +
  theme_bw()

p 


p$layers[[3]]$aes_params$colour <-  "gray50"

p

If you want a more general approach to change a particular geom's colour, you could do something like this function:

recolour_geom <- function(gg_plot, geom, colour = "gray50")
{
  ss <- which(sapply(p$layers, function(l) {
                       paste(gsub("GEOM|GG|PROTO", "", toupper(class(l$geom))),
                       collapse = "")}) %in% toupper(geom))
  
  if (length(ss) > 0)
  {
    for (i in ss)
    {
      p$layers[[i]]$aes_params$colour <- colour
    }
  }
  p
}

Which allows you to do, for example

recolour_geom(p, "errorbar", "blue")
recolour_geom(p, "point", "green")

enter image description here

Be aware though that this changes the ggplot by reference, so p is changed as a side effect of the function.

Created on 2020-08-14 by the reprex package (v0.3.0)

Upvotes: 1

Related Questions