如何在Shiny中使用checkboxGroupInput来有效地控制ggplot2图中的多个反应层?

时间:2017-06-08 03:28:48

标签: r checkbox ggplot2 shiny

我在图表中制作了三个反应层。在下面的可重现示例中,图形以function1绘制开始。如果我检查function2,闪亮重新计算并重绘function1和function2。然后,如果我勾选function3,则重新计算并重新绘制所有3个函数。

假设我想要运行的函数是非常长的推论,每个都需要几分钟。

如何制作它以便在我检查(或取消选中)一个功能时,闪亮不会重新计算并重绘所有已检查的功能?

在下面的代码中,我已经包含了print语句,这些语句显示每次调用renderPlot时都会运行每个被动运行(这是输入$ fun更改时)。

library(shiny)
library(ggplot2)
x <-  seq(0, 10, by=0.1)

runApp(shinyApp(

  ui = shinyUI(fluidPage(
    titlePanel("Test Shiny"),
    sidebarLayout(
      sidebarPanel(
        checkboxGroupInput("fun", label = "Function", 
                           choices = list("function1: x^2" = 1, 
                                          "function2: x^2 + x" = 2, 
                                          "function3: x^2 - x" = 3),
                           selected = c(1))
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  )),

  server = shinyServer(function(input, output) {


    fn1 <- reactive({ 
      print("we are in fn1 <- reactive({})")
      if (1 %in% input$fun ) { 
        geom_line(mapping = aes(x, y=x^2), color="blue") }
    })


    fn2 <- reactive({
      print("we are in fn2 <- reactive({})")
      if (2 %in% input$fun)  { 
        geom_line(mapping = aes(x, y=x^2 + x), color="red") }
    })


    fn3 <- reactive({
      print("we are in fn3 <- reactive({})")
      if (3 %in% input$fun) { 
        geom_line(mapping = aes(x, y=x^2 - x), color="green") }
    })

    output$plot <- renderPlot({

      cat("\n we are in output$plot <-  renderPlot({}) \n")
      ggplot() + fn1() + fn2() + fn3()
    })  
  })
))

我可以使用单个复选框(checkboxInput)实现此效率,但我不想使用单个复选框。单个复选框看起来不太好,除非有办法让它们看起来更像复选框组输入?

我一直试图解决这个问题,并搜索了一段时间。我非常感谢任何帮助!

EDIT 以下是使用基础R plot()lines()响应@Jimbou闪亮代码的一些代码。请参阅@Jimbou提供的闪亮代码下面的评论。

    output$plot <- renderPlot({
  cat("\n we are in output$plot <- renderPlot({}) \n")
  plot(NULL, xlim = c(0,10), ylim = c(0,100))
  if(1 %in% input$fun) {
    print("we are in  if(1 %in% input$fun){} ")
    lines(x=x, y=x^2, col=2)
  }
  if(2 %in% input$fun) {
    print("we are in  if(2 %in% input$fun){} ")
    lines(x=x, y=x^2 + x, col=3)
  }
  if(3 %in% input$fun) {
    print("we are in  if(3 %in% input$fun){} ")
    lines(x=x, y=x^2 - x, col=4)
  }
})

3 个答案:

答案 0 :(得分:0)

我认为最接近的是延迟图层处理,直到您单击操作按钮明确告诉服务器何时开始处理图。

library(shiny)
library(ggplot2)
x <-  seq(0, 10, by=0.1)

runApp(shinyApp(

  ui = shinyUI(fluidPage(
    titlePanel("Test Shiny"),
    sidebarLayout(
      sidebarPanel(
        checkboxGroupInput("fun", label = "Function", 
                           choices = list("function1: x^2" = 1, 
                                          "function2: x^2 + x" = 2, 
                                          "function3: x^2 - x" = 3),
                           selected = c(1)),
        actionButton(inputId = "btn_update_plot",
                     label = "Update Plot")
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  )),

  server = shinyServer(function(input, output) {


    p <- eventReactive(
      input$btn_update_plot,
      {
        ggp = ggplot()

        if (1 %in% input$fun ) 
        { 
          ggp <- ggp + geom_line(mapping = aes(x, y=x^2), color="blue") 
        }

        if (2 %in% input$fun)  
        { 
          ggp <- ggp + geom_line(mapping = aes(x, y=x^2 + x), color="red") 
        }

        if (3 %in% input$fun) 
        { 
          ggp <- ggp + geom_line(mapping = aes(x, y=x^2 - x), color="green") 
        }

        ggp
      }
    )

    output$plot <- renderPlot({
      print("we are in output$plot <-  renderPlot({})")
      p()
    })  
  })
))

答案 1 :(得分:0)

这是一个使用基线R绘图功能和线条的解决方案。

library(shiny)
library(ggplot2)
x <-  seq(0, 10, by=0.1)

runApp(shinyApp(

  ui = shinyUI(fluidPage(
    titlePanel("Test Shiny"),
    sidebarLayout(
      sidebarPanel(
        checkboxGroupInput("fun", label = "Function", 
                           choices = list("function1: x^2" = 1, 
                                          "function2: x^2 + x" = 2, 
                                          "function3: x^2 - x" = 3),
                           selected = c(1))
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  )),

  server = shinyServer(function(input, output) {

    output$plot <- renderPlot({
      plot(NULL, xlim = c(0,10), ylim = c(0,100))
      if(1 %in% input$fun) lines(x=x, y=x^2, col=2)
      if(2 %in% input$fun) lines(x=x, y=x^2 + x, col=3)
      if(3 %in% input$fun) lines(x=x, y=x^2 - x, col=4)
    })  
  })
))

答案 2 :(得分:0)

我已经考虑过这样做的方法。在下面的代码中,checkboxGroupInput像以前一样具有选项“function1”,“function2”或“function3”。如果选中“function1”和“function2”,然后用户检查“function3”,则只计算function3。在原始帖子的代码中,有光泽会计算所有三个函数。

checkboxGroupInput中的任何更改都将使这三个响应式表达式无效 fn1 <- reactive({...})fn2 <- reactive({...})fn3 <- reactive({...}) 导致它们被重新运行。

但是在下面的新代码中,上面的每个反应式表达式(如果已经检查过)通过另一个反应式表达式返回缓存值

我已经包含了print语句,表明在checkboxGroupInput(“function1”,“function2”或“function3”)中检查或取消选中一个框不会导致Shiny重新计算所有已检查的函数,因为我的原始函数会闪亮上面的代码

我之前提到过使用单个复选框,所以我还提供了一个单一复选框“relation4”的示例,以显示使用单个复选框checkboxInput(),不会导致其他被动不必要地重新运行

NB观看打印到控制台的内容

library(shiny)
library(ggplot2)

runApp(shinyApp(

  ui = shinyUI(fluidPage(
    titlePanel("Test Shiny"),
    sidebarLayout(
      sidebarPanel(
        checkboxGroupInput("fun", label = "Function", 
                           choices = list("function1: x^2" = 1, 
                                          "function2: x^2 + x" = 2, 
                                          "function3: x^2 - x" = 3),
                           selected = c(1)),
        h5("A single checkbox"),
        checkboxInput("relation4", label = "relation4", value = FALSE)
      ),
      mainPanel(
        plotOutput("plot")
      )
    )
  )),

  server = shinyServer(function(input, output) {

    x <-  seq(0, 10, by=0.1)

    fn1.geom <- reactive({
      print("we are in fn1.geom <- reactive({})")
      geom_line(mapping = aes(x, y=x^2), color="blue")
    })
    fn1 <- reactive({
      print("we are in fn1 <- reactive({})")
      if (1 %in% input$fun ) { 
        fn1.geom()}
    })

    fn2.geom <- reactive({
      print("we are in fn2.geom <- reactive({})")
      geom_line(mapping = aes(x, y=x^2 + x), color="red") 
    })
    fn2 <- reactive({
      print("we are in fn2 <- reactive({})")
      if (2 %in% input$fun)  { 
        fn2.geom()}
    })

    fn3.geom <- reactive({
      print("we are in fn3.geom <- reactive({})")
      geom_line(mapping = aes(x, y=x^2 - x), color="green")
    })
    fn3 <- reactive({
      print("we are in fn3 <- reactive({})")
      if (3 %in% input$fun) { 
        fn3.geom() }
    })


    # using single checkbox input (checkboxInput() above)
    relation4.geom <- reactive({
      print("we are in relation4.geom <- reactive({})")
        list( geom_line(mapping = aes(x, y=x), color="orange"),
              geom_line(mapping = aes(x, y=6*x), color="purple"),
              geom_line(mapping = aes(x, y=11*x), color="violet") ) 
    })
    relation4 <- reactive({
      print("we are in relation4 <- reactive({})")
      if (input$relation4) {
        relation4.geom()
      }
    })


    output$plot <- renderPlot({
      cat("\n we are in output$plot <-  renderPlot({}) \n")
      ggplot() + fn1() + fn2() + fn3() + relation4() 
    })

  })
))