0

Is it possible to conditionally format elements in a custom ggplot2 theme (such as the presence of legend, position of legend or font styling etc) based on the geom selected? For example, if user wants to create a line graph plot then the theme would be read that as a condition being satisfied and move the legend position to the bottom of the graph.

The most similar question I could find was in: Conditionally modify ggplot theme based on presence of facets?

But I am not sure if this approach (and if so, how) could be applied to other components of the graph such as the type of geom. New to R, thanks. Not sure where to go from here.

717j
  • 9
  • 1
  • 3
    It's possible, but I'm reminded of Hebb's law: "If something's not worth doing, it's not worth doing well". It would likely require at the minimum a new S3 class, and probably overwriting the `+.gg` method. You would need to handle cases where plots have multiple different geom layers. It would likely reduce flexibility, increase complexity, and be of very little benefit to the end user. Is there a use-case you have in mind? – Allan Cameron Dec 21 '22 at 20:44
  • I am just looking to automate some features of a custom theme/package that I am playing around with. I am hoping to allow end-user to skip suppressing the legend on certain graphs where a legend would not be useful. So ideally it would recognize geom_x and suppress the legend. My question was more general because I felt it would be interesting to explore other capabilities if I understand the general method of calling the plot type and conditionally formatting it based on that. – 717j Dec 21 '22 at 20:49
  • I see. `ggplot2` is already pretty flexible and easy to use. Removing legends can be done in a variety of ways already. I think if you are fairly new to R but just want to provide some easy-to-use formatting options, then you could write a function that takes a ggplot and alters it. This is much easier than writing a new type of object that works via the `+` operator – Allan Cameron Dec 21 '22 at 20:56
  • 1
    Not sure the issue without attempted code, but ... `gg <- ggplot(...); if (somecondition) gg <- gg + geom_line(..) + theme(legend.position="bottom"); if (someothercondition) gg <- gg + geom_bar(..)`. – r2evans Dec 21 '22 at 21:02
  • Welcome to SO, 717j! Questions on SO (especially in R) do much better if they are reproducible and self-contained. By that I mean including attempted code (please be explicit about non-base packages), sample representative data (perhaps via `dput(head(x))` or building data programmatically (e.g., `data.frame(...)`), possibly stochastically), perhaps actual output (with verbatim errors/warnings) versus intended output. Refs: https://stackoverflow.com/q/5963269, [mcve], and https://stackoverflow.com/tags/r/info. – r2evans Dec 21 '22 at 21:02

1 Answers1

1

If you really want to do this you can, though I'm not convinced it is worth the effort. You can create a new S3 class and write a ggplot_add method for it:

library(ggplot2)

special_theme <- function(...) {
  thm <- theme(...)
  class(thm) <- c("special_theme", class(thm))
  thm
}

Suppose we want to suppress the legend if there are any geom_point layers present, but otherwise we keep the legend, then our method might look like this:

ggplot_add.special_theme <- function(object, plot, object_name) {
  class(object) <- class(object)[-1]
  if(any(sapply(plot$layers, function(x) inherits(x$geom, "GeomPoint")))) {
    return(plot + object + theme(legend.position = "none"))
  }
  else plot + object
}

So, a standard geom_point will trigger the legend to go away:

ggplot(mtcars, aes(wt, mpg, color = cyl)) + 
  geom_point() + 
  special_theme()

But if there is no point layer, the legend remains.

ggplot(mtcars, aes(wt, mpg, color = cyl)) + 
  geom_col() + 
  special_theme()

Created on 2022-12-21 with reprex v2.0.2

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • Thanks, that is useful and exactly what I was looking for! Follow up question, how do you know to condition to x$geom to call the type of plot being built. Is there documentation that one can look up to see what other things can be used such as x$plot or even x$position. – 717j Dec 27 '22 at 01:44
  • `names(x)` will show you the names of the various members of the ggplot object – Allan Cameron Dec 27 '22 at 06:50