How to RenderTable output to tabPanel in NavBar page + Rshiny app - r

I am building a dashboard page where the user uploads a file and on clicking the actionbutton it should run the server code and show the output and also allow to download the output as file. Below is the code that shows the basic UI.
I would need help with the server function to render the output from the command in server function to the "Table" output in the NavBar page where first 5 rows could be shown in the UI and download the complete output file on clicking the "Download List" button. I am novice with rshiny. Any help would be helpful.
library(shiny)
library(shinydashboard)
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Documentation", tabName = "documentation",selected=FALSE),
menuItem("Dataset", tabName = "dataset", badgeColor = "green"),
menuItem("Result", tabName = "results", badgeColor = "green")
))
body <- dashboardBody(
tabItems(
tabItem(tabName = "documentation",h3("Tool Documentation")),
tabItem(tabName = "dataset",menuItem(icon = NULL, fileInput("PE", "Upload input file:")),
menuSubItem(icon = icon("refresh"),actionButton("Start","Analyze"))),
tabItem(tabName = "results",navbarPage(tabPanel("summary","Summary",icon = icon("list-alt")),
tabPanel("Table",tableOutput("table"),icon = icon("table")),
downloadButton("downList", "Download List")))))
# Put them together into a dashboardPage
ui <- dashboardPage(dashboardHeader(title = "FanDB"),
sidebar,
body)
# Define server logic
server <- function(input, output, session) {
##run this command on input$PE file on the click of actionButton
output$Table <- renderTable({
input$Start
req(input$PE)
a<-read.delim(input$PE,sep="\t",header=T)
b<-a[a[,6]==2,1]
{
return(b)
}
#Show the results from the actionButton in the Table panel in the navbar page and download the results using downloadButton
})
}
shinyApp(ui, server)
Or displaying the "results" menu (navbarPage) which is currently in the sidebarMenu to the dashboardBody on the completion of actionButton would be ideal.

There's a typo: output$Table should be output$table to refer to the table, not the tab holding it. Also, to load a file from fileInput, you need to access input$PE$datapath
The way I'd structure this is to use an eventReactive, which is triggered by the actionButton, to load the data and make it available as a reactive expression which is used by renderTable
server <- function(input, output, session) {
# When button is pressed, load data and make available as reactive expression
table_content <- eventReactive(input$Start, {
req(input$PE$datapath)
a <- read.delim(input$PE$datapath,sep="\t",header=T)
b <- a[a[,6]==2,1]
return(b)
})
# Render data as table
# Since table_content is reactive, the table will update when table_content changes
output$table <- renderTable({
table_content()
})
}
To download the table, you can just set up a downloadHandler function with this same table_content() expression as the content. There are a bunch of other questions on downloadHandler, so I won't go into detail on that.
If you want the input$Start button to change to the results tab when clicked, you need to do 2 things:
First, add an id to your sidebarMenu:
sidebar <- dashboardSidebar(
sidebarMenu(id = 'tabs',
...
Second, set up updateTabItems to change the selected tab to results. Since you're using shinydashboard, you want to use shinydashboard::updateTabItems, not shiny:: updateTabsetPanel as in this question. Since you want to change tabs when the table content is loaded, I'd make the table_content() reactive the trigger by adding this:
observeEvent(table_content(),{
updateTabItems(session, "tabs", 'results')
})
Now, when table_content() is changed, the tab will be switched to results. If something goes wrong in your eventReactive and the file cannot be read or processed properly, then the tab won't switch.

Related

Force input widget creation in Shiny even if widget has not yet been displayed in browser

In Shiny, one can use the following line to force displaying/refreshing an output even if not displayed within the ui:
outputOptions(output, "my_output", suspendWhenHidden = FALSE)
Is there a similar way to "force" input widget creation?
My context: I do have a button that pre-populate a textinput on another tab. Potentially, this textinput may not been generated yet if user didn't go to this specific tab. In such a case, the pre-population legitimely fails.
Good practice would probably be to use a reactiveValues, to feed it with the "pre-populate value" when clicking the button, and then to use this rv within the input widget creation. But I was wondering if a similar option as the above was available in Shiny.
Here’s a simple, working example of the situation I think you are describing.
That is, you don’t need to do anything special.
library(shiny)
ui <- fluidPage(
tabsetPanel(
tabPanel("A", actionButton("populate", "Populate B things")),
tabPanel("B", textInput("b_text", "Add some B text"))
)
)
server <- function(input, output, session) {
observeEvent(input$populate, {
updateTextInput(session, "b_text", value = "Updated from tab A")
})
}
shinyApp(ui, server)
If the input you want to update is generated with uiOutput() then you can
use outputOptions() to force evaluation, like you already mentioned:
library(shiny)
ui <- fluidPage(
tabsetPanel(
tabPanel("A", actionButton("populate", "Populate B things")),
tabPanel("B", uiOutput("b_panel"))
)
)
server <- function(input, output, session) {
observeEvent(input$populate, {
updateTextInput(session, "b_text", value = "Updated from tab A")
})
output$b_panel <- renderUI({
textInput("b_text", "Add some B text")
})
outputOptions(output, "b_panel", suspendWhenHidden = FALSE)
}
shinyApp(ui, server)

Why is my remove UI function in R shiny not working?

I've reviewed similar posts and haven´t found any that address this specific need. Below is very simple MWE of what I'm trying to do: shown in 2 images, and in runnable code. My "Hide" button (or remove UI) doesn't work. Help!! I'm sure it's a simple solution but I'm new to this.
What I'm trying to do: Click on the "Add" button and a file input prompt appears below. Click "Hide" button and the file input prompt goes away. Click "Add" again (after "Hide") and the file input prompt appears again. If you click "Add" now (and repeatedly), that single file input prompt remains. (Most other posts have the object appearing repeatedly, again and again in a growing column, with every additional click of the button - this isn't what I need). Just one click to make it appear (and clicking "Add" over and over just keeps it there in its original single manifestation), and "Hide" makes it go away. Simple as that.
Images:
library(shiny)
ui <- fluidPage(
h2("Testing showing and hiding of a function in UI ..."),
br(),
h3(actionButton("addBtn", "Add")),
h3(actionButton("hideBtn","Hide")),
uiOutput("FileInput"),
) # close fluid page
server <- function(input, output, session) {
output$FileInput <- renderUI({
"txt"
req(input$addBtn)
tagList(fileInput("file1", "Choose file",multiple= FALSE,
accept=c("csv",
"comma-separated-values",
".csv"), # close c
width=250,
buttonLabel = "select one file",
placeholder = "Add file"
), # close file input
)} # close tag list
)} # close render UI
observeEvent(input$hideBtn, {
removeUI(
selector = "div:has(> #txt)")
}) # close observe event
shinyApp(ui, server)
Perhaps you can use shinyjs package to get the desired result. Try this
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
h2("Testing showing and hiding of a function in UI ..."),
br(),
h3(actionButton("addBtn", "Add")),
h3(actionButton("hideBtn","Hide")),
uiOutput("FileInput"),
) # close fluid page
server <- function(input, output, session) {
output$FileInput <- renderUI({
"txt"
req(input$addBtn)
tagList(fileInput("file1", "Choose file",multiple= FALSE,
accept=c("csv",
"comma-separated-values",
".csv"), # close c
width=250,
buttonLabel = "select one file",
placeholder = "Add file"
) # close file input
) # close tag list
}) # close render UI
observeEvent(input$addBtn, {
shinyjs::show("FileInput")
})
observeEvent(input$hideBtn, {
shinyjs::hide("FileInput")
#removeUI(selector = "div:has(> #txt)")
})
}
shinyApp(ui, server)
If you do not want to use shinyjs package, you can use insertUI and removeUI as shown below.
library(shiny)
ui <- fluidPage(
h2("Testing showing and hiding of a function in UI ..."),
br(),
h3(actionButton("addBtn", "Add")),
h3(actionButton("hideBtn","Hide")),
uiOutput("FileInput"),
) # close fluid page
server <- function(input, output, session) {
output$FileInput <- renderUI({
req(input$addBtn)
tagList(tags$div(id = 'placeholder1')
) # close tag list
}) # close render UI
observeEvent(input$addBtn, {
if (input$addBtn==0){return(NULL)
}else {
insertUI(
selector = '#placeholder1' ,
## wrap element in a div with id for ease of removal
ui = tags$div(id="fi",
div(style="display: inline-block; width: 185px ;" ,
fileInput("file1", "Choose file",multiple= FALSE,
accept=c("csv",
"comma-separated-values",
".csv"), # close c
width=250,
buttonLabel = "select one file",
placeholder = "Add file"
) # close file input
))
)
}
})
observeEvent(input$hideBtn, {
if (input$hideBtn==0){return(NULL)
}else {
removeUI(selector = "div:has(> #fi)")
}
})
}
shinyApp(ui, server)

Login to single tabPanel in Shiny

I have been trying to make a login for a single tabPanel in Shiny. I have used the shinyAlert method, (as described here: How to access Shiny tab ids for use with shinyalerts?) which works, but unfortunately, it shows parts of the tabPanel's content before the user is logged in.
Is there a way to change this? I am trying to figure out how to make the "backdrop" of the shinyAlert just a white page until the user is successfully logged in. I read that this might be possible with CSS, but it is unclear to me how.
Or is there another method to do this, that I haven't considered? I am pretty new to Shiny.
Edit: the relevant parts of the code.
ui <- fluidPage(navbarPage("Eksempel", theme = shinytheme("cerulean"),
tabPanel("Home", icon = icon("home"),
fluidRow(
box(
Title = "Welcome to the example layout",
width = 10,
solidHeader = TRUE,
"Welcome text")
)),
tabPanel("Prototype", icon = ("chart-line"),
fluidPage(tagList(
textInput("user", "User:"),
passwordInput("password", "Password:"),
uiOutput("secrets"))),
# other tabPanels
server <- function(input, output, session){
output$secrets <- renderUI({
req(input$user == "admin", input$password == "shiny")
fluidPage( #contents of tabPanel, containing different plots ect.
)
})
The contents of the fluidPage I am trying to hide works fine when I don't try to hide it.
You can use req in combination with a renderUI and uiOutput to hide stuff until someone authenticates.
library(shiny)
ui <- fluidPage(
tagList(
textInput("user", "User:"),
passwordInput("password", "Password:"),
uiOutput("secrets")
)
)
server <- function(input, output) {
output$secrets <- renderUI({
req(input$user == "admin", input$password == "stackoverflow")
wellPanel("Hello admin! These are the secrets!")
})
}
shinyApp(ui = ui, server = server)
If you want a more enterprise-ready approach, you can try ShinyProxy or Shiny-Server Pro.

Disabling buttons in Shiny

I am writing some Shiny code where the user will enter some inputs to the app and then click a an action button. The action button triggers a bunch of simulations to run that take a long time so I want once the action button is clicked for it to be disabled so that the user can't keep clicking it until the simulations are run. I came across the shinyjs::enable and shinyjs::disable functions but have been having a hard time utilizing them. Here is my server code:
output$button1= renderUI({
if(input$Button1 > 0) {
shinyjs::disable("Button1")
tableOutput("table")
shinyjs::enable("Button1")}
})
However, when I use this code, and click the action button nothing happens. I.e., teh action button doesn't grey out nor does the table get generated. However, when I take away the shinyjs::enable() command, i.e.,
output$button1= renderUI({
if(input$Button1 > 0) {
shinyjs::disable("Button1")
tableOutput("table")
}
})
The table gets generated first, and then the button goes grey, however I would have expected the button to go grey and then the table to generate itself.
What am I doing wrong here?
Here is my updated code based on Geovany's suggestion yet it still doesn't work for me
Button1Ready <- reactiveValues(ok = FALSE)
observeEvent(input$Button1, {
shinyjs::disable("Button1")
RunButton1Ready$ok <- FALSE
RunButton1Ready$ok <- TRUE
})
output$SumUI1= renderUI({
if(Button1Ready$ok){
tableOutput("table")
shinyjs::enable("Button1")
}
})
where for clarification I have also:
output$table <- renderTable({
#My code....
)}
I think that you are using shinyjs::disable and shinyjs::enable in the same reactive function. You will only see the last effect. I will recommend you to split in different reactive functions the disable/enable and use an extra reactive variable to control the reactivation of the button.
I don't know how exactly your code is, but in the code below the main idea is illustrated.
library(shiny)
library(shinyjs)
ui <- fluidPage(
shinyjs::useShinyjs(),
sidebarLayout(
sidebarPanel(
actionButton("Button1", "Run"),
shinyjs::hidden(p(id = "text1", "Processing..."))
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output) {
plotReady <- reactiveValues(ok = FALSE)
observeEvent(input$Button1, {
shinyjs::disable("Button1")
shinyjs::show("text1")
plotReady$ok <- FALSE
# do some cool and complex stuff
Sys.sleep(2)
plotReady$ok <- TRUE
})
output$plot <-renderPlot({
if (plotReady$ok) {
shinyjs::enable("Button1")
shinyjs::hide("text1")
hist(rnorm(100, 4, 1),breaks = 50)
}
})
}
shinyApp(ui, server)

Using conditionalPanel (or other methods) to create a temporary banner that disappears if user navigates away

I want to create a welcome message for when a user first opens the shiny webpage. Currently I have it such that it is constantly on the first tabPanel. Is there a way to make it disappear when the user navigates away and then back to that panel?
fluidRow(
column(width=12,
tabsetPanel(type = "tabs", id = "tabs1",
tabPanel("Express Usage", wellPanel("Welcome! Please select the libraries you are interested in viewing from below and use the tabs to navigate between graphs. It is best to limit your selection to no more than 5 libraries at a time"), plotOutput("express_Plot", height=400)),
tabPanel("Juvenile Usage", plotOutput("juvenile_Plot", height=400)),
tabPanel("test", h3(textOutput("text_test")))))
),
You can set the value attribute for all your tabPanels accordingly.
In this way, you can tell, in server.R, which tab is currently selected by reading input$tabs1, where tabs1 is the id you set for the tabsetPanel.
Replace the wellPanel with a uiOutput element, and update the UI elements according
to:
The current panel.
The times the panel has been visited.
ui.R
library(shiny)
shinyUI(fluidPage(
fluidRow(
column(width=12,
tabsetPanel(type = "tabs", id = "tabs1",
tabPanel("Express Usage",
uiOutput("welcome"), # replace the wellPanel
plotOutput("express_Plot", height=400), value="ex_usage"),
tabPanel("Juvenile Usage", plotOutput("juvenile_Plot", height=400), value="juv_usage"),
tabPanel("test", h3(textOutput("text_test")))), value="test")
)
)
)
server.R
library(shiny)
shinyServer(function(input, output, session){
visits <- reactiveValues(times = 0)
output$welcome <- renderUI({
if (input$tabs1 == "ex_usage") {
isolate(visits$times <- visits$times + 1)
if (isolate(visits$times) == 1) {
return (wellPanel("Welcome! Please select the libraries you are interested in viewing from below and use the tabs to navigate between graphs. It is best to limit your selection to no more than 5 libraries at a time"))
}
else {
return ()
}
}
})
})

Resources