rstudio / shinymeta

Record and expose Shiny app logic using metaprogramming
https://rstudio.github.io/shinymeta
223 stars 14 forks source link

Managing complicated control flow #83

Open CedricMidoux opened 4 years ago

CedricMidoux commented 4 years ago

Hello and thank you for your package.

In this example, what is the correct way to write the condition inside metaRender for a better display with the Show code button.

library(shiny)
library(shinymeta)
library(ggplot2)

ui <- fluidPage(

  titlePanel("Old Faithful Geyser Data"),

  sidebarLayout(
    sidebarPanel(
      sliderInput("bins",
                  "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30),
      radioButtons("column",
                   "Select column:",
                   choices = c("eruptions", "waiting"))
    ),

    mainPanel(
      outputCodeButton(plotOutput("plot"))
    )
  )
)

server <- function(input, output) {

  output$plot <- metaRender(renderPlot, {
    p <- ggplot(faithful, aes_string(..(input$column)))
    p <- p + geom_histogram(bins = ..(input$bins))
    if (..(input$bins<=30)) {
      p <- p + theme_dark()
    } else {
      p <- p + theme_bw()
    }
    p
  })

}

shinyApp(ui = ui, server = server)

Here, the Show code button show :

library(ggplot2)
p <- ggplot(faithful, aes_string("eruptions"))
p <- p + geom_histogram(bins = 30L)
if (TRUE) {
  p <- p + theme_dark()
} else {
  p <- p + theme_bw()
}
p

I would like it to simply display:

library(ggplot2)
p <- ggplot(faithful, aes_string("eruptions"))
p <- p + geom_histogram(bins = 30)
p <- p + theme_dark()
p

Many thanks in advance for your support!

cpsievert commented 4 years ago

There are a couple different ways to currently approach this problem. The most straight-forward would be to duplicate code in each case (just make sure to that you're always returning a metaExpr():

output$plot <- metaRender2(renderPlot, {
    if (input$bins<=30) {
      metaExpr(ggplot(faithful, aes_string(..(input$column))) + geom_histogram(bins = ..(input$bins)) + theme_dark())
    } else {
      metaExpr(ggplot(faithful, aes_string(..(input$column))) + geom_histogram(bins = ..(input$bins)) + theme_bw())
    }
  })

Clearly that's not ideal if there's lots of code that needs duplicating. A more sophisticated approach that avoids duplication might be through clever use of quote() and eval():

output$plot <- metaRender2(renderPlot, {
    my_theme <- if (input$bins<=30) quote(theme_dark()) else quote(theme_bw())
    metaExpr({
      p <- ggplot(faithful, aes_string(..(input$column)))
      p <- p + geom_histogram(bins = ..(input$bins)) 
      p + eval(..(my_theme))
    })
  })

This generates valid code, but it's also not ideal in that it generates code that has an unnecessary eval() in it (e.g., p + eval(theme_dark())).

I don't immediately see an approach that both avoids duplication and generates "perfectly human-like" code...maybe @jcheng5 can think of a better alternative?

CedricMidoux commented 2 years ago

Hello, Do you have a new approach for this problem? Thank you in advance