ggplot2 arguments
moduleThis vignette will guide you through implementation of custom
ggplot2::labs and ggplot2::theme for
ggplot2 graphics based modules. We will enable 2 ways of
updating ggplot2::labs and ggplot2::theme by
the end users. The ggplot2 specification could be updated
with the teal.ggplot2_args options variable or
a ggplot2_args argument in a tm_g_* module. We
still take into account default specification set up by the module
creator in the server function, which has the lowest priority.
The implementation should consist of 5 steps:
ggplot2_args argument to the
tm_g_* function and then its server function. The default
should be set to the
ggplot2_args(labs = list(), theme = list()) function for
single plot. and
list(default = ggplot2_args(labs = list(), theme = list()))
multi-plot modules.stopifnot or
checkmate) of the ggplot2_args argument to the
tm_* function. The validation is more complex for
multi-plot modules, where the ggplot2_args could be a
list. The module creator has to provide a list of plots
names, which should be validated at this step and added to the
param field in roxygen2. For multi-plot
modules the step
if (is_ggplot2_args) ggplot2_args <- list(default = ggplot2_args)
is recommended.ggplot2_args sources with
resolve_ggplot2_args().parse_ggplot2_args() function which will
parse inputs to list of expressions.Reduce(function(x, y) call("+", x, y), list(...) function
could be helpful at this step.The resolve_ggplot2_args() function picks the first non
NULL value for each argument, checking in order:
ggplot2_args argument provided by the end user. For
multi-plot case, per plot (user_plot) and then default
(user_default) setup.options),
teal.ggplot2_args.module_plot which is a developer setup.When a more complex ggplot2 object has to be used inside
the ggplot2_args function, then a base::quote
function would prevent an object expansion in Show R Code. For example
the ggplot2::element_text function returns a complex
object, then we should use code like
ggplot2_args(theme = list(plot.title = quote(ggplot2::element_text(size = 20))))
to prevent Show R Code expansion.
If you get a
promise already under evaluation: recursive default argument reference or earlier problems?
error, then probably your function argument has the same name as a
function which is an input for it. To solve the problem please use
:: to prefix it directly to a specific package, like
new_fun <- function(ggplot2_args = ggplot2_args()).
library(shiny)
library(ggplot2)
library(teal.widgets)
options("teal.ggplot2_args" = ggplot2_args(labs = list(caption = "Caption from options")))
user_ggplot2_args <- list(
  default = ggplot2_args(
    labs = list(title = "User default title"),
    theme = list(legend.position = "right", legend.direction = "vertical")
  ),
  plot1 = ggplot2_args(
    labs = list(title = "User title"),
    theme = list(legend.position = "right", legend.direction = "vertical")
  )
)
ui <- fluidPage(
  shinyjs::useShinyjs(),
  tags$div(plotOutput("plot1"))
)
server <- function(input, output, session) {
  dev_ggplot2_args <- ggplot2_args(
    labs = list(subtitle = "Dev substitle"),
    theme = list(legend.position = "none")
  )
  f_ggplot2_expr <- parse_ggplot2_args(
    resolve_ggplot2_args(
      user_plot = user_ggplot2_args$plot1,
      user_default = user_ggplot2_args$default,
      module_plot = dev_ggplot2_args
    )
  )
  plot_expr <- substitute(
    expr = {
      gg <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
        geom_point() +
        ggplot_expr_labs +
        ggplot_expr_theme
      print(gg)
    },
    env = list(ggplot_expr_labs = f_ggplot2_expr$labs, ggplot_expr_theme = f_ggplot2_expr$theme)
  )
  print(plot_expr)
  output$plot1 <- renderPlot(eval(plot_expr))
}
if (interactive()) {
  shinyApp(ui, server)
}