Shinydashboard multiple conditions in conditionalPanel with same inputs - r

I'm building an app with shinyDashboard. I want to display several selectInput in sidebarMenu regarding the selected tabItem AND tabPanel. The same selectInput are used in different tabItem.
It looks simple but I struggle with the conditional syntax in conditionalPanel using multiples arguments with both AND (&&), OR (||) and IN (%in%) operators. I tried to add bracket but it is not doing the job.
I wrote this code, with is reproductible and working but not doing what I want as its always display the selectInputs.
library(shinydashboard)
library(dplyr)
mtcars$gear <- as.character(mtcars$gear)
all_gears <- sort(unique(mtcars$gear))
mtcars$cyl <- as.character(mtcars$cyl)
all_cyl <- sort(unique(mtcars$cyl))
ui <- dashboardPage(
dashboardHeader(title = "test"),
dashboardSidebar(
sidebarMenu(id="menu1",
menuItem(
"Dashboard",
tabName = "dashboard",
icon = icon("dashboard")
),
menuItem(
"Indicators",
tabName = "indicators",
icon = icon("info-circle")
)
),
conditionalPanel(
condition = "input.menu1 == 'dashboard' && input.tabselected %in% c('1','2')",
selectInput(
inputId = "cylinders",
label = "Select number of cylinders",
choices = all_cyl,
selected = '4',
multiple = TRUE,
selectize = FALSE
)
),
conditionalPanel(
condition = "(input.menu1 == 'dashboard' && input.tabselected == 2) || input.menu1 == 'indicators'",
selectInput(
inputId = "gearsnumber",
label = "Select number of gears",
choices = all_gears,
selected = '3',
multiple = TRUE,
selectize = FALSE
)
)
),
dashboardBody(
tabItems(
tabItem(tabName = "dashboard",
tabsetPanel(
tabPanel("Graph", value=1, plotOutput("plot")),
tabPanel("Table", value=2, dataTableOutput("table")),
tabPanel("Empty", value=3)
)
),
tabItem(tabName = "indicators",
infoBoxOutput("totalweight")
)
)
)
)
server <- function(input, output, session) {
selectedDatacyl <- reactive({
req(input$cylinders)
df <- as.data.frame(mtcars)
df$gear <- as.character(df$gear)
df$cyl <- as.character(df$cyl)
df <- mtcars
df %>% dplyr::filter(cyl %in% input$cylinders)
})
selectedDatagears <- reactive({
req(input$gearsnumber)
df <- selectedDatacyl()
df %>% dplyr::filter(gear %in% input$gearsnumber)
})
output$plot <- renderPlot({
ggplot( data = selectedDatacyl(), aes(x = rownames(selectedDatacyl()), y = mpg)) + geom_point()
})
output$table <- DT::renderDataTable({
DT::datatable( data = selectedDatagears(),
options = list(pageLength = 14),
rownames = FALSE)
})
output$totalweight <- renderInfoBox({
infoBox(
"Total weight",
paste0(sum(selectedDatagears()$wt), "lbs"),
icon = icon("chart-area"),
color = "green"
)
})
}
shinyApp(ui = ui, server = server)
What should I do to make thoses conditions operational? Thanks to all contribs.

The condition in conditionalPanel is a JavaScript expression, not a R expression.
So you have to replace
input.menu1 == 'dashboard' && input.tabselected %in% c('1','2')
with
input.menu1 == 'dashboard' && (input.tabselected == '1' || input.tabselected == '2')
or
input.menu1 == 'dashboard' && ['1','2'].indexOf(input.tabselected) > -1

Related

R Shiny - Automatically adding filters with the names of the columns and select values of each column in the data

I would like to add/remove filters based on column names, i.e., if I select 2 column names, those column names should show numericRangeInput or seletizeInput or any other based on the class. Can it be done with conditionalPanel
Here is what I am trying
library(shiny)
nodes = read.csv("data/nodes.csv", header=T, as.is=T)
ui <- shinyUI(
fluidPage(
actionButton("addNode", "Add Node filter", icon=icon("plus", class=NULL, lib="font-awesome")),
uiOutput("filterPage1")
)
)
server <- function(input, output){
i <- 0
observeEvent(input$addNode, {
i <<- i + 1
output[[paste("filterPage",i,sep="")]] = renderUI({
t4 = class(nodes[,names(nodes)[i]])
print(t4)
list(
fluidPage(
fluidRow(
conditionalPanel(
condition = "t4=='character'",
column(6, selectInput(paste("filteringFactor",i,sep=""), paste0(names(nodes4)[i],':'),
choices=unique(nodes[,names(nodes)[i]]), selected=NULL,
width="100%")),
column(6, actionButton(paste("removeFactor",i,sep=""), "",
icon=icon("times", class = NULL, lib = "font-awesome"),
onclick = paste0("Shiny.onInputChange('remove', ", i, ")"))),
condition = "t4=='numeric'",
column(6, sliderInput(paste("filteringFactor",i,sep=""), paste0(names(nodes4)[i],':'),
choices=unique(nodes4[,names(nodes4)[i]]), selected=NULL,
width="100%")),
column(6, actionButton(paste("removeFactor",i,sep=""), "",
icon=icon("times", class = NULL, lib = "font-awesome"),
onclick = paste0("Shiny.onInputChange('remove', ", i, ")")))
)
)
),
uiOutput(paste("filterPage",i + 1,sep=""))
)
})
})
observeEvent(input$remove, {
i <- input$remove
output[[paste("filterPage",i,sep="")]] <- renderUI({uiOutput(paste("filterPage",i + 1,sep=""))})
})
}
shinyApp(ui, server)
I made an example based on the link I shared to elaborate on my comments (yours isn't reproducible):
library(shiny)
library(shinyWidgets)
library(tools)
library(datasets)
d <- data(package = "datasets")
dataset_is <- sapply(gsub(" .*$", "", d$results[,"Item"]), function(x){is(get(x))[1]})
DFs <- names(dataset_is[dataset_is == "data.frame"])
filterParams <- function(vars){
setNames(lapply(vars, function(x){
list(inputId = x, title = paste0(tools::toTitleCase(x), ":"), placeholder = "...")
}), vars)
}
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
selectInput("dataset", label = "Select dataset", choices = DFs),
tags$h3("Filter data with selectize group"),
uiOutput("panelProxy"),
DT::dataTableOutput(outputId = "table")
)
)
)
server <- function(input, output, session) {
selected_dataset <- reactive({
DF <- get(input$dataset)
setNames(DF, gsub("\\.", "_", names(DF))) # avoid dots in inputId's (JS special character)
})
vars_r <- reactive({
input$vars
})
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = selected_dataset,
vars = vars_r
)
output$table <- DT::renderDataTable({
req(res_mod())
res_mod()
})
output$panelProxy <- renderUI({
available_vars <- names(selected_dataset())
panel(
checkboxGroupInput(
inputId = "vars",
label = "Variables to use:",
choices = available_vars,
selected = available_vars,
inline = TRUE
),
selectizeGroupUI(
id = "my-filters",
params = filterParams(available_vars)
),
status = "primary"
)
})
}
shinyApp(ui, server)

Reset in Shiny applications

I am trying to clear what ever is written in the text area but looks like it not working. Based on the below applications, when the user clicks on "click" button, the contents (if written) should get cleared. But it is not. Can anyone help me here please........................................
data(mtcars)
library(shiny)
library(shinydashboard)
library(dplyr)
library(DT)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "Dynamic sidebar"),
dashboardSidebar(sidebarMenu(id = "menu", sidebarMenuOutput("menu"))),
dashboardBody(tabItems
(
tabItem
(tabName = "plots", h2("Dashboard plots"),
fluidRow(column(width = 12, class = "well",
h4("Boxplot"),
plotOutput("bxp")))
),
tabItem(tabName = "dashboard", h2("Dashboard tab content"),
dataTableOutput(outputId = "subdt"),textAreaInput("sd","label1"),textAreaInput("sd1","label2") ,
actionButton("idff","click"))
)
)
)
server <- function(input, output, session) {
output$menu <- renderMenu({
sidebarMenu(
# menuItem("Plots Menu", tabName = "plots", icon = icon("line-chart")),
menuItem("Table Menu", icon = icon("info"),
menuSubItem(
"Dashboard", tabName = "dashboard", icon = icon("calendar")
),
selectInput(
inputId = "mcm", label = "Some label", multiple = TRUE,
choices = unique(mtcars$cyl), selected = unique(mtcars$cyl)
)
)
)
})
observe({
print(input$menu)
})
datsub <- reactive({
mtcars %>%
filter_at(vars("cyl"), all_vars(. %in% input$mcm))
})
output$subdt <- renderDataTable({
datatable(datsub(),selection = if(input$menu == "dashboard"){'single'} else {'none'})
# print(datatable.selection())
})
# datatable(datsub(),selection = if(input$menu == "dashboard"){'single'} else {'none'})
output$bxp <- renderPlot({
hist(rnorm(100))
})
observeEvent(input$idff,{
print("cjec")
shinyjs::reset('sd')
shinyjs::reset('sd1')
})
}
shinyApp(ui, server)
I'd suggest to update the textAreaInput as suggested in the comments. Update the event handler as follows:
observeEvent(input$idff, {
updateTextAreaInput(session = session, inputId = 'sd', value = "")
updateTextAreaInput(session = session, inputId = 'sd1', value = "")
})

Reactively updating sidebar in modular Shiny app

I have a modularized Golem app using bs4Dash. I want to update the active sidebar tab from an actionBttn that is dynamically generated from renderUI. While updatebs4ControlbarMenu works as expected as shown here, it does not work in the modularized version of the application. What am I doing wrong? I suspect it is related to input[[btnID]] management across modules but I struggle to find the solution.
Working example without modules as shown here:
library(shiny)
library(shinyWidgets)
library(bs4Dash)
library(tidyverse)
shinyApp(
ui = bs4DashPage(
sidebar_collapsed = FALSE,
controlbar_collapsed = TRUE,
enable_preloader = FALSE,
navbar = bs4DashNavbar(skin = "dark"),
sidebar = bs4DashSidebar(
inputId = "sidebarState",
bs4SidebarMenu(
id = "sidebr",
bs4SidebarMenuItem(
"Tab 1",
tabName = "tab1"
),
bs4SidebarMenuItem(
"Tab 2",
tabName = "tab2"
)
)
),
bs4DashBody(
bs4TabItems(
bs4TabItem(
tabName = "tab1",
h1("Welcome!"),
fluidRow(
pickerInput(
inputId = "car",
label = "Car",
choices = row.names(mtcars),
selected = head(row.names(mtcars), 3),
multiple = TRUE,
options = list(
`actions-box` = TRUE)
),
pickerInput(
inputId = "gear",
label = "Gear",
choices = unique(mtcars$gear),
selected = unique(mtcars$gear),
multiple = TRUE,
options = list(
`actions-box` = TRUE)
)
),
fluidRow(
column(6,
uiOutput("uiboxes")
)
)
),
bs4TabItem(
tabName = "tab2",
h4("Yuhuuu! You've been directed automatically in Tab 2!")
)
)
)
),
server = function(input, output, session) {
submtcars <- reactive({
req(input$car, input$gear)
mtcars %>%
mutate(
carnames = rownames(mtcars)) %>%
filter(
carnames %in% input$car &
gear %in% input$gear
)
})
observeEvent( submtcars(), {
n_ex <- nrow(submtcars())
output$uiboxes <- renderUI({
lapply(1:n_ex, FUN = function(j) {
print(paste("j is ", j))
bs4Box(
title = submtcars()$carnames[j],
width = 12,
str_c("Number of gears:", submtcars()$gear[j]),
btnID <- paste0("btnID", j),
print(btnID),
fluidRow(
column(
2,
actionBttn(
inputId = btnID,
icon("search-plus")
)
)
)
)
})
})
lapply(1:n_ex, function(j) {
btnID <- paste0("btnID", j)
observeEvent(input[[btnID]] , {
updatebs4ControlbarMenu(
session,
inputId = "sidebr",
selected = "tab2"
)
})
})
})
}
)
Modularized attempt not working:
library(shiny)
library(shinyWidgets)
library(bs4Dash)
library(tidyverse)
mod_exlib_ui <- function(id){
ns <- NS(id)
tagList(
fluidRow(
pickerInput(
inputId = ns("car"),
label = "Car",
choices = row.names(mtcars),
selected = head(row.names(mtcars), 3),
multiple = TRUE,
options = list(
`actions-box` = TRUE)
),
pickerInput(
inputId = ns("gear"),
label = "Gear",
choices = unique(mtcars$gear),
selected = unique(mtcars$gear),
multiple = TRUE,
options = list(
`actions-box` = TRUE)
)
),
fluidRow(
column(6,
uiOutput(ns("uiboxes"))
)
)
)
}
mod_exlib_server <- function(id){
moduleServer( id, function(input, output, session){
ns <- session$ns
submtcars <- reactive({
# req(input$car, input$gear)
mtcars %>%
dplyr::mutate(
carnames = rownames(mtcars)) %>%
dplyr::filter(
carnames %in% input$car &
gear %in% input$gear
)
})
observeEvent( submtcars(), {
n_ex <- nrow(submtcars())
output$uiboxes <- renderUI({
lapply(1:n_ex, FUN = function(j) {
print(paste("j is ", j))
bs4Box(
title = submtcars()$carnames[j],
width = 12,
paste("Number of gears: ", submtcars()$gear[j]),
btnID <- paste0("btnID", j),
print(btnID),
fluidRow(
column(
2,
actionBttn(
inputId = ns(btnID),
icon("search-plus")
)
)
)
)
})
})
lapply(1:n_ex, function(j) {
btnID <- paste0("btnID", j)
observeEvent(input[[btnID]] , {
print(btnID)
updatebs4ControlbarMenu(
session,
inputId = "sidebr",
selected = "exdet2"
)
})
})
})
})
}
app_ui <- tagList(
bs4DashPage(
navbar = bs4DashNavbar(),
sidebar = bs4DashSidebar(
expand_on_hover = TRUE,
inputId = "sidebarState",
bs4SidebarMenu(
id = "sidebr",
bs4SidebarMenuItem(
"Tab 1",
tabName = "tab1"
),
bs4SidebarMenuItem(
"Tab 2",
tabName = "tab2"
)
)
),
bs4DashBody(
bs4TabItems(
bs4TabItem(
tabName = "tab1",
h1("Welcome!"),
mod_exlib_ui("exlib_ui_1")
),
bs4TabItem(
tabName = "tab2",
h4("Yuhuuu! You've been directed automatically in Tab 2!")
)
)
)
)
)
app_server <- function( input, output, session ) {
# Your application server logic
mod_exlib_server("exlib_ui_1")
}
shinyApp(
ui = app_ui,
server = app_server)
After exploring the example of function updatebs4TabSetPanel() that is in the same family, it seems that the selected value needs to be a number.
Hence, you can use this code with CRAN version 0.5.0:
updatebs4ControlbarMenu(
session,
inputId = "sidebr",
selected = "2" #"exdet2"
)

Select columns from expression in shiny app

I am trying to build a shiny dashboard app, where I process the input data and produce summary statistics based on the user supplied grouping variables. The last step, where I am stuck is to
implement a working function , which enables the user to select to display only a subset of the columns after the calculation of the summary statistics.
My attempt is in the lines after output$select_col in global.R . Right now each time I try to use the selector shiny crashes with the error "incorrect number of dimensions".
global.R
# Shiny
library(shiny)
library(shinydashboard)
library(shinyjs)
# Data tools
library(dplyr)
library(tidyr)
library(tibble)
library(data.table)
server.R
server <- function(input, output) {
raw_tables<-reactive({
mtcars
})
output$cyl <- renderUI({
selectInput(inputId = "cyl",
label = "Which number of cyl to consider",
choices = c(4,6,8),
selected = NULL,
multiple=TRUE)
})
filtered_tables<-
reactive({
if(is.null(input$cyl)){
data_filtered <- raw_tables()
}
else{
data_filtered <- raw_tables() %>% filter(cyl %in% input$cyl)
}
})
new_statistics <- reactive({
if(is.null(filtered_tables())){
return(NULL)
}
if(length(input$grouping_variables) == 0){
op <- filtered_tables() %>%
ungroup()
} else {
op <- filtered_tables() %>%
group_by_(.dots = input$grouping_variables)
}
op %>% #
summarise(nr_cars = n(),
mean_mpg = mean(mpg,na.rm=T),
sd_mpg = sd(mpg,na.rm=T))
})
nice_table <-reactive({
if(is.null(new_statistics())){
return(NULL)
}
DT::datatable(new_statistics(),
colnames = c(
"nbr cars"="nr_cars" ,
"mean mpg"="mean_mpg",
"sd mpg"="sd_mpg"
), selection = list(target = 'column') , extensions = c('ColReorder'), options = list(colReorder = TRUE)
) %>%
DT::formatRound(columns=c(
"nbr cars" ,
"mean mpg",
"sd mpg"),
digits=2)
})
output$select_col <- renderUI({
if(is.null(nice_table())){
return(NULL)
}
selectInput("col", "Select columns:", choices = colnames(nice_table()), selected=NULL, multiple=TRUE)
})
output$statistics = DT::renderDataTable({
if(length(input$col)>0)
{
return(DT::datatable(nice_table()[, colnames(nice_table()) %in% input$col]))
}
else
{
return(NULL)
}
})
}
ui.R
dbHeader <- dashboardHeader(title = "test",
titleWidth = 250)
sidebar <- dashboardSidebar(
width = sidebarWidth,
br(),
sidebarMenu(
menuItem(text = "Data View",
tabName = "dat_view",
icon = icon("cloud-download")
)
)
)
body <- dashboardBody(
# Add shinyJS mini-sidebar
shinyjs::useShinyjs(),
tabItems(
tabItem(tabName = "dat_view",
fluidPage(
sidebarLayout(
sidebarPanel(width=2,
selectInput(inputId = 'grouping_variables',
label = 'Which grouping var?',
choices = c("cyl","gear","carb"),
selected = NULL,
multiple=TRUE,
selectize=TRUE),
uiOutput("cyl"),
uiOutput("select_col")
)
,
mainPanel(
tabsetPanel(id="dat_view_tabs",
tabPanel(
'statistics',
DT::dataTableOutput(outputId='statistics')
)
)
)
)))))
ui <- dashboardPage(skin = "blue",
header = dbHeader,
sidebar = sidebar,
body = body)

Modify my rChart based on a reactive input?

I am having trouble with some code that I've written.
Here is a sample of the dataset: https://docs.google.com/spreadsheets/d/1C_P5xxzYr7HOkaZFfFiDhanqDSuSIrd2UkiC-6_G2q0/edit?usp=sharing
Objective:
I have a dataset that contains a column of Purchase_Month, candy and freq of the number of times that type of candy was purchased in that given month.
I have an rPlot which I was to change based on the chosen Candy bar in the SelectInput. And output a line chart based on the number of times that candy was purchased that month.
I have my current code below, but it tells me that candyCount is not found.
## ui.R ##
library(shinydashboard)
library(rCharts)
dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(
width = 150,
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("bar-chart"))
)
),
dashboardBody(
sidebarPanel(
htmlOutput("candy")
),
mainPanel(
showOutput("plot2", "polycharts")
))
)
##server.R##
library(rCharts)
library(ggplot2)
library(ggvis)
server <- function(input, output, session) {
output$candy <- renderUI({
available2 <- dataset[(dataset$candy == input$candy), "candy"]
selectInput(
inputId = "candy",
label = "Choose a candy: ",
choices = sort(as.character(unique(available2))),
selected = unique(available2[1])
)
})
observeEvent(input$candy, {
candyChoice<- toString(input$customer_issue)
print(candyChoice)
candyCount<- dataset[dataset$candy == candyChoice, ]
})
})
output$plot2 <- renderChart2({
p2 <- rPlot(freq~purchase_month, data = candyCount, type = 'line')
p2$guides(y = list(min = 0, title = ""))
p2$guides(y = list(title = sprintf("%s Claims",input$candy)))
p2$addParams(height = 300, dom = 'chart2')
return(p2)
})
}
Updated Data: Why wouldn't this work?
candyCount<- reactive({
dataset[dataset$candy == input$candy, ]
})
output$plot2 <- renderChart2({
p2 <- rPlot(freq~purchase, data = candyCount(), type = 'line')
p2$guides(y = list(min = 0, title = ""))
p2$guides(y = list(title = ""))
p2$addParams(height = 300, dom = 'chart2')
return(p2)
})
output$candy <- renderUI({
available2 <- dataset[(dataset$candy == input$candy), "candy"]
selectInput(
inputId = "candy",
label = "Choose a candy: ",
choices = sort(as.character(unique(available2))),
selected = unique(available2[1])
)
})
In the above you are trying to subset by an input, which is inside your output. The selectInput needs to be inside UI.R.
A working basic example you may find useful.
library(shiny)
df <- read.csv("/path/to/my.csv")
ui <- shinyUI(pageWithSidebar(
headerPanel('Candy Data'),
sidebarPanel(
selectInput('candy', 'Candy', unique(as.character(df[,2])), selected = "Twix")
),
mainPanel(
plotOutput('plot1')
)
))
server <- shinyServer(function(input, output, session) {
selectedData <- reactive({
df[which(df[,2] == input$candy),3]
})
output$plot1 <- renderPlot({
barplot(selectedData())
})
})
shinyApp(ui, server)
In the above example the ui renders a selectInput which has the ID candy. The value, i.e the candy selected is now assigned to input$candy scope. In server we have a reactive function watching for any input change. When the user selects a new candy this function, df[which(df[,2] == input$candy),3] is saying "subset my data frame, df, by the new input$candy". This is now assigned to the selectedData(). Finally we render then boxplot.
EDIT
server.R
require(rCharts)
options(RCHART_WIDTH = 500)
df <- read.csv("path/to/my.csv")
shinyServer(function(input, output, session) {
selectedData <- reactive({
df[which(df[,2] == input$candy),]
})
output$plot1 <- renderChart({
p <- rPlot(freq~purchase_month, data = selectedData(), type = "line")
p$addParams(dom = 'plot1')
return(p)
})
})
ui.R
require(rCharts)
options(RCHART_LIB = 'polycharts')
shinyUI(pageWithSidebar(
headerPanel('Candy Data'),
sidebarPanel(
selectInput('candy', 'Candy', unique(as.character(df[,2])), selected = "Twix")
),
mainPanel(
showOutput('plot1', 'polycharts')
)
))
save files in directory and then runApp.
At available2 you're filtering the data about a selected candy with dataset$candy == input$candy. But you use the same available2 to determine which are the choices at selectInput. I'm guessing you wanted: available2 <- dataset[, "candy"].

Resources