I am using shinycssloaders to show loading animation. There are multiple inputs on the page which are loaded from the server. These inputs are also dependent on each other.
In the below example I have used a reactive object to create such dependency. First the table is displayed and only when the calculation of table is completed (rv$a <- 1) plot can be completed.
library(shiny)
library(shinycssloaders)
ui <- fluidPage(
withSpinner(tableOutput('data')),
withSpinner(plotOutput('plot'))
)
server <- function(input, output) {
rv <- reactiveValues(a = NULL)
output$data <- renderTable({
#Some long calculation here, using Sys.sleep for simplicity
Sys.sleep(2)
rv$a <- 1
head(mtcars)
})
output$plot <- renderPlot({
req(rv$a)
#Some long calculation here, using Sys.sleep for simplicity
Sys.sleep(2)
plot(rnorm(100), rnorm(100))
})
}
shinyApp(ui, server)
This works fine but it shows 2 loaders, one for table and other one for plot. I want to combine these 2 loaders and show only 1 loading animation which covers the entire page combining table and plot. Also loading should end only after all the calculation is done i.e after plot calculation.
I have tried putting table and plot in a div and use spinner on div but it did not work and gave a blank page.
ui <- fluidPage(
withSpinner(div(
tableOutput('data'),
plotOutput('plot')
))
)
Does anybody have a solution to this? Is this possible using some different package?
You can use the tagList() function, which creates a list of the tags allowing the shinycssloaders package to wrap all the inputs within it in one go.
So the ui will look like the following:
ui <- fluidPage(
withSpinner(tagList(tableOutput('data'),
plotOutput('plot')))
)
Just some extra information for the animation. You can all change the style of the animation such as the the type, color, size , etc by adding these as arguments to the withSpinner(). Check the withSpinner() RDocumentation.
Related
I'm trying to build a simple app with two modes. The user can leave 'non-interactive-mode' by flicking a switch. This generates some new UI elements, and produces a result based on the values in the UI element.
For some operations this works fine, but my if statements throw Warnings at the first time I run the code (Warning: Error in if: argument is of length zero). I think I understand why this is happening (the input doesn't exist the first time the code reads the if block), but can it be worked around in a simple way?
MWE below:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
materialSwitch(inputId = "interactive", label = "Interactive?",value=FALSE),
uiOutput("on_interactive_only"),
uiOutput("result_output")
)
server <- function(input, output) {
# Non-interactive Result
output$result_output <- renderUI(if(!input$interactive){
(renderTable(data.frame('dummy'=1:3)))})
# If interactive we need another UI element
output$on_interactive_only <- renderUI(if(input$interactive){
numericInput("value_to_specify",'Which Number?',5)})
# And now we need to react to that value
output$result_output <- renderUI(if(input$interactive){
if(input$value_to_specify > 3){
(renderTable(data.frame('dummy'=input$value_to_specify)))}})
}
shinyApp(ui = ui, server = server)
I'm attempting to design a Shiny App where the user changes several inputs, then presses a "Plot" button to generate new visualizations. Currently, I have the a data object being generated in an eventReactive tied to the "Plot" button, with that data then getting fed into the renderPlot functions.
The framework seems to work, except that the plots will change whenever the inputs are changed. This often leads to errors in the plots, as different inputs load in different data. Pressing the "Plot" button after changing the inputs will cause the correct plots to render, but I'm trying to find a way to ensure that the plots don't change ever until that button is hit.
I believe the solution is a use of the "isolation" function, and I've tried that just about everywhere. However, none of these attempts have been successful. Below is a (simplified) setup of my code.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# several selectInput options
actionButton('plot', label = 'Plot')
)
mainPanel(
plotOutput('outputPlot', height = '3in'),
)
)
)
server <- function(input, output) {
plotData <- eventReactive(input$plot, {
# load various data and organize into a list
return(data.list)
})
outPutPlot <- renderPlot({
plot.data <- plotData()
# manipulate data based on the specific plot, then generate
return(plot)
)
}
You’re right that you’d need to isolate() all reactive dependencies other
than plotData(). Without having a complete runnable example, it’s not
possible to point out where this might have gone wrong. However, it may be
easier to wrap the renderPlot() call in bindEvent(), which will isolate
everything. You just pass the expressions you want to depend on in other
arguments.
So try something like this:
bindEvent(renderPlot({ ... }), plotData())
I am developing a shiny application that needs to show a variable number of elements in the screen. Since, I have no previous idea of how many items there are, I chose to use the uiOutput and on my server.R I use the renderUI to build the dynamic UI. When I have only a few items, it works perfectly, but when there are a lot of items (which is my case) it takes way too long to load the page because it renders all of them at once.
Since only a few of the items are visible on screen at each time, I was thinking about doing some sort of pagination or lazy loading but I could not find how to implement this in shiny.
Here is a simplified version of my renderUI function:
output[['custom.ui']] <- renderUI({
lapply(1:nrow(items), function(i) {
# Some code
box(my_custom_ui())
})
})
I tried using the withSpinner with no success. It shows the spinners, but they all render at the same time.
output[['custom.ui']] <- renderUI({
lapply(1:nrow(items), function(i) {
ui.id <- str_glue('box_{i}')
output[[ui.id]] <- renderUI({
# Some code
box(my_custom_ui())
})
uiOutput(ui.id) %>% withSpinner()
})
})
I want to display a dataframe in a table using grid.table(myDataFrame). I need help figuring out:
what output* and render* functions to use with shiny
what to write exactly in the render* function body
This far I have the following codes
In the UI.R, inside fluidPage and fluidRow:
dataTableOutput("TauxInsertion")
And then in Server.R:
output$TauxInsertion <- renderDataTable({
dataDepartement()
# TauxInsertionTable <- grid.table(dataDepartement())
# TauxInsertionTable
})
dataDepartement is a reactive variable that contains a dataFrame. Returning this data frame inside the renderDataTable gives me a table. But I need to be able to display the row names and add some color and style to the display. The commented part is what I have tried but doesn't display anything.
There are no significant messages in the console. I have also tried options(shiny.trace=TRUE) but to no avail.
I think you have to use functions dedicated to plot. Take a look
library(shiny)
library(grid)
library(gridExtra)
ui <- fluidPage(
plotOutput("plot")
)
server <- function(input, output) {
output$plot <- renderPlot({
grid.table(head(iris,3))
})
}
shinyApp(ui = ui, server = server)
I'm looking at implementing 3D interactive plots in my shiny App, and so far I've been using plotly. However, plotly has one major disadvantage, it's extremely slow when rendering.
I've done checks, and the whole creation of updated outplot$plot <- renderPlotly ({.....}) and plotlyOutput("plot") takes less than 0.5 seconds, despite the large data set involved. This is a know issue for years but still seems to be current.
Hence, I'm looking to use a package called car, also because it has many options, some which I particularly want that are not available in other packages. Info on the car package is here: http://www.sthda.com/english/wiki/amazing-interactive-3d-scatter-plots-r-software-and-data-visualization
The problem is that it renders in a separate popup window rather than inside the shiny app, and I want to have it inside it, or even better, add a button that allow the user to have it as a popup, but only when asked. However, i can't figure out how to jam the bugger into the actual shiny page.
Here is my minimal example with a single text element and the graph code that (in my case) keeps appearing in a separate window rather than in the app.
install.packages(c("rgl", "car", "shiny"))
library("rgl")
library("car")
library(shiny)
cars$time <- cars$dist/cars$speed
ui <- fluidPage(
hr("how do we get the plot inside this app window rather than in a popup?"),
plotOutput("plot", width = 800, height = 600)
)
server <- (function(input, output) {
output$plot <- renderPlot({
scatter3d(x=cars$speed, y=cars$dist, z=cars$time, surface=FALSE, ellipsoid = TRUE)
})
})
shinyApp(ui = ui, server = server)
There is also this package, scatterplot3d but that's not interactive
http://www.sthda.com/english/wiki/scatterplot3d-3d-graphics-r-software-and-data-visualization
And there are some RGL packages but they have the same issue (seperate window) and don't offer the options I am lookign for.
You need to use an rglwidget which takes the last rgl plot and puts in in an htmlwidget. It used to be in a separate package, but it has recently been integrated into `rgl.
Here is the code to do this:
library(rgl)
library(car)
library(shiny)
cars$time <- cars$dist/cars$speed
ui <- fluidPage(
hr("how do we get the plot inside this app window rather than in a popup?"),
rglwidgetOutput("plot", width = 800, height = 600)
)
server <- (function(input, output) {
output$plot <- renderRglwidget({
rgl.open(useNULL=T)
scatter3d(x=cars$speed, y=cars$dist, z=cars$time, surface=FALSE, ellipsoid = TRUE)
rglwidget()
})
})
shinyApp(ui = ui, server = server)
Yielding this: