Is shiny able to use interactive ui? - r

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.

Related

My uiOutput is not showing properly in Shiny App

I pretend to upload an excel file and get to choose between the sheets of that file. It is working perfectly but for some reason the name of the sheets is not taking up the whole space and doing this weird thing:
Wrong display of name of sheets
The part of the script where I establish it is:
...
sidebarLayout(
sidebarPanel(
column(4, fileInput("file2", "Select file (.xls/.xlsx)",
accept = c(".xls",".xlsx")
)),
column(8, uiOutput("name_of_my_sheets", style='padding:6px; font-size:80%; position:relative')),
I tried many things like columning and positioning it differently but canĀ“t get it to work. When I use half of my screen to test de app, it works well.
Right display of name of sheets
I cannot post the whole code for confidential issues unluckily but be happily prone to answer any questions. Thank you in advance!!

Appearing guide page on Shiny app similar to Radiant's

Radiant is an amazing Shiny applet that everyone probably knows : https://vnijs.shinyapps.io/radiant/?SSUID=c730754697
This app benefits from a very nice way of helping its users by using a clickable "?" mark below each sidebar panel, and subsequent appearing document on the page.
May anyone please explain me how to add such help page to my Shiny applet? I could not find the related functions in the codes of this applet.
You should check out R package: shinyBS. Where you can use function bsModal, i is exactly what you are looking for.
Below is an example app posted on the github page, as you can see after pressing the "View Table", pop up appears with the table.
Additionally to get this nice question mark button, you can use function/ object created with bsButton() as a trigger with bsModal() together.
--> Here is a link to stackoverflow question which has an example of shinyBS that might help you.
Regarding the guide to shiny apps I came across wonderful rintrojs package which allows you to build in descriptions of your widgets within shiny apps. You can find the description here https://carlganz.github.io/rintrojs/
rm(list = ls())
library(shiny)
library(shinyjs)
library(rintrojs)
ui <- fluidPage(
useShinyjs(),
introjsUI(),
introBox(actionButton("hide","a"),data.step = 1,data.intro = "By Clicking this button the other one will dissapear"),
introBox(actionButton("b","b"),data.step = 2,data.intro = "Toggle this button"),br(),
bsButton("help", label = "About this Page", block = F,style = "primary",icon =icon("question-circle"))
)
server <- shinyServer(function(input,output,session){
observeEvent(input$help,introjs(session, options = list("showBullets"="false", "showProgress"="true", "showStepNumbers"="false","nextLabel"="Next","prevLabel"="Prev","skipLabel"="Skip")))
observeEvent(input$hide,{
toggle("b")
})
})
runApp(list(ui = ui, server = server))
Radiant uses modals for the help files. In the latest versions of shiny the easiest way to do something like this is with modelDialog. See https://shiny.rstudio.com/reference/shiny/latest/modalDialog.html

R Shiny app progress Indicator for loading data

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/

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?

display different number of tabPanels in a navbarPage in Shiny, without renderUI or uiOutput

I am trying to display from 1 to 5 tabPanels in a navbarPage in Shiny.
I have 5 plots my code generates, but I'd like a user to be able to select how many they want to have access to -- to be displayed one plot in each tabPanel, naturally.
I've got an external configuration file (config.txt) that via source('config.txt'), I have access to a number_of_pages variable.
For example, number_of_tabPages <- 3
How would I set this up in UI.R?
The number of tabPanels can't be hardcoded at all in the UI file, since it depends on a value that is specified by a user, not using a control.
I've searched around and found that most of the approaches to this kind of thing
involve using uiOutput and renderUI functions, such as this similar problem, but I don't want any special control in the UI to do any selecting.
This is where things get tricky, when we are building the UI depending on values that may change. My brain is trying to wrap itself around the best method for doing this type of thing -- I feel like it isn't exactly in line with how Shiny wants to communicate with itself using a UI <--> server environment.
Any advice is greatly appreciated.
My UI.R is easy to create when it isn't dynamic:
fluidRow(
column(12,
"",
navbarPage("",tabPanel("First Tab",
plotOutput("plot1")),
tabPanel("Second Tab",
plotOutput("plot2")),
tabPanel("Third Tab",
plotOutput("plot3")),
tabPanel("Fourth Tab",
plotOutput("plot4")),
tabPanel("Fifth Tab",
plotOutput("plot5"))
)
)
)
)
Thanks!
If you don't need the user to change the number of tabPanel interactively, but just load varying numbers of them when the app is started you can use the do.call function in the navBarPage:
library(dplyr)
library(shiny)
library(ggvis)
#number of tabs needed
number_of_tabPages <- 10
#make a list of all the arguments you want to pass to the navbarPage function
tabs<-list()
#first element will be the title, empty in your example
tabs[[1]]=""
#add all the tabPanels to the list
for (i in 2:(number_of_tabPages+1)){
tabs[[i]]=tabPanel(paste0("Tab",i-1),plotOutput(paste0("plot",i-1)))
}
#do.call will call the navbarPage function with the arguments in the tabs list
shinyUI(fluidRow(
column(12,
"",
do.call(navbarPage,tabs)
)
)
)

Resources