print() not working within reactive function - r

I typically use print when I'm building shinyapps as a way to check to make sure what I think should happen is actually what is happening. However, I've run into a problem where print is no longer printing to the R console when I have an app running. Here's a simple example of what I've tried:
ui <- fluidPage(
sliderInput("slider", "Slider Range",
min = 0, max = 5000, value = c(11))
)
server <- function(input, output){
print("Non-Reactive")
new <- reactive({
print("Reactive")
print(input$slider)
})
}
shinyApp(ui, server)
Within the R console, I get: [1] "Non-Reactive" and that is it. No [1] "Reactive" or [1] 11 for my slider.
I know it used to work before, but I'm not sure what changed. If there's another easier way to check/debug code for shinyapps aside from print I'd love to know my other options too.
Note: My shinyapp package is version 0.13.0. My RStudio version is 0.99.491. R is currently 3.2.2.

As jenesaisquoi mentioned, I had to use observe(new()) later in my server code in order to observe changes in the reactive() function. I must just by dumb luck never used print() in a reactive() function when testing things.

Related

Run App gives no result R shiny app and crashes RStudio

I'm having an issue with the running of a R shiny app. Here's what I do:
open RStudio
load the shiny code (e.g. app.R)
set the wd
library(shiny)
press on "Run App"
Then nothing happens.
And if I try to terminate the execution, R does not answer anymore and says to force the closing of RStudio.
Here's one of my codes (I tried some, so I don't think this is the issue, but I report one anyway):
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Un'applicazione con uno slider"),
sidebarLayout(
h1("Sposta lo Slider!"),
sliderInput("slider1", "Spostami!", 0, 100, 0)
),
mainPanel(
h3("Valore dello slider:"),
textOutput("text")
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$text <- renderText(input$slider1)
}
# Run the application
shinyApp(ui = ui, server = server)
Do you have any advice to give me in order to make anything happen? I have no errors shown, so I don't know what to do...
I just see "runApp(...mypath.../app)" and blank space after it.
Thank you in advance.
Edit 1:
I also tried this, but nothing happened (as before):
library(shiny)
runExample("01_hello")
Edit 2: Copy-pasting the code directly in the console doen not work either
I was experiencing the same issue with R 4.1 on Windows 10. Updating all packages seems to have solved it:
update.packages(ask = FALSE, checkBuilt = TRUE)

Assign to global shiny environment in package

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.

Shiny reactive UI not running server code

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!

reactivity and rhandsontable

I have recently discovered the rhandsontable package in r and it will be very useful in some of my r shiny projects. I have slightly modified what I saw here Get selected rows of Rhandsontable as a little tester for what I will use this package for.
I want to be able to let users change values of the data frame from within r using the rhandsontable package.So here I want df[1,1] to update each time I change that value. I am just a bit confused when it comes to wrapping a reactive function around render functions especially the renderRHandsontable function. I have used reactive functions with plotting but this is a bit different.
library(shiny)
library(rhandsontable)
ui=fluidPage(
rHandsontableOutput('table'),
verbatimTextOutput('selected'),
verbatimTextOutput("tr")
)
server=function(input,output,session)({
a<-c(1,2)
b<-c(3,4)
c<-rbind(df1,df2)
df1<-data.frame(df3)
#need reactive function around the following
output$table=renderRHandsontable(
rhandsontable(df1,selectCallback = TRUE,readOnly = FALSE)
)
output$selected=renderPrint({
cat('Selected Row:',input$table_select$select$r)
cat('\nSelected Column:',input$table_select$select$c)
cat('\nSelected Cell Value:',input$table_select$data[[input$table_select$select$r]][[input$table_select$select$c]])
df1[input$table_select$select$r,input$table_select$select$c]<-input$table_select$data[[input$table_select$select$r]][[input$table_select$select$c]]
})
#need reactive function around the following
output$tr <- renderText({
df1[1,1]
})
})
# end server
shinyApp(ui = ui, server = server)
It is an interesting area that will open up a lot in my shiny apps for users to play around with.
Thanks
Your code here is not reproducible. In the beginning of your server function, you used rbind() on df1 and df2when neither of these objects exist yet. R will throw an error (and it should!)
Because of that I will have to assume that your data frame is in fact the following:
a<-c(1,2)
b<-c(3,4)
c<-rbind(a,b)
df1<-data.frame(c)
To bind the reactivity output from Rhandsontable to your textOutput, you can use the observe() function from Shiny or even better, the handy hot_to_r function from rhandsontable itself. This function converts the handsontable data to R object.
Without changing your ui function, this will be your server function:
server <- function(input,output,session)({
a<-c(1,2)
b<-c(3,4)
c<-rbind(a,b)
df1<-data.frame(c)
output$table<-renderRHandsontable(
rhandsontable(df1)
)
#use hot_to_r to glue 'transform' the rhandsontable input into an R object
output$tr <- renderText({
hot_to_r(input$table)[1,1]
})
})
Then proceed to call your Shiny app as usual: shinyApp(ui = ui, server = server) and your output$tr now reacts to any edits on your table.

Unit Testing Shiny Apps

So I have been writing a fairly detailled shiny app, and in the future will need updating as the functionality behind what is run is constantly changing.
What I need to be able to do is have unit tests (either using testthat or another library more useful for shiny apps) that enables me to run these tests in a more automated fashion.
I have written a simple shiny app. For the sake of testing in this would like a way to know that if I choose the number 20 in the numeric input then I get 400 as the output$out text. But want to be able to do this without actually running the app myself.
library(shiny)
ui <- fluidPage(title = 'Test App',
numericInput('num', 'Number', 50, 1, 100, 0.5),
'Numeric output',
textOutput('out')
)
server <- function(input, output, session) {
aux <- reactive(input$num ^ 2)
output$out <- renderText(aux())
}
shinyApp(ui = ui, server = server)
As many already mentioned, you can use the package shinytest combined with testthat.
Here a simple example:
library(shinytest)
library(testthat)
context("Test shiny app")
#open shiny app
app <- ShinyDriver$new('path_to_shiny_app')
test_that("app gets expected output", {
#set numeric input
app$setInputs(num = 20)
#get output
output <- app$getValue(name = "out")
#test
expect_equal(output, "400")
})
#stop shiny app
app$stop()
I see two potential approaches here – testing the underlying functionality, and performing tests of the web application itself. Note that the latter actually would require running the server, but is a more accurate representation of if your web app works or not.
By testing the underlying functionality, what I mean is refactoring the calculations you currently perform in the server to their own, independent functions. Instead of squaring the number directly in the server, you ought to separate the functionality from the server so it can be tested. For example, like so:
square_of_number <- function(n) return(n^2)
Now, you can separately test the square_of_number function for its expected output.
library('testthat')
square_of_number <- function(n) return(n^2)
expect_equal(square_of_number(4), 16)
Further, if you want to test the application itself, you could also create tests using a headless browser on the actual UI you generate with Shiny. One method as suggested in the comments is using Shinytest, but one approach that I'd suggest trying is:
Running the server with a specific port,
Interfacing this server with a tool like rvest or RSelenium to manipulate the page and then scrape the output,
then verifying said output with testthat.

Resources