call R script from Shiny App

前端 未结 1 1526
忘了有多久
忘了有多久 2021-02-09 19:27

I developed a shiny app which displays some dynamic charts. These charts are generated at execution time according to the value of some buttons. This shiny app gets the data fro

1条回答
  •  后悔当初
    2021-02-09 19:52

    Scoping in Shiny

    All this largely depends on where exactly you call source(). If you need the data to be found from within both the UI and the server function, you put source() outside the app.

    If you place source() inside the server function, the UI won't be able to find any object created by the script. If you put this inside a render function, the objects are only visible inside that render function. See also Scoping rules for Shiny

    Note that if you have separate server.R and ui.R files and you want the UI to find the objects created by the script, you should add a global.R file to your app directory. The source() command then goes in the global.R file.

    A small example:

    source('testScript.R')
    
    shinyApp(
      fluidPage(
        selectInput("cols", "pick columns",
                     choices = names(x)),
        dataTableOutput("what")),
      function(input, output, session){
        output$what <- renderDataTable(x)
      }
    )
    

    and testScript.R contains one line:

    x <- iris
    

    The key here is:

    1. the script actually has to create these objects
    2. the script should be sourced in the correct spot.

    So if you can do the following:

    shinyApp(
      fluidPage(
        selectInput("cols", "pick columns",
                     choices = names(x)),
        dataTableOutput("what")),
      function(input, output, session){
        source('testScript.R', local = TRUE)
        output$what <- renderDataTable(x)
      }
    )
    

    you get an error about not being able to find x. That's normal, because x is now only defined inside the environment of the server function.

    You still can do this though:

    shinyApp(
      fluidPage(
        dataTableOutput("what")),
      function(input, output, session){
        source('R/testScript.R', local = TRUE)
        output$what <- renderDataTable(x)
      }
    )
    

    Note how x is only needed inside the server function, not inside the UI.

    Using functions

    For functions, the same thing applies. You put the function definition in a script and source it like before. A function is nothing else but an object, so the script essentially creates a function object that then can be found using the exact same scoping rules.

    Keep in mind though that this function should return something if you want to use the result of the function. So put this trivial example in testScript.R:

    myfun <- function(x){
      tmp <- iris[x]
      return(tmp)
    }
    

    And now you can do the following:

    source('testScript.R', local = TRUE)
    
    shinyApp(
      fluidPage(
        selectInput("cols", "pick columns",
                    choices = names(myfun())),
        dataTableOutput("what")),
      function(input, output, session){
        output$what <- renderDataTable(myfun(input$cols))
      }
    )
    

    This doesn't work any longer if you put the source() inside the server function. The UI side won't be able to see myfun() any more.

    rm(list = ls())
    shinyApp(
      fluidPage(
        selectInput("cols", "pick columns",
                    choices = names(myfun())),
        dataTableOutput("what")),
      function(input, output, session){
        source('R/testScript.R', local = TRUE)
        output$what <- renderDataTable(myfun(input$cols))
      }
    )
    # Error in myfun() : could not find function "myfun"
    

    0 讨论(0)
提交回复
热议问题