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 from a raw csv which is previously treated and transformed. I got a Rscript apart from the shiny app to do all those "transformations" of the raw data. What I would like to do is to call this Rscript from the shiny app in order to be executed when the shiny app is launched.
I have already checked these links but it didn't help at all: How can I connect R Script with Shiny app in R? and this one using Source() in Shiny. I checked the Rstudio documentation too: http://shiny.rstudio.com/tutorial/lesson5/.
I think it should be something like this, being procesadoDatos.R the RScript. i just want the source command to be executed at the beginning in order to load the data as the shiny app is starting:
source("procesadoDatos.R",local = TRUE)
shinyServer(function(input, output,session) {
(renderplots, reactives elements and so on)}
The Rscript is the shiny project path as the server.R and UI.R files. I also tried including the path but it didn't work either.
Another thing I tried was to create a function which makes all the transformations and then call it from server.R file after sourcing it:
source("procesadoDatos.R",local = TRUE)
generate_data(ticketsByService_report10.csv)
Being generate_data this function defined in the RScript:
generate_data <- function(csv_file) {
(all those transformation, data frame an so on)}
In all cases I got the same error saying that the data frames which are generated in the RScript aren't found.
Does anyone know what is wrong? Thanks in adavance
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:
the script actually has to create these objects
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"
Related
I have a shiny app (bundled as part of a package) where at the beginning of the server function I create a bunch of reactive data frames that later get used in other parts of the app.
Since quite a few dataframes get created, I wanted to make a simple setup_data() function that could be called at the beginning, in order to help keep the app code tidy. However, since the dfs are created inside a function, I need to use either <<- or assign to make sure they're available in Shiny's server environment.
library(shiny)
setup_data <- function(){
reactiveDat1 <<- shiny::reactiveValues()
reactiveDat1$mydf <<- data.frame(x = 1, y = 2)
reactiveDat2 <<- shiny::reactiveValues()
reactiveDat2$mydf <<- data.frame(x = 5, y = 10)
}
ui <- fluidPage(
titlePanel(""),
sidebarLayout(
sidebarPanel(
),
mainPanel(
)
)
)
server <- function(input, output) {
setup_data()
# rest of app goes here....
}
# Run the application
shinyApp(ui = ui, server = server)
Doing it this way generates a cran NOTE of no visible binding for '<<-' assignment, and in general it is bad practise to do global assigns in a cran package.
Therefore, is there way I can create a function that does the setup like this, but in a way conducive to shiny and cran packages? Ideally I'd like to avoid returning everything in a list, and I haven't found a way to make this work in the Shiny Modules framework as there is no corresponding UI to tie these to.
Is there any other options?
You can setup the data using the global.R file. Any R objects that are created in the global.R file become available to the app.R file, or the ui.R and server.R files respectively. Take a look at how to modularize shiny apps.
EDIT: As pointed out in the comments, you can use local = TRUE to only load objects into the shiny environment.
I'm trying to debug my Shiny app and would like to view a reactive dataframe with e.g. glimpse(df).
Initially I tried to create a breakpoint and then view the environment by my reactive df is a value not an object when used inside server.r. I also tried browser() but was not sure what it would do.
I did some searching on SO and tried various things using sink(), renderPrint() but had no success.
How can I print the contents of glimpse(some_reactive_df()) to the console when I run my app?
Calling print() from within the reactive({}) expression will do that.
library(shiny)
library(dplyr)
shinyApp(
ui <- fluidPage(
selectizeInput("cyl_select", "Choose ya mtcars$cyl ", choices = unique(mtcars$cyl)),
tableOutput("checker") # a needed output in ui.R, doesn't have to be table
),
server <- function(input, output) {
d <- reactive({
d <- dplyr::filter(mtcars, cyl %in% input$cyl_select)
print(glimpse(d)) # print from within
return(d)
})
output$checker <- renderTable({
glimpse(d()) # something that relies on the reactive, same thing here for simplicty
})
})
Assuming you provide Shiny a reason to run (and re-run) your reactive of interest, by having it be involved with a rendering in server() and linked output in ui(). This is usually the case for my debugging scenarios but it won't work unless the reactive is being used elsewhere in app.R.
I'm trying to get a Shiny reactive UI running. It is getting quite complex (in terms of lines of code) so I thought refactoring was a good idea. To put it short, this is my server code:
require(ggplot2)
require(h2o)
shinyServer(function(input, output, session) {
#stop()
localH2o <<- h2o.init(nthreads = 3) #Global variable
source("BuilderServer.R", local = TRUE)[1]
source("ReviewerServer.R", local = TRUE)[1]
# CleanupFUnctions
session$onSessionEnded(function() {
rm(list=ls())
})
})
where I assumed source with local = TRUE was just like copy-paste the content of the R files. So they contain functions of the form output$functionName <- renderUI({code}). The ui code depends on these functions, most of them are reactive, the ui code looks like this:
shinyUI(navbarPage("Metamodel",
tabPanel("Build Custom Model",
fluidRow(
column(12,align="center",
uiOutput("BuilderUpTitle")
)
),
fluidRow(
column(3,
uiOutput("BuilderAxisSelector")
)
)
)
))
In this particular case, the "BuilderUpTitle" function looks like this:
output$BuilderUpTitle <- renderUI({
inFile <- input$BuilderInputFile
if(is.null(input$BuilderInputFile)){
fileInput("BuilderInputFile", "Upload a xlsx file")
} else {
#R Stuff done here with the file
textInput("text", label = h3("Model Title"), value = "Enter text...")
}
})
I wrote the code yesterday and it was working. Today I turned on the computer again, and when launching the app, not even the dependencies from the server.R appear to load (ggplot2 and h2o). The download button from the "BuilderUpTitle" function doesn't appear at all and shiny appears to only execute the ui.R code. I set the workspace to the folder of the sourcefiles and it doesn't help. Even if I uncomment the stop() function from the server, nothing seems to change. Setting breakpoints in RStudio doesn't stop the code inside the server, so that is why I think shiny is not calling the server function. However, the code was working before and I did not modify a single file. I even copied the content of the source files to the server.R code and still they do not load. Is there something obvious that I'm missing? Thank you in advance!
Ok, once again, I found myself what the problem is, and none of the things I said would've made anyone find what was wrong. Here is the tiniest possible code that reproduces the problem:
ui.R
shinyUI(fluidPage(
fluidRow(
uiOutput("itWillLock"),
uiOutput("itWillLock")
)
))
server.R
shinyServer(function(input, output) {
output$itWillLock <- renderUI({
sliderInput("slider","Slider",min=0,max=1,value=0)
})
})
I guess R gets stuck in an infinite loop and never reaches the server.R file. Is this a bug that I should report? Or just common sense will keep people out of this trouble. Thank you!
I want to deploy (to the web) an application made in R/Shiny by a call to the shinyApp() function.
It is possible to make an app by a call to ShinyApp() as follows:
test_app = shinyApp(
ui = fluidPage(
numericInput("n", "n", 1),
plotOutput("plot")
),
server = function(input, output) {
output$plot <- renderPlot( plot(head(cars, input$n)) )
}
)
This retuns an object that represents the app and the app can run by printing that object. I wish to deploy the app that is made usingshinyapps::deployApp( test_app) however that gives me the following error:
Error in shinyapps::deployApp(test_app) :
appDir must be a single element character vector
This is because the deployApp function is expecting a directory not a shinyApp object. Presumably the information to build and therefore deploy the app is contained in the test_app object, but inspecting that object does not reveal much, and it seems to be the same for any app I create:
> str(test_app)
List of 4
$ httpHandler :function (req)
$ serverFuncSource:function ()
$ onStart : NULL
$ options : list()
- attr(*, "class")= chr "shiny.appobj"
>
The code to produce the app is not contained in any obvious way in that object. I suspect the answer may have something to do with R6 reference classes, which I do not understand.
Does anybody know how I might extract the information contained in the app from the test_app object in order to deploy it via the deployApp() function? (or an alternative approach)
I have posted this on the shinyApps users google group but got no response, so I'm trying again here.
The shinyApp command is not meant to be used for app construction, from its' help:
You generally shouldn't need to use these functions to create/run
applications; they are intended for interoperability purposes, such as
embedding Shiny apps inside a knitr document.
deployApp doesn't support shinyApp apps, as you probably found from ?deployApp. That said, it's an easy fix for your (and most) apps, by more or less pasting your commands into files called ui.R and server.R, wrapped in shinyUI() and shinyServer():
ui.R:
library(shiny)
shinyUI(fluidPage(
numericInput("n", "n", 1),
plotOutput("plot")
)
)
server.R:
library(shiny)
shinyServer(function(input, output) {
output$plot <- renderPlot( plot(head(cars, input$n)) )
}
)
Put the two files in a directory and then run deployApp("dir") after testing with runApp("dir")
If you have parts of your shiny app that are not part of server or UI (ie data preprocessing), you will need to paste them above the shiny call in the relevant file. If you are calling you shiny app with arguments, you can either hard code them above your shiny call, or integrate them as reactive values in the shiny itself.
I'm writing shiny app and I want to create mathematical functions from user input - There is textInput where user writes a function, e.g x^2, sin(x)+5 etc. Then, I want to plot this function so I have to concatenate string from textInput and 'function(x)' statement to get R function. As far as I know, I need to have reactive variable which contains the R function. I came up with that:
func<-reactive(
bquote(function(x){ .(parse(text = input$fun)[[1]])}), quoted = TRUE
)
where input$fun is id of textInput. This solution doesn't work and I have no other idea.
You can use f<-function(x) {eval(parse(text=input$func))} to transform the input into a function.
Fron #JoeCheng:
While this certainly works, I'd caution anyone reading this to only use eval() on user input if the app will only be run locally. Apps that do this are not safe to deploy on a server because a user could feed in whatever code they want, for example system("rm -rf ~")
For example, in a shiny app:
app.R
library(shiny)
ui <- shinyUI(fluidPage(
mainPanel(textInput("func", "Function:", ""),
submitButton("Plot!"),
plotOutput("plot")
)
))
server <- function(input, output, session) {
output$plot<-renderPlot({
f<-function(x) {eval(parse(text=input$func))}
x<-1:10
plot(x,f(x))
}
)
}
shinyApp(ui = ui, server = server)
Would give you this: