Get the name in selectInput widget in R shiny - html

I'm using the selectInput function of shiny package with option groups like this Output of the selectInput function
In the ui.r file i've something like that:
ListOfItemsWithNames = list(condition = c("KO","WT"),treatment = c("non","oui"))
selectInput("Select1_contrast",label="Compare",ListOfItemsWithNames)
In the server.R file, when i call input$Select1_contrast I only get the selected value ("oui" for instance).
Is there a way to get both the value an the name of the variable (ie, "oui" and "treatment") ?

Here is another possibility. It uses key-value pairs. Those pairs are allowed according to the documentation of selectInput
choices List of values to select from. If elements of the list are named, then that name rather than the value is displayed to the user. This can also be a named list whose elements are (either named or unnamed) lists or vectors. If this is the case, the outermost names will be used as the "optgroup" label for the elements in the respective sublist. This allows you to group and label similar choices. See the example section for a small demo of this feature.
addKeys = function(nested_list){
keyed_nl = list()
for (a in names(nested_list))
for (b in (nested_list[[a]]))
keyed_nl[[a]][[b]] = paste0(a, "-", b)
keyed_nl
}
ListOfItemsWithNames = list(condition = c("KO", "WT"),
treatment = c("non", "oui"))
keyedList = addKeys(ListOfItemsWithNames)
library(shiny)
shinyApp(
fluidPage(
selectInput("choiceKey", "choose", keyedList),
textOutput('text')
),
function(input, output, session)
output$text = renderText(input$choiceKey)
)
As you can see, input$choiceKey will give you the category and the choice seperated with -. Using strsplit, you can get both parts seperately

This should work. In this version, you have a sencond dropdown menu and therefore a second input.
library(shiny)
ListOfItemsWithNames = list(condition = c("KO","WT"),treatment = c("non","oui"))
ui = inputPanel(
selectInput("category", "choose a category", names(ListOfItemsWithNames )),
selectInput("choice", "select a choice", ListOfItemsWithNames[[1]])
)
server = function(input, output, session){
observe({
updateSelectInput(session, "choice",
choices = ListOfItemsWithNames[[input$category]])
})
}
shinyApp(ui, server)

Related

Shiny tooltips / spsComps

My question is in regards to
Shiny: Add Popover to Column Name in Datatable, the package spsComps for using tooltips, when I remove the tooltip which is defined in the mainPanel, the tooltip on the datatable column also does not work anymore.
library(shiny)
library(spsComps)
library(DT)
library(dplyr)
# define the question button in a button since we need to uses multiple times
infoBtn <- function(id) {
actionButton(id,
label = "",
icon = icon("question"),
style = "info",
size = "extra-small",
class='btn action-button btn-info btn-xs shiny-bound-input'
)
}
ui <- fluidPage(
titlePanel('Making a Popover Work in DataTable'),
mainPanel(
fluidRow(dataTableOutput('myTable'))
)
)
server <- function(input, output, session) {
output$myTable <- DT::renderDataTable({
# construct the title and convert to text
hp_text <- tags$span(
"hp",
infoBtn('notWorking') %>%
bsPopover(title = "This one does not work",
content = "I'd like to give information about hp: it means horsepower. I want a popover, because my real example has lot's of text.",
placement = "top",
trigger = "hover")
) %>%
as.character()
# use !! and := to inject variable as text
datatable(mtcars %>% rename(!!hp_text:=hp),
rownames=TRUE,
selection='none',
escape=FALSE)
})
}
shinyApp(ui = ui, server = server)
However, when once a tooltip is displayed once in the UI, then it also works for the datatable (from #lz100)
library(shiny)
library(spsComps)
library(DT)
library(dplyr)
# define the question button in a button since we need to uses multiple times
infoBtn <- function(id) {
actionButton(id,
label = "",
icon = icon("question"),
style = "info",
size = "extra-small",
class='btn action-button btn-info btn-xs shiny-bound-input'
)
}
ui <- fluidPage(
titlePanel('Making a Popover Work in DataTable'),
mainPanel(
fluidRow(
#popover button
infoBtn('workingPop') %>%
bsPopover(title = "This Popover Works",
content = "It works very well",
placement = "right",
trigger = "hover"
)
),
fluidRow(dataTableOutput('myTable'))
)
)
server <- function(input, output, session) {
output$myTable <- DT::renderDataTable({
# construct the title and convert to text
hp_text <- tags$span(
"hp",
infoBtn('notWorking') %>%
bsPopover(title = "This one does not work",
content = "I'd like to give information about hp: it means horsepower. I want a popover, because my real example has lot's of text.",
placement = "top",
trigger = "hover")
) %>%
as.character()
# use !! and := to inject variable as text
datatable(mtcars %>% rename(!!hp_text:=hp),
rownames=TRUE,
selection='none',
escape=FALSE)
})
}
shinyApp(ui = ui, server = server)
Is this a bug? Or is there something I am missing?
Change this on your UI:
mainPanel(
fluidRow(dataTableOutput('myTable')),
spsDepend("pop-tip")
)
So here, we add spsDepend("pop-tip"). This means loading the dependent Javascript library when app starts. In therory, -v-, the dependency would be automatically added, users do not need to know this. However, in this case, you are using the renderDataTable function. This package does not know how to handle htmltools::htmlDependency, which is the mechanism how usually developers add JS dependencies for shiny apps.
In your case, if you only use it once in the renderDataTable, we need to manually add the dependency in UI by spsDepend. But like your second case, if it has been used at least once in the UI, the dependency is there, you don't need to worry.
You can see the question mark for the button is not working either. The same problem. renderDataTable does not know how to add the dependency for actionButton. So in general, I wouldn't call it a bug, but a feature DT package doesn't support yet.
For the question mark, even if is not a problem caused by spsComps, but we do have a solution from spsComps, adding the icon library:
mainPanel(
fluidRow(dataTableOutput('myTable')),
spsDepend("pop-tip"),
spsDepend("font-awesome")
)

Build a workflow in R shiny

Hope all are safe there :slight_smile:
In the below simple application (rather my question should hold for all applications as well), is there a way to build workflow, so that we can get to know about the application well. For example
In this app,
In terms of UI.R
1) There is 1 actionbutton (So can we list the number of action buttons in the app, along with there ID's)
2) There is 1 dataTableoutput (So can we list the number of dataTableoutput in the app, along with there ID's)
So in general, can we list the number of inputs and there type(actionbutton, radiobutton etc)
Interms of Server.R
3) Can we show that dataTableOutput("Test") is dependent on actionButton("plot"). I mean can we extract a list of outputs that is dependent on observerEvents?
So basically, just by running the small chunk of code, the user should know that this output(test) is dependent on observeEvent(plot).?
library(shiny)
library(dplyr)
library(shinycssloaders)
library(DT)
ui <- fluidPage(
actionButton("plot","plot"),
dataTableOutput("Test")
)
server <- function(input, output, session) {
observeEvent(input$plot, {
output$Test <- DT::renderDT(DT::datatable(head(iris),
rownames = FALSE, options = list(dom = 't',
ordering=FALSE)))
})
}
shinyApp(ui = ui, server = server)

Extend width of column with renderDataTable in Shiny

I having trouble understanding the behavior of renderDataTable function using Shiny.
I am trying to extend the width of one specific column.
When I am not using Shiny, and just trying to visualize the output of the table, I write the below and I get the expected output in the plot (Amazon Title column is extended):
Category <- c("Tools & Home Improvement", "Tools & Home Improvement")
AmazonTitle <- c("0.15,Klein Tools NCVT-2 Non Contact Voltage Tester- Dual Range Pen Voltage Detector for Standard and Low Voltage with 3 m Drop Protection", " ABCDFGEGEEFE")
ASIN_url <- c("<a href='https://www.amazon.com/dp/B004FXJOQO'>https://www.amazon.com/dp/B004FXJOQO</a>", "<a href='https://www.amazon.com/dp/B004FXJOQO'>https://www.amazon.com/dp/B0043XJOQO</a>")
ASIN <- c("B004FXJOQO", "B0043XJOQO")
All_ASIN_Information <- data.frame(Category, AmazonTitle, ASIN_url, ASIN)
DT::datatable(All_ASIN_Information, escape=FALSE,
options = list(
pageLength = 20, autoWidth = TRUE,
columnDefs = list(list( targets = 2, width = '600px'))
)
)
But when I use this exact block inside a DT::renderDataTable function for Shiny, the result is different and the column width is not extended....
See behavior for Shiny with below code:
library(shiny)
library(DT)
ui <- fluidPage(
mainPanel(
DT::dataTableOutput("Table_ASIN")))
server <- function(input, output){
output$Table_ASIN <- DT::renderDataTable(
DT::datatable(All_ASIN_Information, escape=FALSE,
options = list(
pageLength = 20, autoWidth = TRUE,
columnDefs = list(list( targets = 2, width = '600px'))
)))
}
shinyApp(ui, server)
I don't know if this behavior is caused by the hyperlinks created in column 'ASIN_url' but I would really need them anyway.
Any help much appreciated on this !
One option would be to shorten the link like this:
ASIN_url <- c("<a href='https://www.amazon.com/dp/B004FXJOQO'>Link</a>", "<a href='https://www.amazon.com/dp/B004FXJOQO'>Link</a>")
Another would be to add a scroll bar by including scrollX = TRUE in the option list

Removing multiple elements with removeUI / wrapping multiple elements with tags$div() assigning an id for each variable

I was suggested using insertUI here and found that it is a great feature. The following code allows to generate control widgets for a single or multiple elements using insertUI, but struck on incorporating removeUI related part. Tried jQuery options to remove inserted UI elements but did not work out. I found the following from Shiny dynamic UI, i.e., Note that, if you are inserting multiple elements in one call, you must wrap them in either a tagList() or a tags$div() (the latter option has the advantage that you can give it an id to make it easier to reference or remove it later on). Also, comments here gave some clues, i.e., tags$div(id="sepal.width.div", sliderInput("sepal.width.slider", ...)), but my lack of HTML/CSS knowledge stops me going forward. I'm looking at (a) wrapping multiple widget element(s) with tags$div() assigning a unique id for each variable, which will be used in removeUI; (b) calling multiple elements via removeUI.
varnames <- names(iris[,1:4]) # names
varinit <- apply(iris[,1:4],2,median) # initival value used in slider
varmin <- apply(iris[,1:4],2,min) # min.
varmax <- apply(iris[,1:4],2,max) # max.
ListofSelVars <<- vector(mode="character")
# control widgets for all elements
allControls <- lapply(setNames(varnames, varnames), function(x) {
sliderInput(x, x, varmin[x], varmax[x], c(varmin[x], varinit[x]),
round = -2)
})
ui <- navbarPage(
tabPanel("Plot",
sidebarLayout(
sidebarPanel(
checkboxGroupInput("ConditioningVariables", "Conditioning variables (choose one or more):",
varnames,inline = TRUE),
# add an action button
actionButton("add", "Update UI elements")
),
mainPanel()
)
)
)
server <- function(input, output, session) {
observeEvent(input$add, {
insertUI(
selector ='#add',
where = "afterEnd",
ui = allControls[setdiff(input$ConditioningVariables,ListofSelVars)]
)
## removeUI related goes, here
## removeUI(selector=paste0())
## setdiff(ListofSelVars,input$ConditioningVariables) gives elements to be removed
## Global variable, keep track of elements that are selected
ListofSelVars <<- input$ConditioningVariables
})
}
shinyApp(ui, server)
Here is the working code. The main issue is with the names here, i.e. Sepal.Width. I wrapped each slider with a div with id like div.Sepal.Width so that it is easier to remove. removeUI requires a jQuery selector, so it appears that something like #div.Sepal.Width would work, except that it does not, because . is itself a jQuery selector that means class, so we need to double escape the .. Of course you can also remove the . when you first create the divs, thus avoiding the trouble...
varnames <- names(iris[,1:4]) # names
varinit <- apply(iris[,1:4],2,median) # initival value used in slider
varmin <- apply(iris[,1:4],2,min) # min.
varmax <- apply(iris[,1:4],2,max) # max.
ListofSelVars <<- vector(mode="character")
# control widgets for all elements
allControls <- lapply(setNames(varnames, varnames), function(x) {
tags$div(id=paste0("div.",x), sliderInput(x, x, varmin[x], varmax[x], c(varmin[x], varinit[x]),
round = -2))
})
ui <- fluidPage(
titlePanel("Dynamic sliders"),
sidebarLayout(
sidebarPanel(
checkboxGroupInput("ConditioningVariables", "Conditioning variables (choose one or more):",
varnames,inline = TRUE),
# add an action button
actionButton("add", "Update UI elements")
),
mainPanel(
uiOutput("plot_out")
)
)
)
server <- function(input, output, session) {
observeEvent(input$add, {
insertUI(
selector ='#add',
where = "afterEnd",
ui = allControls[setdiff(input$ConditioningVariables,ListofSelVars)]
)
ListofRemoval <- setdiff(ListofSelVars,input$ConditioningVariables)
for (item in ListofRemoval) {
item = gsub(".", "\\.", item, fixed=TRUE)
item = paste0("#div\\.", item)
removeUI(item)
}
ListofSelVars <<- input$ConditioningVariables
})
}
shinyApp(ui, server)

Two inputs for the same value in Shiny

I'm new to shiny and i don't know anything about html, I'm having an issue to find a way to get a slider and a numeric input at the same time for the same input value in my app. Also I would like that when i for instance set the numeric value to 25 the slider automatically sets itself to 25 once the button is pushed.
Thank you for your help.
I tried that for my ui but it doesn't work ...
library(shiny)
shinyUI(fluidPage(
numericInput(inputId = "num1",
label = "Jour limite",
value = 10, min = 1, max=500),
sliderInput(inputId = "num",
label= "Jour limite",
value= 10 ,min=1 ,max=500
),
actionButton(inputId="clicks",
label= "Actualiser"),
plotOutput("courbj")
))
Don't know if it's relevant but here is my server code :
print(getwd())
CourbeTot <- read.table("data/CourbeTot.csv",header=TRUE,sep=";")
shinyServer(
function(input,output) {
valeur <- eventReactive(input$clicks, {
(input$num)
})
output$courbj <- renderPlot({
plot(CourbeTot$DFSurvieTot.time,CourbeTot$DFSurvieTot.ProptionAuDelaDe,xlim=c(1,2*valeur()))
})
})
You can try to set a reactive Input (slider and numeric) using renderUI on server site.
here the UI.R
library(shiny)
shinyUI(fluidPage(
uiOutput("INPUT"),
uiOutput("SLIDER"),
plotOutput("courbj")
))
Here the Server.R.
library(shiny)
print(getwd())
CourbeTot <- 1:10
shinyServer(
function(input,output) {
valeur <- reactive({
S <- input$num
N <- input$num1
max(c(10,S,N))
})
output$courbj <- renderPlot({
plot(c(CourbeTot,valeur()))
})
# rective slider and numeric input
output$SLIDER = renderUI({
sliderInput(inputId = "num",
label= "Jour limite",
value= valeur() ,min=1 ,max=500)
})
output$INPUT = renderUI({
numericInput(inputId = "num1",
label = "Jour limite",
value = valeur(), min = 1, max=500)
})
})
As you provided no reproducible example I created one. Slider and numeric Input will change according to the other, respectively. This is done 1. per the max function which will alwas output the highest value set by one of the two inputs. And. 2 that the inputs are moved to the server side using the renderUI. You see that I removed the click button because of problems with the initial NULL behavior. Upon this error you can't (or I found no way) select one value and update the other after the click. This seems to be a shiny bug asked already here. The code is not perfect, but I think it is a good basis to play around and you can adjust it for your purpose.