I have created quite a large app that I now want to extent by introducing tabs. So far I have, as an example:
ui.R
shinyUI(
#OLD CODE
)
server.R
(
#OLD CODE
)
What I would like to do:
ui.R
shinyUI(
tabsetPanel(
"Tabs",
tabPanel("Old Code",value="tb1"),
tabPanel("New Code",value="tb2"),
id = "nlp"
),
if (id=="tb1") {
#OLD CODE
} else if (id=="tb2") {
#New Code
} else {
#Do nothing
}
How do I get the if function to recognise id as a variable?
When I run the script it comes up with the error object 'id' not found. So then I've tried input$id and output$id with no avail.
I have also tried going to the server.R and tried
Server.R
output$id <- renderText("id")
also didn't work when trying to bring that back into the UI
and I have also tried
Server.R
output$id <- reactive({input$id})
this also didn't work when I tried to use it in the UI. Where am I going wrong and how can I use the Id variable in the UI?
Thanks
Based on the Shiny Tabsets example, you should be putting the UI elements into each call to tabPanel, like so:
shinyUI(
tabsetPanel(
tabPanel(
title = "Old Code",
plotOutput('plot1'),
plotOutput('plot2')
),
tabPanel(
title = "New Code",
tableOutput('table')
),
id = "nlp"
)
)
Unless you are trying to do more than necessary, your code does not need to know what tab the client has selected. I may be wrong (please do not think I'm an authority on shiny), I think the elements within the not-selected tabs are not unnecessarily recalculated (unless dependencies exist and require it).
Related
In R Shiny I am trying to dynamically set a download button's label using reactive renderText and textoutput.
It works as expected but the label is always shown in the new line, and hence the button looks wacky next to a regular button
as shown here
Backend logic is -
In server.R, an input field's value is used to generate conditional labels
output$mycustomlabel <- renderText({ if(input$inputtype=="One") return("Download label 1") else return("Download label 2")})
Then in UI.R, that label is used as
downloadButton("download.button.test", textOutput("mycustomlabel"))
Can someone guide why does it display text on new line, and how can I keep it on same line?
If you want to change the button label you probably need to update it with javascript.
An easier approach could be to have two different buttons and use conditional panels to display one of the buttons:
ui <- fluidPage(
radioButtons('inputtype', 'Set label', c('One', 'Two')),
conditionalPanel(
'input.inputtype == "One"',
downloadButton('btn1', 'Download label 1')
),
conditionalPanel(
'input.inputtype == "Two"',
downloadButton('btn2', 'Download label 2')
)
)
Note that with this approach you do need two observers in the server function.
I'm doing this same thing with a dynamic label on a downloadButton. In my case, I want the user to choose between downloading a dataframe as an Excel file or a CSV file.
Here's what I'm doing:
In the ui definition, where you want the button to show up, use
uiOutput( 'myCustomButtonUI' )
In the server definition, include:
output$myCustomButtonUI <- renderUI({
myCustomLabel <- 'Placeholder'
if( input$inputtype == 'One' ) myCustomLabel <- 'Download Label 1'
if( input$inputtype == 'Two' ) myCustomLabel <- 'Download Label 2'
downloadButton( inputId = 'download.button.test',
label = myCustomLabel )
})
output$download.button.text <- downloadHandler(
filename = "<some filename>",
content = .... <go look up downloadHandler() if you're unfamiliar> ..."
)
The idea is that, because you want your button to be dynamic, it needs to be rendered on the server side. The output of the server side is a tiny piece of UI that is placed in your larger UI by the uiOutput function.
There are numerous posts regarding changing titles of other pieces of Shiny apps, e.g.:
Change the title by pressing a shiny button Shiny R
Shiny page title and image
Shiny App: How to dynamically change box title in server.R?
My question is related, but not answered by any of these. I would like to make the <head><title>...</title></head> tag reactive, or at least controllable from within an observeEvent in server.R.
The following does not work, since ui can't find theTitle, but is the kind of approach I'd hope is possible:
library(shiny)
ui <- fluidPage(
title = theTitle(),
textInput("pageTitle", "Enter text:")
)
server <- function(input, output, session) {
theTitle <- reactiveVal()
observeEvent( input$pageTitle, {
if(is.null(input$pageTitle)) {
theTitle("No title yet.")
} else {
theTitle(input$pageTitle)
}
})
}
I've tried making output$theTitle <- renderText({...}) with the if..else logic in that observeEvent, and then setting title = textOutput("theTitle") in ui's fluidPage, but that generates <div ...> as the title text, or <span ...> if we pass inline=True to renderText.
In case this clarifies what I'm looking for, the answer would make something equivalent to the literal (replacing string variables with that string) ui generated by
ui <- fluidPage(
title = "No title yet.",
....
)
before the user has entered any text in the box; if they have entered "Shiny is great!" into input$pageTitle's box, then we would get the literal
ui <- fluidPage(
title = "Shiny is great!",
....
)
One way would be to write some javascript to take care of that. For example
ui <- fluidPage(
title = "No title yet.",
textInput("pageTitle", "Enter text:"),
tags$script(HTML('Shiny.addCustomMessageHandler("changetitle", function(x) {document.title=x});'))
)
server <- function(input, output, session) {
observeEvent( input$pageTitle, {
title <- if(!is.null(input$pageTitle) && nchar(input$pageTitle)>0) {
input$pageTitle
} else {
"No title yet."
}
session$sendCustomMessage("changetitle", title)
})
}
shinyApp(ui, server)
This was created following the How to send messages from the browser to the server and back using Shiny guide
As of June 2021, there is an R package called shinytitle that can update the window title from within Shiny's reactive context: https://cran.r-project.org/package=shinytitle
Is it possible to get the available options for a shiny widget (ie. all of the possible checkboxes from a checkboxInput)?
I have some checkbox input where the options available to check are dependent on other input -- they are updated by observers. Then, suppose I want a button that the user can click and the all of the currently available checkboxes will be checked.
Here is an illustrative example, where I try to update the checkboxes using updateCheckboxGroupInput and the variable input$options. However, this doesn't work because input$options is only the currently selected boxes, so the button does nothing.
Is there already variable that contains all the available checkboxes, or is necessary to maintain another reactive variable with this information?
library(shiny)
shinyApp(
shinyUI(
fluidPage(
uiOutput('ui')
)
),
shinyServer(function(session, input, output) {
output$ui <- renderUI({
inputPanel(
checkboxGroupInput('options', 'Current Options:',
choices=letters, selected='a', inline=TRUE),
column(width = 2,
actionButton('subset', 'Subset the options'),
actionButton('selectAll', 'Select All'))
)
})
## Observers for buttons
observeEvent(input$subset,
updateCheckboxGroupInput(session,
inputId='options',
choices=sample(letters, 10),
inline=TRUE)
)
observeEvent(input$selectAll,
updateCheckboxGroupInput(session,
inputId='options',
## *** What do I put here for selected? ***
selected=input$options,
inline=TRUE)
)
})
)
There isn't a simple Shiny builtin way to do that. You'd have to either use JavaScript to see what the options are, or store the options in a reactive variable
I want to include a small "Help" actionLink (next to a "Render" actionButton) that acts as a popover (see here). Here's my code:
server.R:
shinyUI(pageWithSidebar(
sidebarPanel(
actionButton("renderButton", "Render"),
actionLink("link", "Help") ),
mainPanel()
))
ui.R:
shinyServer(function(input, output, session) {
# ... dealing with renderButton ...
output$link <- renderUI({
addPopover(session=session, id=output$link, title="",
content="Testing.", placement = "bottom",
trigger = "click", options = NULL)
})
})
Right now, the actionLink shows up on the sidebar, but clicking on it has no effect. Any tips? I think it may have to do with the id in addPopover, but I haven't found many examples to provide a framework. I found this, but I want to deal with the popover in server.R, not ui.R. Can it be done this way, or should I just make the popover in ui.R?
From ?Tooltips_and_Popovers:
There must be at least one shinyBS component in the UI of your app in
order for the necessary dependencies to be loaded. Because of this,
addTooltip and addPopover will not work if they are the only shinyBS
components in your app.
To get the pop over to work, you can change your actionButton into a bsButton, and modify server.R to only contain the call to addPopover. The id argument to addPopover also needs to be changed to refer to the id of the ui object you want the pop over to appear on, in your case "link", the id of the actionLink .
Here's the modified example code in a self-contained code chunk:
library(shiny)
library(shinyBS)
runApp(
# Ui
list(ui = pageWithSidebar(
headerPanel("Test App"),
sidebarPanel(
bsButton("renderButton", "Render"),
actionLink("link", "Help") ),
mainPanel("Hello World!")
),
# Server
server = function(input, output, session) {
# ... dealing with renderButton ...
addPopover(session=session, id="link", title="",
content="Testing.", placement = "bottom",
trigger = "click", options = NULL)
})
)
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 ()
}
}
})
})