R Shiny app progress Indicator for loading data - r

Shiny is our internal BI tool. For our Shiny apps, we load data before shinyServer running:
load("afterProcessedData.RData")
# or dt = fread("afterProcessedData.csv")
shinyServer(function(input, output, session){ ...
However, some of apps are loading big files and they take up to 30s to load up. Many users, when they open a page, don't know whether the page is broken since it is stuck when it is loading. They may close it or click filters, which may cause an error. In this case, a progress bar will be very helpful. I notice withProgress() may help but it has to be inside reactive() or renderXx().
One way I can do is to have laod() warpped with reactive() inside the shinyServer(function(input, output, session){ but my concern is it will slower the performance. And my users very care about the responsive performance.
Any suggestions for this situation?
Edit: I guess there is not an easy way to do this. I have another thought. Maybe I can show a text on the screen saying 'the data is loading', but I have to make it disappear after the first table gets show up. However, I don't know how to set up the condition. Below is my code showing first table:
dashboardBody(
fluidRow(
tabBox(width = 12,
tabPanel("Summary",
dataTableOutput("data1")),
Thank you in advance!

Even though I am still interested in knowing how to add process bar for load(), I have implemented the alternative solution, which is good for now. It has a text saying 'the data is loading...' on the page, and it will disappear after first table shows up.
#server.R firstData is a reactive function to get the data for 1st table
output$firstTable = reactive({
return(is.null(firstData()))
})
#ui.R
conditionalPanel(
condition = "output.firstTable",
box(width = 12,
h1("The data is loading...")
)
)

To reference the intriguing note from #user5249203 , withSpinner() looks to be a useful option for this functionality and is a part of the shinycssloaders package. I have not used myself, but it is definitely an intriguing package that happens to be on CRAN and to have some nice examples: https://andrewsali.shinyapps.io/example/

Related

R Shiny - cache big dataframe

I'm quite new to Shiny, so my apologizes if my question is an easy one. I tried to check on google and stackoverflow but couldn't locate a simple and helpful answer so far.
What's my goal/issue: I'm coding a Shiny page that displays a table with hundreds of thousands of rows.
Data is sourced from different databases, manipulated, cleaned, and displayed to all the users upon request.
Problem 1: in order to load all the data, the script takes almost 5minutes
Problem 2: if at 8:00am user1 requests this data and at 8:05am user2 requests the same data, two different queries are launched and also two different spaces in memory are used to show exactly the same data to two different users.
So the question is: shall I use a cache system to enhance this process?
if not, what else shall I use?
I found a lot of official Shiny documentation on caching plots but nothing related to caching data (and I found this quite surprising).
Other useful information: data in cache should be deleted every evening around 10pm since new data will be available the next day / early morning.
Code:
ui <- dashboardPage( # https://rstudio.github.io/shinydashboard/structure.html
title = "Dashboard",
dashboardHeader(title = "Angelo's Board"),
dashboardSidebar( # inside here everything that is displayed on the left hand side
includeCSS("www/styles.css"),
sidebarMenu(
menuItem('menu 1', tabName = "menu1", icon = icon("th"),
menuItem('Data 1', tabName = 'tab_data1'))
)),
dashboardBody(
tabItems(
tabItem(tabName = 'tab_data1')),
h3("Page with big table"),
fluidRow(dataTableOutput("main_table"))
))
server <- function(input, output, session) {
output$main_tabl <- renderDataTable({
df <- data.frame(names = c("Mark","George","Mary"), age = c(30,40,35))
})
}
cat("\nLaunching 'shinyApp' ....")
shinyApp(ui, server)
Resources I used to check for potential solution:
How to cache data in shiny server? but apparently I cannot use Jason Bryer package
https://shiny.rstudio.com/reference/shiny/1.2.0/memoryCache.html but I have no idea of how to use this code applied to my example
https://shiny.rstudio.com/articles/plot-caching.html is mainly focused on plot caching
Any help would be much appreciated. Thanks
I would break out the bulk of your ETL processes into a separate R script and set that script to run on a cron. You can then have this script write out the processed dataframe(s) to a .feather file. Then have your shiny app load the feather file(s) - feather is optimized for reading so should be fast.
Example, take the necessary libraries and code out of your server.R (or app.R) file, and create a new R script called query.R. That script performs all the ETL operations and finally writes out your data to a .feather file (requires the feather package). Then create a crontab to run that script as often as needed.
Your server.R script then just needs to read in that feather file when the app loads and you should see a significant performance improvement. In addition, you have have the query.R script run during off hours so that performance on the linux box isn't negatively impacted.
Another option, put this DataFrame in global.R and change /etc/shiny-server/shiny-server.conf by adding «app_idle_timeout 0» after «location / {». This will disable application idle timeouts in Shiny Server, so global.R will be in RAM for all users.
To prevent first user from long data loading, you can put in cron «#reboot wget -O index.html localhost:3838» on your server, so on every reboot global.R will load to memory automatically.
Also, about pre-cache organisation you can read here.

How to convert a Shiny app consisting of multiple files into an easily shareable and reproducible Shiny example?

There are resources on how to create a Minimal, Complete, and Verifiable example in general on Stack Overflow, and on how to make a great R reproducible example. However, there are no similar guidelines for shiny questions, while adhering to certain standards makes it much more likely that quality answers will be given, and thus that your question will be resolved.
However, asking a good Shiny question can be difficult. shiny apps are often large and complex, use multiple data sources, and the code is often split over multiple files, making it difficult to share easily reproducible code with others. Even though a problem may be caused in server.R, the example is not reproducible without the contents of ui.R (and possibly other files like stylesheets or global.R). Copy-pasting the contents of all these files individually is cumbersome, and requires other users to recreate the same file structure to be able to reproduce the problem.
So; how to convert your shiny app into a good reproducible example?
Example data
Of course, all guidelines regarding sample data mentioned in the answer on the question “how to make a great R reproducible example” also hold when creating questions related to Shiny. To summarize: Make sure no additional files are needed to run your code. Use sample datasets like mtcars, or create some sample data with data.frame(). If your data is very complex and that complexity is really required to illustrate the issue, you could also use dput(). Avoid using functions like read.csv(), unless of course you have questions related to functions like fileInput.
Example code
Always reduce your code to the bare minimum to reproduce your error or unexpected behavior. This includes removing calls to additional .CSS files and .js files and removing unnecessary functions in the ui and the server.
Shiny apps often consist of two or three files (ui.R, server.R and possibly global.R), for example this demo application. However, it is preferable to post your code as a single script, so it can easily be run by others without having to manually create those files. This can easily be done by:
wrapping your ui with ui <- fluidPage(…),
the server with server <- function(input,output, session) {…},
and subsequently calling shinyApp(ui, server).
So a simple skeleton to start with could look as follows:
library(shiny)
ui <- fluidPage(
)
server <- function(input,output,session) {
}
shinyApp(ui, server)
Working Example
So, taking all the above into account, a good Minimal, Complete, and Verifiable example for a Shiny application could look as follows:
library(shiny)
df <- data.frame(id = letters[1:10], value = seq(1,10))
ui <- fluidPage(
sliderInput('nrow', 'Number of rows', min = 1, max = 10, value = 5),
dataTableOutput('my_table')
)
server <- function(input, output, session) {
output$my_table <- renderDataTable({
df[1:input$nrow,]
})
}
shinyApp(ui, server)
Adding CSS
There are multiple ways to add custom CSS to a Shiny application, as explained here. The preferred way to add CSS to a Shiny application in a reproducible example is to add the CSS in the code, rather than in a separate file. This can be done by adding a line in the ui of an application, for example as follows:
tags$head(tags$style(HTML('body {background-color: lightblue;}'))),

Is shiny able to use interactive ui?

I'm almost done with my project and I'm trying to do some aesthetic changes to my app in order to be more user friendly and attractive.
The idea:
Since my app requires to upload a table in order to work, I thought it would be better if I put a stand alone large upload button in the middle of the screen and then a navigation bar would appear with the results, plots, downloads would appear.
Here's what I've tried:
shinyUI(
fileInput("file","Upload the file")
if(!is.null(input$file)) {
navbarPage("My Application",
tabPanel("Data", tableOutput("table")),
tabPanel("Summary", tableOutput("sum")),
tabPanel("Regression", verbatimTextOutput("reg")),
tabPanel("Wavelet Coefficients", htmlOutput("tmod1"),
tableOutput("mod1"),
tableOutput("mod2")),
tabPanel("Wavelet Plot", plotOutput("plot")),
tabPanel("About file", tableOutput("filedf"))
)}
)
The error is the following:
ERROR: D:\OneDrive\MODWT App/ui.R:7:1: unexpected 'if'
6:
7: if
^
Is there any solution to this? :/
My current "plan b" is to create two apps, where the first is the upload one, and if the user upload the file then server.R will call the "original" app. Is this even possible?
I apologise if this question seems silly but I'm a noob coder, so I'm not aware of the limitations.
Thanks
To dynamically add or remove UI elements in Shiny you should use the built-in dynamic UI functions such as conditionalPanel.
You'll move the logic from your if statement to the condition argument of conditionalPanel.
There are a few other functions like that which you can read about here and you can also use custom JS.

Write R code in a shiny app?

Is it possible to write R Code within the shiny app while it's running? I've built a shiny app, but would like to give users the option to write their own R code in the shiny app. I want to put the console in shiny along with the viewer and a simplified environment pane. I've never seen anything like this, so before I spend a lot of time doing this I'm wondering if it's even possible. Has anyone seen something like this?
Thanks to Cory I found rfiddle, which is exactly what I'm looking for. However I can't seem to get it to work. I used the iframe that r-fiddles website says to use to embed rfiddle, but I keep getting this error message:
Error in withReactiveDomain(shinysession, { :
No handler registered for for type .clientdata_output_<iframe width="300" height="600" src="http://r-fiddle.org/#/embed/eYsWfghB/1" allowfullscreen="allowfullscreen" frameborder="0"></iframe>_hidden
Code:
library(shiny)
ui = shinyUI(
fluidPage(
htmlOutput(tags$iframe(width=300, height=600,
src='http://r-fiddle.org/#/embed/eYsWfghB/1',
allowfullscreen='allowfullscreen', frameborder='0'))
)
)
server = shinyServer(function(input, output, session) {
})
shiny::shinyApp(ui,server)

Accessing uiOutput Value On App Load

To simplify this example I've only included the necessary code to describe the issue I'm having. Should it be required, I will include a fully reproducible example, but I have a hunch that this issue can be solved through theory alone by someone with more experience using Shiny. Basically, I've programmed a Shiny app in R which looks something like this:
ui.R
plotOutput(outputId = 'heatmap1', height = "800px")
uiOutput('selectStrains')
uiOutput('selectRegions')
server.R
output$selectStrains = renderUI({
checkboxGroupInput(inputId='strains',
choices=sort(colnames(mousedata)),
selected=colnames(mousedata))
})
output$selectRegions = renderUI({
checkboxGroupInput(inputId='regions',
choices=sort(rownames(mousedata)),
selected=rownames(mousedata))
})
# more code
output$heatmap1 = renderPlot({
input$recalculate
mousedatamat = as.matrix(mousedata[isolate(input$strains), isolate(input$regions)])
heatmap.2(mousedatamat)
})
problem:
My problem is that in server.R, when the app is first loaded, input$strains and input$regions are both NULL. Therefore, mousedatamat in server.R will be a 0x0 matrix, and the heatmap will be empty on the front page of the app, which makes for a pretty poor user experience. I don't know how the ui.R and server.R files interact when an app is launched, so I'm finding it difficult to debug. To make the plot show up I either need to click a recalculate button (input$recalculate), or resize the window (but only in the horizontal dimension for some reason).
To add more mystery to the mix, I have the same heatmap figure on page 2 (I'm using a navbarPage layout), which shows up on the app load when I navigate to that tab! It is the very same code, only instead it is assigned to output$heatmap2. When I navigate back to page 1, output$heatmap1 still does not display.
I've tried placing the calls to uiOutput above plotOutput in ui.R, but the main reason I don't know how to solve this I think is because I don't know much about execution flow when an app is started. Any ideas or information on this topic?

Resources