Shiny - disable selection of radio buttons upon selection of a checkbox - r

Is it possible to incorperate code in shiny to disable the selection of certain radio buttons upon the selection of a checkbox? For example, upon selection of ID039, selection of ID038 and ID037 would be disabled? For the given example, I need to ensure that if the checkbox option (NA) is selected, the summary table does not compute the minimum score for ID038 and ID037.
library(shinydashboard)
library(shinythemes)
library(shiny)
library(shinyWidgets)
library(DT)
library(tidyverse)
ui <- fluidPage(
theme = shinytheme("united"),
# Application title
titlePanel("TITLE"),
sidebarLayout(
sidebarPanel(
selectInput("select",
label = helpText("Select a critera"),
choices = list("Criteria_1", "Criteria_2"),
selected = c("NULL")
)
),
mainPanel(tabsetPanel(
tabPanel(
"Criteria", conditionalPanel(h3("Question 1", align = "left"),
condition = "input.select == 'Criteria_1'",
prettyRadioButtons(
inputId = "Id037_crit1",
label = "Predictions:",
choices = c(
"Option 1" = 1,
"Option 2" = 2,
"Option 3" = 3
),
inline = TRUE,
status = "danger",
fill = TRUE
),
),
conditionalPanel(h3("Question 2", align = "left"),
condition = "input.select == 'Criteria_1'",
prettyRadioButtons(
inputId = "Id038_crit1",
label = "Hypotheses:",
choices = c(
"Option 1" = 1,
"Option 2" = 2,
"Option 3" = 3
),
inline = TRUE,
status = "danger",
fill = TRUE
)
),
# SERVER ------------------------------------------------------------------
server <- function(input, output) {
calc_min_val <- function(contains) {
radios_inputid <- str_subset(names(input), contains)
map_dbl(radios_inputid, ~ as.numeric(input[[.x]])) %>%
min()
}
summ <- reactive({
min_values <- c("crit1$", "crit2$") %>%
map(calc_min_val)
tibble(
Lowest_Criteria = c("Specific hypotheses and prediction are provided?", "Predictions regarding the electromagnetic area of
interest are sufficient?"),
value = map(min_values, ~.)
)
})
output$summary <- DT::renderDT({
datatable(summ())
})}
shinyApp(ui, server)

To disable the radio buttons you can use shinyjs package and the following code on the server side.
observeEvent(input$Id039_crit1,{
if (input$Id039_crit1) {
shinyjs::disable("Id037_crit1")
shinyjs::disable("Id038_crit1")
}else {
shinyjs::enable("Id037_crit1")
shinyjs::enable("Id038_crit1")
}
})

Related

Update selectInput on the double click of table in Shiny App

In the Shiny App below, I want to update the value of selectInput box based on the row that is double-clicked by the user in the table of tab 3. For example, if user double clicks at row 3 in the table, then the value of selectInput should change to 3.
Here is my code -
library(shiny)
library(shinydashboard)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
selectizeInput(inputId = "select_by", label = "Select by:",
choices = c(as.character(1:5)))
)
)
body <- dashboardBody(
fluidRow(
tabBox(
side = "right",
selected = "Tab3",
tabPanel("Tab1", "Tab content 1", textOutput("tabset1Selected")),
tabPanel("Tab2", "Tab content 2", textOutput("tabset2Selected")),
tabPanel("Tab3", "Tab content 3", textOutput("tabset3Selected"),
DT::dataTableOutput("table", width = "100%", height = "100%"), color="#bb0a1e", size = 1.5, type = 8)
)
),
)
shinyApp(
ui = dashboardPage(
dashboardHeader(title = "tabBoxes"),
siderbar,
body
),
server = function(session, input, output) {
# The currently selected tab from the first box
output$tabset1Selected <- output$tabset2Selected <- output$tabset3Selected <- renderText({
input$select_by
})
outputOptions(output, "tabset1Selected", suspendWhenHidden = FALSE)
outputOptions(output, "tabset2Selected", suspendWhenHidden = FALSE)
outputOptions(output, "tabset3Selected", suspendWhenHidden = FALSE)
table_dt <- reactive({data.table(values = c(1,2,3,4,5))})
output$table <- DT::renderDataTable({
DT::datatable(table_dt(), filter = 'top', selection = "single", fillContainer = TRUE, width = "90%",
callback = htmlwidgets::JS(
"table.on('dblclick', 'td',",
" function() {",
" var data = table.row(this).data();",
" Shiny.setInputValue('table_tbl_dblclick', {dt_data: data});",
" }",
");"
))
}
)
observeEvent(input$table_tbl_dblclick, {
reactTXT$selected <- input$table_tbl_dblclick$dt_data[[2]] # Since table index starts with 0, adding 1 to map index with data.table
})
reactTXT <- reactiveValues()
observeEvent(eventExpr = input$select_by, handlerExpr = {
req(input$select_by)
reactTXT$selected <- input$select_by
updateSelectizeInput(session, "select_by", selected = reactTXT$selected)
}, ignoreInit = TRUE)
}
)
Can someone point out the reason selectInput is not updated after clicking inside the table?
I don't quite understand what the purpose of your observeEvents are. If it is only to update the selectize input this one works for me:
observeEvent(input$table_tbl_dblclick, {
updateSelectizeInput(session, "select_by", selected = input$table_tbl_dblclick$dt_data[[2]])
})
Updated alternative to preserve reactTXT as the source of the new value:
observeEvent(input$table_tbl_dblclick, {
selected <- input$table_tbl_dblclick$dt_data[[2]] # Since table index starts with 0, adding 1 to map index with data.table
reactTXT$selected <- selected
})
reactTXT <- reactiveValues()
observeEvent(reactTXT$selected, handlerExpr = {
updateSelectizeInput(session, "select_by", selected = reactTXT$selected)
}, ignoreInit = TRUE)
From comments below

Adjust plotly output height to box with dynamic height in shiny dashboard

In the shiny app below I have a box which height depends on the number of shiny widgets it includes and a plot. I would like the box height to somehow saved every time it changes and be passed to the plot in order to have the same height always.
library(shiny)
library(plotly)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
# Copy the line below to make a set of radio buttons
radioButtons("radio1", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2),
selected = 1)
),
dashboardBody(
fluidRow(
column(4,
box(
# Copy the line below to make a set of radio buttons
radioButtons("radio2", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1),
uiOutput("rd3")
)),
plotlyOutput("t2")
)
)
)
server <- function(input, output, session) {
output$rd3<-renderUI({
if(input$radio1==1){
return(NULL)
}
else{
radioButtons("radio3", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1)
}
})
output$t2<-renderPlotly(
fig <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
)
}
shinyApp(ui, server)
The following works based on spsComps::heightMatcher.
However, I needed to trigger a resize event via shinyjs to avoid the plot height getting out of sync after a few clicks, which I think should not be necessary (also makes it quite slow).
library(shiny)
library(plotly)
library(shinydashboard)
library(spsComps)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(# Copy the line below to make a set of radio buttons
radioButtons(
"radio1",
label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2),
selected = 1
)),
dashboardBody(
useShinyjs(),
fluidRow(
column(4,
box(
id = "box_1",
# Copy the line below to make a set of radio buttons
radioButtons(
"radio2",
label = h3("Radio buttons"),
choices = list(
"Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3
),
selected = 1
),
uiOutput("rd3")
)),
box(id = "box_2", plotlyOutput("t2", height = "100%")),
spsComps::heightMatcher("box_2", "box_1")
)
)
)
server <- function(input, output, session) {
observeEvent(input$radio1, {
shinyjs::runjs("$(window).trigger('resize');")
})
output$rd3 <- renderUI({
if (input$radio1 == 1) {
return(NULL)
} else {
radioButtons(
"radio3",
label = h3("Radio buttons"),
choices = list(
"Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3
),
selected = 1
)
}
})
output$t2 <- renderPlotly({fig <-
plot_ly(
data = iris,
x = ~ Sepal.Length,
y = ~ Petal.Length
)})
}
shinyApp(ui, server)

Wide datatables causing scrollx to scroll back when applying filters

I am able to render a datatable in my shiny app. However, whenever there is a wide table, the horizontal scroller gets back to it's initial position when you apply filters on the columns in the back. This issue occurs with numeric columns only.
I was wondering if there is a way I can disable range-based filters (but keep the filters itself) or if there is any other workaround for this problem.
I have searched github issues and stackoveflow prior to posting this question here since I couldn't find anybody having this problem.
Here is a reproducible example along with pictures-
options(scipen = 99999) #converts the sci numbers to their regular format
library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinythemes)
library(writexl)
library(dplyr)
library(DT)
library(dplyr)
mtcars_modified <- mtcars %>% dplyr::mutate(wt_2= wt,
qsec_2 = qsec,
am_2= am,
mpg_2= mpg,
gear_2 = gear,
carb_2 = carb,
disp_2 = disp,
row_names_col= rownames(mtcars))
ui <- fluidPage(
theme = shinythemes::shinytheme("simplex"),
shinyjs::useShinyjs(), # enables javascript/jQuery enhanchments
# Create Right Side Text
navbarPage(
id = "navbar",
title= div(HTML("G<em>T</em>")),
#windowTitle = "GT",
tabPanel("Data Set Info",
materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 1,
"iris"= 2,
"mtcars_modified" = 3),
icon= icon("check"),
selected = 1,
status = "success",
animation="smooth"
),
br(),
br()
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel1", "navigation"
),
tabPanelBody(
"panel2",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel1_data')),
tabPanel("Summary", verbatimTextOutput("panel1_sum")),
tabPanel(
"Plot"
)
)
),
tabPanelBody(
"panel3",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel3_data')),
tabPanel("Summary", verbatimTextOutput("panel3_sum")),
tabPanel(
"Plot"
)
)
)
)
)
)
) ,
#resizes the navbar tabs/button
tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;
font-family: "serif";')))
)
)
server <- function(input, output, session) {
# this event hides the side panel when toggled on/off
observeEvent(input$toggleSidebar, {
shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
if(!isTRUE(input$toggleSidebar)) {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
} else {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
}
})
# here we put all the data
data_sets <- list(df1 = data.frame(),
df2= iris,
df3 = mtcars_modified)
# store current dataset in reactive so we can work with plot panels
data_to_use <- reactiveValues(name = "df", data = data.frame())
observeEvent(input$controller, {
# skip first panel since it is used to display navigation
updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
# enswure value is avilable throught selected tabSet
req(input$controller)
# get current data and df name
data_to_use$data <- data_sets[[as.numeric(input$controller)]]
data_to_use$name <- names(data_sets[as.numeric(input$controller)])
# update table and sum
output[[paste0('panel', input$controller, '_data')]] <-
DT::renderDT(server = FALSE, {
DT::datatable(data_to_use$data,
filter = 'top',
extensions = 'Buttons',
options = list(scrollY = 600,
scrollX = TRUE,
dom = '<"float-left"l><"float-right"f>rt<"row"<"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>',
lengthMenu= list(c(10, 25, 50, -1),
c('10', '25', '50','All')),
buttons = list(
list(extend = "collection", text = "Download",
filename = "data_excel",
exportOptions = list(
modifier = list(page = "all")
),
action = DT::JS("function ( e, dt, node, config ) {
Shiny.setInputValue('Download_DATA', true, {priority: 'event'});}"
)
)
),
scrollCollapse= TRUE,
lengthChange = TRUE,
widthChange= TRUE,
rownames = TRUE))})
output[[paste0('panel', input$controller, '_sum')]] <- renderPrint(summary(data_to_use$data))
})
}
#runs the app
shinyApp(ui= ui, server= server)

Reactivity and Renders doesn't work when switching to another tabPanel

I have a reproducible example below where only the first tabPanel is working, however when I switch to another panel, I don't get any renders (the toggle becomes un-interactable also). I have looked into conditionalPanel however I see them getting done without the use of mainPanel I was wondering if it possible to have tabs where each tab has its own mainPanel , so I can see a different sidebar and an output contained within different tabs. Any help is welcome!
options(scipen = 99999) #converts the sci numbers to their regular format
library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinyalert)
library(esquisse)
library(DT)
library(dplyr)
#library(devtools)
#library(remotes)
#remotes::install_github("dreamRs/esquisse")
library(hrbrthemes)
library(ggthemes)
library(ggplot2)
library(svglite)
ui <- fluidPage(
shinyjs::useShinyjs(), # enables javascript/jQuery enhanchments
# Create Right Side Text
navbarPage(
title= div(HTML("G<em>T</em>")),
#General reports
tabPanel("General Reports",
shinyWidgets::materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
shinyWidgets::prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 1,
"iris"= 2),
icon= icon("check"),
selected = 1,
status = "success",
animation="smooth"
),
br(),
br(),
a(actionButton(inputId = "admin_email", label = "Contact",
icon = icon("envelope", lib = "font-awesome")),
href="mailto:xyz#email.us")
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel1", "Text coming soon."
),
tabPanelBody(
"panel2",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel2_data')),
tabPanel(
"DIY Plot",
esquisse::esquisse_ui(
id = "esquisse2",
header = FALSE,
container = esquisseContainer(
width = "100%", height = "760px", fixed = FALSE
),
controls = c("labs", "parameters", "appearance", "filters", "code")
)
)
)
)
)
)
)
),
# monthly reports
tabPanel("Extra General Reports",
shinyWidgets::materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
shinyWidgets::prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 3,
"mtcars"= 4),
icon= icon("check"),
selected = 3,
status = "success",
animation="smooth"
),
br(),
br(),
a(actionButton(inputId = "admin_email", label = "Contact",
icon = icon("envelope", lib = "font-awesome")),
href="mailto:xyz#email.us")
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel3", "Text coming soon."
),
tabPanelBody(
"panel4",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel4_data')),
tabPanel(
"DIY Plot",
esquisse::esquisse_ui(
id = "esquisse4",
header = FALSE,
container = esquisseContainer(
width = "100%", height = "760px", fixed = FALSE
),
controls = c("labs", "parameters", "appearance", "filters", "code")
)
)
)
)
)
)
)
),
#resizes the navbar tabs/button
tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;
font-family: "serif";')))
)
)
server <- function(input, output, session) {
# this event hides the side panel when toggled on/off
observeEvent(input$toggleSidebar, {
shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
if(!isTRUE(input$toggleSidebar)) {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
} else {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
}
})
# here we put all the data
data_sets <- list(df1 = data.frame(),
df2 = iris,
df3 = data.frame(),
df4 = mtcars)
# store current dataset in reactive so we can work with plot panels
data_to_use <- reactiveValues(name = "df", data = data.frame())
# modules only need to be called it once but individually for esquisse
esquisse::esquisse_server(id = "esquisse2", data_rv = data_to_use)
esquisse::esquisse_server(id = "esquisse4", data_rv = data_to_use)
observeEvent(input$controller, {
# skip first panel since it is used to display navigation
updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
# enswure value is avilable throught selected tabSet
req(input$controller)
# get current data and df name
data_to_use$data <- data_sets[[as.numeric(input$controller)]]
data_to_use$name <- names(data_sets[as.numeric(input$controller)])
# update table and sum. Use server = FALSE to get full table
output[[paste0('panel', input$controller, '_data')]] <- DT::renderDT(server = FALSE, {
DT::datatable(data_to_use$data,
filter = 'top',
extensions = 'Buttons')})
})
}
#runs the app
shinyApp(ui= ui, server= server)
You have two radioButtons, one for each sidebar, but both of them have the inputId = "controller". Same with inputId = "toggleSidebar". InputIds need to be unique in shiny!
I suggest you either use a single sidebar for the entire app, or since both tabs are essentially identical you can also use modules.

R Shiny - Multiple radioButtons with same id / adding headers to groups of radioButtons

WHAT I AM TRYING TO ACHIEVE:
Add different headers on the different groups of radio buttons. I did it by creating two radioButtons widgets with the same id and different labels.
PROBLEM:
When I run the script, Option D is selected and corresponding output show. WELL AND GOOD
When I select any other option, it is selected and corresponding output show. AGAIN WELL AND GOOD
*When I try to select Option D again, it gets selected BUT the corresponding output does not show in the main panel. *
MWE:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
width = 3,
radioButtons("aspect","Structure",
choices = list("Option A" = "size",
"Option B" = "coh",
"Option C" = "bound")
),
hr(),
radioButtons("aspect","Composition",
choices = list("Option D" = "div")
)
),
mainPanel(
width = 9,
fluidRow(
h3(textOutput("aboutText"))
)
)
)
)
server <- function (input, output){
aspectDesc <- reactive({
switch(input$aspect,
size = "Alpha",
coh = " Beta",
bound = "Charlie",
div = "Delta")
})
output$aboutText <- renderText({paste("Text about ", aspectDesc())})
}
shinyApp(ui = ui, server = server)
WHAT I HAVE TRIED
I removed the second RadioButtons widget and moved Option D to the first widget. It works fine. But I can not add the different headers.
I have looked up how to group different radioButtons together but could not find anything substantial
I set up the same id on two different radioButtons( which I did by accident) and at least I could select ONLY one option ( the way I wanted it).
I am totally at a loss what I am missing out. Although it seems to be a trivial issue.
Any help would be highly appreciated!
After some labor, I've found this solution.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
sidebarLayout(
sidebarPanel(
width = 3,
radioButtons("aspect1","Structure",
choices = list("Option A" = "size",
"Option B" = "coh",
"Option C" = "bound"),
selected = character(0)
),
hr(),
radioButtons("aspect2","Composition",
choices = list("Option D" = "div")
)
),
mainPanel(
width = 9,
fluidRow(
h3(textOutput("aboutText"))
)
)
)
)
server <- function (input, output, session){
aspectDesc <- reactiveVal("Delta")
onclick("aspect1", {
updateRadioButtons(session, "aspect2", choices = list("Option D" = "div"),
selected = character(0))
aspectDesc(switch(input$aspect1,
size = "Alpha",
coh = " Beta",
bound = "Charlie"))
})
onclick("aspect2",{
updateRadioButtons(session, "aspect1",
choices = list("Option A" = "size",
"Option B" = "coh",
"Option C" = "bound"),
selected = character(0))
aspectDesc("Delta")
})
output$aboutText <- renderText({paste("Text about ", aspectDesc())})
}
shinyApp(ui = ui, server = server)

Resources