3

I am trying to select a theme from ggplot2 based on some string given. For demo purposes, consider the following code:

library(dplyr); library(ggplot2)
mtcars %>% 
  ggplot(aes(mpg, wt))+
  geom_point() -> p
all_ggplot2_funs <- getNamespaceExports("ggplot2")
p +
eval(parse(text=paste0(all_ggplot2_funs[grep("theme_", all_ggplot2_funs)][15],
                       "()")))

This works fine and would allow me to use theme_minimal. However, from a security point of view as highlighted in past threads on the eval-parse scenario in different languages, I would like to avoid this.

I could probably use do.call but was looking at something akin to python's () where I can just call a function based on a string e.g.

methods = {pi: math.pi, sum: math.sum}
methods["pi"]()

What could be an R base way to achieve this?

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
  • 1
    related https://stackoverflow.com/questions/6403852/how-to-call-a-function-using-the-character-string-of-the-function-name-in-r – tjebo Dec 19 '21 at 21:16
  • 1
    instead of creating the character vector with exported functions, you could apply akruns solution directly to the namespace with getFunction("theme_minimal", where = "package:ggplot2") – tjebo Dec 19 '21 at 21:20
  • 1
    Thanks @tjebo, it was slightly more complicated than selecting `theme_minimal`. I wanted to get all these themes, store them somewhere (shiny stuff), and then I can later grep based on a provided string but the solution was indeed very [useful](https://github.com/Nelson-Gon/shinymde/commit/810cf8f36c5760b59549842870ee754c6d353fcb). – NelsonGon Dec 19 '21 at 21:23

2 Answers2

4

We may use getFunction

library(ggplot2)
p1 <- p + 
   getFunction(all_ggplot2_funs[grep("theme_", all_ggplot2_funs)][15])()

-checking

> p2 <- p + theme_minimal()
> all.equal(p1, p2)
[1] TRUE
akrun
  • 874,273
  • 37
  • 540
  • 662
2

I don't think you need to have a separately extracted list of functions since it's already accessible in the function list. And It would seem to be more stable against future additions of features to the ggplot2-universe to call the function by name rather than by position in a list so I would argue for:

choice <- "minimal"
p+ match.fun( paste0("theme_", choice) )()
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Thanks, sorry this was just an example. I did use a name based `grep` for the real situation. This is an elegant solution too. – NelsonGon Dec 20 '21 at 00:20