Using reactive conditions inside an eventReactive - r

I am building a Shiny app which generates a dataframe through a specific function. I want to use an eventReactive() to attribute the result of this function depending on a reactive input.
I tried to follow this answer : Working with a reactive() dataframe inside eventReactive()? but when I want to use an observeEvent, it always generate an error Warning: Error in $.shinyoutput: Reading objects from shinyoutput object not allowed.
My first try was as follows with an example :
DATA and LIBRAIRIES
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(dplyr)
df <- data.frame(c1 = c(rep("A", 3), rep("B", 4), "on"),
c2 = 1:8,
c3 = c(2002,2003,2002,2004,2002,2003,2005, 2005))
my_function <- function(arg1, arg2)
{
df = data.frame(
v1 = mean(df %>% filter(c1 == arg1) %>% select(c2) %>% pull()),
v2 = arg2
)
return(df)
}
UI
ui <- fluidPage(
selectInput(inputId = "input1", label = NULL,
choices = c("A", "B"),
selected = "A"),
selectInput(inputId = "input2", label = NULL,
choices = c("on", "off"),
selected = "on"),
uiOutput("ui_year"),
uiOutput("fct_extract"),
actionButton(inputId = "extraction", label = "Go", icon = icon("play")),
uiOutput("col_visu")
)
SERVER
server <- function(input, output) {
output$ui_year <- renderUI({
checkboxGroupInput(inputId = "year1", label = NULL, choices = df %>% filter(c1 == "A") %>% select(c3) %>% pull())
})
output$fct_extract <- renderUI({
shinyWidgets::radioGroupButtons(
inputId = "fct_extract",
label = NULL,
selected = "B1",
choices = c("B0", "B1"),
status = "warning")
})
fct_extr <- reactive(output$fct_extract)
df2 <- eventReactive(input$extraction, {
if (fct_extr() == "B0")
{
my_function(arg1 = input$input1,
arg2 = input$input1)
} else if (fct_extr() == "B1")
{
my_function(arg1 = input$input2,
arg2 = input$input1)
}
})
columns <- reactive(colnames(df2()))
output$col_visu <- renderUI({
shinyWidgets::multiInput(
inputId = "col_visu", width = "400px",
label = h2("Selection :"),
choices = columns())
})
}
When I put the actionButton, it generates the message : Reading objects from shinyoutput object not allowed. and nothing else happened
So I tried in the SERVER :
fct_extr <- reactive(output$fct_extract)
df2 <- observeEvent(input$extraction, {
if (fct_extr() == "B0")
{
my_function(arg1 = input$input1,
arg2 = input$input1)
} else if (fct_extr() == "B1")
{
my_function(arg1 = input$input2,
arg2 = input$input1)
}
})
}
Here I got the message : argument "x" is missing, with no default instead of the result of col_visu and when I put the actionButton, the app closed
In addition, when I don't try to add the choice with fct_extra, it works :
df2 <- eventReactive(input$extraction, {
my_function(arg1 = input$input1,
arg2 = input$input1)
})
columns <- reactive(colnames(df2()))
output$col_visu <- renderUI({
shinyWidgets::multiInput(
inputId = "col_visu", width = "400px",
label = h2("Selection :"),
choices = columns())
})
Thank you to the one of you who will explain how to include a reactive inside an eventReactive :)

You define the following dynamic radioGroupButton:
output$fct_extract <- renderUI({
shinyWidgets::radioGroupButtons(
inputId = "fct_extract",
label = NULL,
selected = "B1",
choices = c("B0", "B1"),
status = "warning")
})
This defines a UI element whose value is accessible in input with the key set to the element's inputId. So, in this case, the value is under input$fct_extract
Note that this is independent of the name of your UI object in the output, which just happens to also be fct_extract. This naming is confusing and probably caused your error: trying to access the value of the widget in output$fct_extract when it is actually in input$fct_extract.
To fix your code, replace the illegal line (fct_extr <- reactive(output$fct_extract)) with the correct:
fct_extr <- reactive(input$fct_extract)
In fact, this reactive is redundant since input$fct_extract is already a reactive value. So just ditch your reactive entirely and use input$fct_extract (without brackets) where you would have used fct_extr()

I made a few edits to your code to get it working. Here are the actual code changes though for your question:
mean(df... instead of mean(a...
my_function <- function(arg1, arg2)
{
df = data.frame(
v1 = mean(df %>% filter(c1 == arg1) %>% select(c2) %>% pull()),
v2 = arg2
)
return(df)
}
and then removing the line fct_extr <- reactive(output$fct_extract). I think you meant to use reactiveVal but it's unnecessary here. I just replaced:
if (fct_extr() == "B0")... else if (fct_extr() == "B1") with
if (input$fct_extr == "B0")... else if (input$fct_extr == "B1")
Full code below.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(dplyr)
df <- data.frame(c1 = c(rep("A", 3), rep("B", 4), "on"),
c2 = 1:8,
c3 = c(2002,2003,2002,2004,2002,2003,2005, 2005))
my_function <- function(arg1, arg2)
{
df = data.frame(
v1 = mean(df %>% filter(c1 == arg1) %>% select(c2) %>% pull()),
v2 = arg2
)
return(df)
}
ui <- fluidPage(
selectInput(inputId = "input1", label = NULL,
choices = c("A", "B"),
selected = "A"),
selectInput(inputId = "input2", label = NULL,
choices = c("on", "off"),
selected = "on"),
uiOutput("ui_year"),
uiOutput("fct_extract"),
actionButton(inputId = "extraction", label = "Go", icon = icon("play")),
uiOutput("col_visu")
)
server <- function(input, output) {
output$ui_year <- renderUI({
checkboxGroupInput(inputId = "year1", label = NULL, choices = df %>% filter(c1 == "A") %>% select(c3) %>% pull())
})
output$fct_extract <- renderUI({
shinyWidgets::radioGroupButtons(
inputId = "fct_extract",
label = NULL,
selected = "B1",
choices = c("B0", "B1"),
status = "warning")
})
# fct_extr <- reactiveVal(input$fct_extract)
df2 <- eventReactive(input$extraction, {
if (input$fct_extract == "B0")
{
my_function(arg1 = input$input1,
arg2 = input$input1)
} else if (input$fct_extract == "B1")
{
my_function(arg1 = input$input2,
arg2 = input$input1)
}
})
columns <- reactive(colnames(df2()))
output$col_visu <- renderUI({
shinyWidgets::multiInput(
inputId = "col_visu", width = "400px",
label = h2("Selection :"),
choices = columns())
})
}
shinyApp(ui, server)

Related

Display line plot when condition is met in data entry

I am building a shiny budgeting shiny application that prompts the user to enter data such as what type of expense was spent, the amount, and a description. I would like to display a line plot in the second pannel of the application labeled "Monthly Budget" ONLY when the user has entered at least one data entry where the category is "Savings". I have tried experimenting with things such as hiding/displaying the plot whenever the condition is met, but it seems that I always get a NaN error message with this approach. Thus, I am experimenting with conditionalPanel() in hopes of accomplishing this task. I've noticed similar posts to this one, however this is the first case that I have found where conditionalPanel() deals with data that the user inputs as opposed to a given dataset. In the code below I get the following error message: "Error in: Invalid input: date_trans works with objects of class Date only".
Here is the code:
# Libraries
library(shiny)
library(ggplot2)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
############ THIS IS WHERE THE ERROR HAPPENS #############
tabPanel("Monthly Budget",
conditionalPanel("output.any(ReactiveDf() == 'Savings') == TRUE ",
plotOutput("SavingsPlot")
)
########### THIS IS WHERE THE ERROR HAPPENS ##############
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
output$SavingsPlot <- renderPlot({
savings <- ReactiveDf()[ReactiveDf()$Category == "Savings",]
savings <- savings[, -c(1,3,5)]
savings$Date <- as.Date(savings$Date)
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = as.Date(savings$Date))
weekly <- apply.weekly(savings,sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = Date)) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
})
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)
We can use a condition like nrow(filter(ReactiveDf(), Category == 'Savings')) > 0 as if ReactiveDf is a normal df. Also, when converting the xts object to a df the Date column was coerced to character.
app:
# Libraries
library(shiny)
library(tidyverse)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
library(lubridate)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
tabPanel("Monthly Budget",
plotOutput("SavingsPlot")
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
if (nrow(filter(ReactiveDf(), Category == 'Savings')) > 0) {
output$SavingsPlot <- renderPlot({
savings <- filter(ReactiveDf(), Category == 'Savings')
savings$Date <- as.Date(savings$Date, format = "%Y-%m-%d")
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = savings$Date)
weekly <- apply.weekly(savings, sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = ymd(Date))) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
}) }
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)

How to ensure that in pickerInput choices at least one item is selected in each group

I have not been able to find an answer to this issue on SO. The code below
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(shinyjs)
library(magrittr)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(title = "PickerInput Query", titleWidth=450),
dashboardSidebar( width = 300,
useShinyjs(),
sidebarMenu(id = "tabs")
),
dashboardBody(
tags$head(
tags$style(HTML("
.col-sm-10 {
width: 45% !important;
}
.col-sm-2 {
width: 55% !important;
}
"))),
uiOutput('groupvar'),
uiOutput('shapetype')
))
server <- function(input, output, session) {
sx <- c("M","F")
#arm <- c(rep("DrugA",2),rep("DrugB",2),rep("Placebo_NotDrug",1))
arm <- c(rep("Drug A",2),rep("Drug B",2),rep("Placebo NotDrug",1))
d <- data.frame(
subjectID = c(1:100),
sex = c(rep("F",9),rep(sx,43),rep("M",5)),
treatment = c(rep(arm,20)),
race = c(rep("W",76),rep("B",15),rep("O",5),rep("H",1),rep("A",3)),
baseline_result = c(rnorm(50, 4, 3), rnorm(50, 3, 3)),
postbase_result = c(rnorm(50, 5, 3), rnorm(50, 4, 2)),
stringsAsFactors = FALSE)
dat <- reactive(d)
myfun <- function(df, var1) {
df %>% mutate(newvar = !!sym(var1)) # create newvar
}
output$groupvar<-renderUI({
bc<-colnames(dat()[sapply(dat(),class)=="character"])
tagList(
pickerInput(inputId = 'group.var',
label = 'Select group by variable. Then select order, color and shape',
choices = c("NONE",bc[1:length(bc)]), selected="NONE",
width = "350px",
options = list(`style` = "btn-warning"))
)
})
### pick order, color and shape
observeEvent(input$group.var, {
output$shapetype<-renderUI({
req(input$group.var,dat())
if(is.null(input$group.var)){
return(NULL)
}else if(sum(input$group.var=="NONE")==1){
return(NULL)
}else{
mydf <- subset(dat(), dat()[input$group.var] != "")
mydf2 <- myfun(mydf,input$group.var) ## create a new variable named newvar
mygrp <- as.character(unique(mydf2$newvar))
ngrp <- length(mygrp)
myorder <- (1:ngrp)
mycolor <- c("red", "blue", "green", "brown", "orange", "maroon")
myshape <- c("circle", "triangle", "plus", "cross", "diamond", "downtriangle")
lapply(1:ngrp, function(i){
pickerInput(paste0("line.vars.",i),
label = paste0(mygrp[i], ":" ),
choices = list(DisplayOrder = myorder,
ShapeColor = mycolor,
ShapeType = myshape,
Group = mygrp), ## how do we hide or disable this 4th item
selected = list( i, mycolor[i], myshape[i], mygrp[i] ),
multiple = T,
inline = TRUE,
width = "275px" , #mywidth,
options = list('max-options-group' = 1,
`style` = "btn-primary"))
})
}
})
}, ignoreInit = TRUE)
}
shinyApp(ui, server)
gives the following output:
It gives the option for the user to pick the order, color and shape for each of the available group value in their data. However, when users accidentally click on their selected choice again, it deselects that choice. In the image above, I have deselected order, color and shape for Drug A. It should not allow a user to deselect any group. My expectation is that if color has a choice of red and blue, they should be able to pick either color but not none.
#Stephane Laurent's answer works for the first element. I am still able to deselect order, color and shape from the second element onwards in the treatment example above. Please see the output below:
output2
Try this. The JavaScript code prevents to deselect an option if it is the unique selected option.
js <- "
$(document).ready(function(){
$('#somevalue').on('show.bs.select', function(){
$('a[role=option]').on('click', function(e){
var selections = $('#somevalue').val();
if(selections.length === 1 && $(this).hasClass('selected')){
e.stopImmediatePropagation();
};
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});"
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
pickerInput(
inputId = "somevalue",
label = "A label",
choices = c("a", "b"),
multiple = TRUE
),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderPrint(input$somevalue)
}
shinyApp(ui, server)
EDIT
I see that you are using pickerInput with groups of options. Here is the JS code for this situation:
js <- "
$(document).ready(function(){
$('#groups').on('show.bs.select', function(){
$('a[role=option]').on('click', function(e){
var classes = $(this).parent().attr('class').split(/\\s+/);
if(classes.length === 2){
var group = classes[0];
var selections = $('.' + group + '.selected');
if(selections.length === 1){
e.stopImmediatePropagation();
}
}
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});"
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
pickerInput(
inputId = "groups",
label = "Select one from each group below:",
choices = list(
Group1 = c("1", "2", "3", "4"),
Group2 = c("A", "B", "C", "D")
),
multiple = TRUE
),
verbatimTextOutput(outputId = "res_grp")
)
server <- function(input, output) {
output$res_grp <- renderPrint(input$groups)
}
shinyApp(ui, server)
EDIT
For your case:
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(dplyr)
js <- "
$(document).ready(function(){
$('#shapetype').on('show.bs.select', 'select[id^=linevars]', function(){
$('a[role=option]').on('click', function(e){
var classes = $(this).parent().attr('class').split(/\\s+/);
if(classes.length === 2){
var group = classes[0];
var selections = $('.' + group + '.selected');
if(selections.length === 1){
e.stopImmediatePropagation();
}
}
});
}).on('hide.bs.select', function(){
$('a[role=option]').off('click');
});
});"
ui <- dashboardPage(
dashboardHeader(title = "PickerInput Query", titleWidth=450),
dashboardSidebar( width = 300,
sidebarMenu(id = "tabs")
),
dashboardBody(
tags$head(
tags$style(HTML("
.col-sm-10 {
width: 45% !important;
}
.col-sm-2 {
width: 55% !important;
}
")),
tags$script(HTML(js))
),
uiOutput('groupvar'),
uiOutput('shapetype')
))
server <- function(input, output, session) {
sx <- c("M","F")
#arm <- c(rep("DrugA",2),rep("DrugB",2),rep("Placebo_NotDrug",1))
arm <- c(rep("Drug A",2),rep("Drug B",2),rep("Placebo NotDrug",1))
d <- data.frame(
subjectID = c(1:100),
sex = c(rep("F",9),rep(sx,43),rep("M",5)),
treatment = c(rep(arm,20)),
race = c(rep("W",76),rep("B",15),rep("O",5),rep("H",1),rep("A",3)),
baseline_result = c(rnorm(50, 4, 3), rnorm(50, 3, 3)),
postbase_result = c(rnorm(50, 5, 3), rnorm(50, 4, 2)),
stringsAsFactors = FALSE)
dat <- reactive(d)
myfun <- function(df, var1) {
df %>% mutate(newvar = !!sym(var1)) # create newvar
}
output$groupvar<-renderUI({
bc<-colnames(dat()[sapply(dat(),class)=="character"])
tagList(
pickerInput(inputId = 'group.var',
label = 'Select group by variable. Then select order, color and shape',
choices = c("NONE",bc[1:length(bc)]), selected="NONE",
width = "350px",
options = list(`style` = "btn-warning"))
)
})
### pick order, color and shape
observeEvent(input$group.var, {
output$shapetype<-renderUI({
req(input$group.var,dat())
if(is.null(input$group.var)){
return(NULL)
}else if(sum(input$group.var=="NONE")==1){
return(NULL)
}else{
mydf <- subset(dat(), dat()[input$group.var] != "")
mydf2 <- myfun(mydf,input$group.var) ## create a new variable named newvar
mygrp <- as.character(unique(mydf2$newvar))
ngrp <- length(mygrp)
myorder <- (1:ngrp)
mycolor <- c("red", "blue", "green", "brown", "orange", "maroon")
myshape <- c("circle", "triangle", "plus", "cross", "diamond", "downtriangle")
lapply(1:ngrp, function(i){
pickerInput(paste0("linevars",i),
label = paste0(mygrp[i], ":" ),
choices = list(DisplayOrder = myorder,
ShapeColor = mycolor,
ShapeType = myshape,
Group = mygrp), ## how do we hide or disable this 4th item
selected = list( i, mycolor[i], myshape[i], mygrp[i] ),
multiple = T,
inline = TRUE,
width = "275px" , #mywidth,
options = list('max-options-group' = 1,
`style` = "btn-primary"))
})
}
})
}, ignoreInit = TRUE)
}
shinyApp(ui, server)
You are basically looking for a minOptions equivalent to maxOptions. Unfortunately, the underlying plugin of pickerInput (bootstrap-select) does not have this feature and it is likely that such a feature will not be implmented (see here and here for similar feature requests on GitHub).
One option would be build your own workaround via shiny. You would need to check on the server side, whether the user has chosen one option in each group, and if not, display an error message, maybe with validate/need. I attach a simple example below.
Another option would be to drop the pickerInput and use radioGroupButtons, but this could look a bit messy, given that you have several inputs.
Example: check via server side and validate / need
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(shinyjs)
library(magrittr)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(title = "PickerInput Query", titleWidth=450),
dashboardSidebar( width = 300,
useShinyjs(),
sidebarMenu(id = "tabs")
),
dashboardBody(
tags$head(
tags$style(HTML("
.col-sm-10 {
width: 45% !important;
}
.col-sm-2 {
width: 55% !important;
}
"))),
textOutput("text"),
uiOutput('groupvar'),
uiOutput('shapetype')
))
server <- function(input, output, session) {
sx <- c("M","F")
#arm <- c(rep("DrugA",2),rep("DrugB",2),rep("Placebo_NotDrug",1))
arm <- c(rep("Drug A",2),rep("Drug B",2),rep("Placebo NotDrug",1))
d <- data.frame(
subjectID = c(1:100),
sex = c(rep("F",9),rep(sx,43),rep("M",5)),
treatment = c(rep(arm,20)),
race = c(rep("W",76),rep("B",15),rep("O",5),rep("H",1),rep("A",3)),
baseline_result = c(rnorm(50, 4, 3), rnorm(50, 3, 3)),
postbase_result = c(rnorm(50, 5, 3), rnorm(50, 4, 2)),
stringsAsFactors = FALSE)
dat <- reactive(d)
myfun <- function(df, var1) {
df %>% mutate(newvar = !!sym(var1)) # create newvar
}
output$groupvar<-renderUI({
bc<-colnames(dat()[sapply(dat(),class)=="character"])
tagList(
pickerInput(inputId = 'group.var',
label = 'Select group by variable. Then select order, color and shape',
choices = c("NONE",bc[1:length(bc)]), selected="NONE",
width = "350px",
options = list(`style` = "btn-warning"))
)
})
### pick order, color and shape
observeEvent(input$group.var, {
output$shapetype<-renderUI({
req(input$group.var,dat())
if(is.null(input$group.var)){
return(NULL)
}else if(sum(input$group.var=="NONE")==1){
return(NULL)
}else{
mydf <- subset(dat(), dat()[input$group.var] != "")
mydf2 <- myfun(mydf,input$group.var) ## create a new variable named newvar
mygrp <- as.character(unique(mydf2$newvar))
ngrp <- length(mygrp)
myorder <- (1:ngrp)
mycolor <- c("red", "blue", "green", "brown", "orange", "maroon")
myshape <- c("circle", "triangle", "plus", "cross", "diamond", "downtriangle")
lapply(1:ngrp, function(i){
pickerInput(paste0("line.vars.",i),
label = paste0(mygrp[i], ":" ),
choices = list(DisplayOrder = myorder,
ShapeColor = mycolor,
ShapeType = myshape,
Group = mygrp), ## how do we hide or disable this 4th item
selected = list( i, mycolor[i], myshape[i], mygrp[i] ),
multiple = T,
inline = TRUE,
width = "275px" , #mywidth,
options = list('max-options-group' = 1,
`style` = "btn-primary"))
})
}
})
}
, ignoreInit = TRUE)
output$text <- renderText({
validate(
need(length(input$line.vars.1) == 4,
"Please choose one option in every category to proceed.")
)
paste(input$line.vars.1, collapse = ", ")
})
}
shinyApp(ui, server)
#TimTeaFan, that is a great idea. That was my line of thinking before seeing #Stephane Laurent's excellent javascript answer. Stephane's answer works for one group, but not multi-dimensional groups. At least I have not been able to make it work for my app. I have modified #TimTeaFan's answer slightly and adapted it to all pickerInputs. I render it with renderUI. In your code output$text is modified as shown below. Obviously, textOutput should be changed to uiOutput in ui.
output$text <- renderUI({
if(is.null(input$group.var)){
return(NULL)
}else if(sum(input$group.var=="NONE")==1){
return(NULL)
}else{
lapply(1:ngrp(), function(i){
q1 <- paste0("line.vars.",i)
uivar <- expr('$'(input,!!q1))
req(uivar)
fval <- eval_tidy(uivar)
if (length(fval) < 4) {
tagList(
p("ERROR: Please choose one option in every category to proceed.", style = "color:red")
)
}else{ return(NULL) }
})
}
})
I will go with this for now, until I can get a better solution.
update: #StephaneLaurent has updated the javascript to solve this problem and another problem listed here. I will be using both these answers as I am not sure that I will be able to use js in all my pickerInputs based on how my ShinyApp has been setup. Many many many thanks to both #StephaneLaurent and #TimTeaFan.
Update2: The final answer I used to solve this issue is javascript from #Stephane Laurent. For completeness I have attached it below.
js <- "
$(document).ready(function(){
$('div[id^=shapetype]').on('show.bs.select', 'select[id^=linevars]', function(){
$('a[role=option]').on('click', function(e){
var classes = $(this).parent().attr('class').split(/\\s+/);
if(classes.length === 2){
var group = classes[0];
var $ul = $(this).parent().parent();
var selections = $ul.find('.' + group + '.selected');
if(selections.length === 1){
e.stopImmediatePropagation();
}
}else if(classes.length === 1){
var group = classes[0];
var $ul = $(this).parent().parent();
var groupname = $ul.find('li.dropdown-header.' + group + '>span').text();
if(groupname === 'Group'){
e.stopImmediatePropagation();
}
}
});
}).on('hide.bs.select', 'select[id^=linevars]', function(){
$('a[role=option]').off('click');
});
});"
The only caveat is that all the output names should start with shapetype, and variable IDs should start with linevars or adjust the above code appropriately. All ten plots in my shiny app work as expected.

Select max 2 different groups with pickerInput

I would like to restrict a pickerInput from shinyWidgets so that only elements from a maximum of 2 different groups can be selected. I know that I can restrict the selection to max 2 elements or to 2 elements per group, but I did not find a way to have max 2 groups selected, no matter the amount of selected elements inside those groups.
Here is a little toy example:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
pickerInput("groupslct", "Select elements from max 2 diff. Groups:",
choices = list(
Group1 = c(opt1 = "g11",
opt2 = "g12",
opt3 = "g13"),
Group2 = c(opt1 = "g21"),
Group3 = c(opt1 = "g31"),
Group4 = c(opt1 = "g41",
opt2 = "g42",
opt3 = "g43")
),
selected = 1, multiple = TRUE,
options = list("liveSearch" = TRUE,
# "max-options" = 2,
"max-options-group" = 2,
"selectOnTab" = TRUE
))
)
server <- function(input, output, session) {
observe({
print(input$kennwertauswahl)
})
}
shinyApp(ui, server)
I found a way using shinyjs, because updatePickerInput doesn't immediately refresh the input when changing the selected options.
library(shiny)
library(shinyjs)
library(shinyWidgets)
kennwertmap <- data.frame(vals=c("v", "vfree", "vref", "t", "state", "index", "index1", "index2"),
grp=c("v","v","v",
"t","s",
"ix","ix","ix"), stringsAsFactors = FALSE)
ui <- fluidPage(
useShinyjs(),
splitLayout(cellWidths = c("30%", "70%"),
div(style = "height: 1000px;",
pickerInput(("kennwertauswahl"), "Auswahl",
choices = list(
v = c(`mean v` = "v",
`mean v free` = "vfree",
`mean v ref` = "vref"),
t = c(`time` = "t"),
s = c(state = "state"),
i = c(index = "index",
index1 = "index1",
index2 = "index2")
),
selected = 1, multiple = TRUE,
options = pickerOptions(liveSearch = TRUE,
selectOnTab = TRUE))
),
div(
verbatimTextOutput("txt"),
verbatimTextOutput("txt1")
)
)
)
server <- function(input, output, session) {
kennwert <- reactiveValues(a = NULL)
observe({
if (is.null(input$kennwertauswahl)) {
kennwert$a <- NULL
} else {
isolate({
knwn <- input$kennwertauswahl
mappedkenw <- kennwertmap[kennwertmap$vals %in% knwn, ]
if (is.null(kennwert$a)) {
kennwert$a <- mappedkenw
} else {
## Check if 2 Groups already selected
if (length(unique(mappedkenw$grp)) > 2) {
## Grp to Remove
firstgrp <- kennwert$a[kennwert$a$grp != unique(kennwert$a$grp)[2],]
## Add One if new
newone <- setdiff(mappedkenw[,"vals"], kennwert$a$vals)
newone <- kennwertmap[kennwertmap$vals %in% newone, ]
newgrp <- rbind(firstgrp, newone)
kennwert$a <- newgrp
updatePickerInput(session, "kennwertauswahl", selected = newgrp$vals)
delay(100, runjs(HTML('$("#kennwertauswahl").selectpicker("refresh")')))
} else {
## Add One if new
newone <- setdiff(mappedkenw[,"vals"], kennwert$a$vals)
if (length(newone) != 0) {
newone <- kennwertmap[kennwertmap$vals %in% newone, ]
kennwert$a <- rbind(kennwert$a, newone)
}
## Remove One
lessone <- setdiff(kennwert$a$vals, mappedkenw[,"vals"])
if (length(lessone) != 0) {
kennwert$a <- kennwert$a[kennwert$a$vals != lessone,]
}
}
}
})
}
})
output$txt <- renderPrint({
print(input$kennwertauswahl)
})
output$txt1 <- renderPrint({
print(kennwert$a)
})
}
shinyApp(ui, server)

How to put 2 possibles eventReactive in only one variable

I am building a Shiny app which generate a dataframe from a database through the specific function my_function.
I want to use an eventReactive() to attribute the result of my_function depending on different inputs. My problem is that there are 2 ways to select these inputs which are structured in 2 different panels (I need this structure), so I have 2 actionButton that allow me to run my_function, and 1 variable for each eventReactive. Is there a way to put them in only 1 variable ?
df_all is a dataframe with several columns like "VAR1", "YEAR", "TYPE", "AGE" ... I need to filter depending on the inputs.
For the moment I have tried :
library(shiny)
library(shinydashboard)
library(DT)
library(dplyr)
df_all <- data.frame(
VAR1 = c(rep("A", 2), "B", "C")
YEAR = (rep(2001, 3), 2002)
TYPE = c("t1", "t2", "t2", "t1")
)
my_function <- function(arg1, arg2, arg3)
{
df = data.frame(
v1 = paste(arg1, arg2)
v2 = arg3
)
return(df)
}
shinyUI(dashboardPage(
dashboardHeader("title"),
dashboardSidebar(
sidebarMenu(id = "menu",
menuItem("Item1", tabName = "item1")
)),
dashboardBody(
tabItems(
tabItem(tabName = "item1",
selectInput(inputId = "var1", label = NULL, choices = c("A", "B", "C")),
tabsetPanel(
tabPanel("Item1-Panel1",
uiOutput("ui_year1"),
uiOutput("ui_type1"),
div(actionButton(inputId = "extra1", label = "Run", icon = icon("play")))),
tabPanel("Item1-Panel2",
uiOutput("ui_year2"),
uiOutput("ui_type2"),
div(actionButton(inputId = "extra2", label = "Run", icon = icon("play")))),
tabPanel("Item1-Panel3",
DT::dataTableOutput("tableau_ext1"),
DT::dataTableOutput("tableau_ext2"),
downloadButton("downloadCSV", "Save (CSV)"))
))))))
shinyServer(function(input, output) {
output$ui_year1 <- renderUI({
checkboxGroupInput(inputId = "year1", label = NULL, choices = df_all %>% filter(CULTURE == input$var1) %>% select(YEAR) %>% distinct() %>% pull()
})
output$ui_type1 <- renderUI({
checkboxGroupInput(inputId = "type1", label = NULL, choices = sort(df_all %>% filter(VAR1 == input$cult, YEAR %in% input$year1) %>% select(TYPE) %>% distinct() %>% pull())
})
output$ui_year2 <- renderUI({
checkboxGroupInput(inputId = "year2", label = NULL, choices = df_all %>% filter(VAR1 == input$var1) %>% select(YEAR) %>% distinct() %>% pull()
})
output$ui_type2 <- renderUI({
checkboxGroupInput(inputId = "type2", label = NULL, choices = sort(df_all %>% filter(VAR1 == input$cult, YEAR %in% input$year2) %>% select(TYPE) %>% distinct() %>% pull())
})
df1 <- eventReactive(input$extra1, {
my_function(arg1 = input$cult,
arg2 = as.numeric(input$year1),
arg3 = as.character(input$type1))
})
df2 <- eventReactive(input$extra2, {
my_function(arg1 = input$cult,
arg2 = as.numeric(input$year2),
arg3 = as.character(input$type2))
})
})
I tried to attribute the 2 eventReactive in 1 variable df, because I want to see and save the dataframe generated by my_function with :
shinyServer([...]
df <- eventReactive(input$extra1, {
my_function(arg1 = input$cult,
arg2 = as.numeric(input$year1),
arg3 = as.character(input$type1))
})
df <- eventReactive(input$extra2, {
my_function(arg1 = input$cult,
arg2 = as.numeric(input$year2),
arg3 = as.character(input$type2))
})
output$tableau_ext1 <- DT::renderDataTable({
df()
})
output$downloadCSV <- downloadHandler(
filename = function() {
paste0(input$year1, "_", input$type1, ".csv")
},
content = function(file) {
write.csv2(df(), file, row.names = FALSE)
}
)
)
But it didn't worked... If someone knows how to solve my problem, I will be grateful for his help :)
Building off of this thread the following seems to achieve the desired behavior (if I understand everything correctly):
library(shiny)
my_fun <- function() {
x <- sample(x=nrow(iris), size = 6)
x
}
ui <- fluidPage(
tabsetPanel(
tabPanel(title = "panel1",
actionButton("go1", "go 1")),
tabPanel(title = "panel2",
actionButton("go2", "go 2"))
),
mainPanel(dataTableOutput("tab"))
)
server <- function(input, output) {
df <- eventReactive(c(input$go1, input$go2), {
iris[my_fun(),]
}, ignoreNULL = FALSE, ignoreInit = TRUE)
output$tab <- renderDataTable({
df()
})
}
shinyApp(ui, server)
See also ?eventReactive for the ignoreNULL and ignoreInit options.
Edit: Two functions, one eventReactive, and keep track of tabs to know what to render.
library(shiny)
library(dplyr)
go1_fun <- function() {
x <- filter(iris, Species == "setosa") %>% head
x
}
go2_fun <- function() {
x <- filter(iris, Species == "virginica") %>% head
x
}
ui <- fluidPage(
tabsetPanel(id = "tabs",
tabPanel(title = "panel1",
actionButton("go1", "go 1")),
tabPanel(title = "panel2",
actionButton("go2", "go 2"))
),
mainPanel(dataTableOutput("tab"))
)
server <- function(input, output, session) {
df1 <- reactive({
if (req(input$go1)) {
x <- go1_fun()
}
return(x)
})
df2 <- reactive({
if (req(input$go2)) {
x <- go2_fun()
}
return(x)
})
tab_to_render <- eventReactive(c(input$go1, input$go2), {
if (input$tabs == "panel1") x <- df1()
if (input$tabs == "panel2") x <- df2()
return(x)
}, ignoreNULL = FALSE, ignoreInit = TRUE)
output$tab <- renderDataTable({
tab_to_render()
})
}
shinyApp(ui, server)

shiny update plot based on data.table

in my example app I have the user give some input and generate a data.table from it in the first tab. in the second tab I would like to show the plot, depending on the data.table. I am having quite a hard time to get the reactivity right. Unfortunately at this point I get the error: Operation not allowed without an active reactive context.
Please help me or give me hints what I am doing wrong.
the data:
tdata <- data.table(fruit = c("Apple", "Apple", "Apple", "Apple", "Apple", "Apple", "Apple", "Apple","Banana", "Banana","Banana","Banana","Banana", "Banana","Banana","Banana"),
Fertilizer = c(1,2,4,3,2,2,2,2,1,4,3,2,4,4,3,1),
amount = c(2,3,4,7,1,34,33,21,12,32,22,17,14,9,22,6),
red = rep(c("+","+","-","-"),4),
green = rep(c("+","-"),8))
tdata[, grp := do.call(paste, c(list(sep="\n"),.SD)),.SDcols = 4:5]
UI:
library(shiny)
library(data.table)
library(DT)
ui <- (fluidPage(tagList(
sidebarLayout(
sidebarPanel(uiOutput("file_input")),
mainPanel(
tabsetPanel(
tabPanel("Data",dataTableOutput('fruit_table') ),
tabPanel("Plot", plotOutput('barPlot'))
))))))
Server:
server <- function(input, output) {
fileData <- reactive(
return(tdata)
)
output$file_input <- renderUI ({
if(is.null(fileData())){
return()
}else{
tagList(
checkboxGroupInput(inputId = "fruit",
label = "fruit",
choices = c(unique(fileData()[,get("fruit")])),
selected = fileData()[1, 1, with = FALSE]),
checkboxGroupInput(inputId = "tube",
label = "Fertilizer",
choices = unique(fileData()[,get("Fertilizer")]),
selected = fileData()[1, 3, with = F]),
###build checkboxes from Loop:
lapply(1:(length(fileData())-4), function(i) {
checkboxGroupInput(inputId = paste0("color",i),
label = colnames(fileData()[,i+3, with = FALSE]),
choices = c(unique(fileData()[,get(colnames(fileData()[,i+3, with = FALSE]))])),
inline = TRUE,
selected = fileData()[1, i+3, with = FALSE])
}))}})
output$fruit_table <- renderDataTable({
if(is.null(fileData())){
return(NULL)
}else{
validate(
need(input$fruit, 'Check at least one fruit'),
need(input$tube, 'Check at least one Fertilizer'),
####loop not working in here
need(input$color1, "Check at least one !"),
need(input$color2, "Check at least one !")
)
filter_expr <- TRUE
if (!(is.null(input$fruit))) {
filter_expr <- filter_expr & fileData()[,fruit] %in% input$fruit
#print((input$fruit))
}
if (!(is.null(input$tube))) {
filter_expr <- filter_expr & fileData()[,Fertilizer] %in% input$tube
}
##non-loop-verison
if (!(is.null(input$color1))) {
filter_expr <- filter_expr & fileData()[,red] %in% input$color1
}
if (!(is.null(input$color2))) {
filter_expr <- filter_expr & fileData()[,green] %in% input$color2
}
datatable(fileData()[filter_expr,],options = list(pageLength = 25))
}})
plot.dat <- reactiveValues(main = NULL)
plot.dat$main <- ggplot(data = fileData(), mapping = aes( x = fileData()[,grp], y =fileData()[,amount]))+
geom_boxplot( stat = 'boxplot',
position = position_dodge(width=0.8),
width = 0.55)
observe({
output$barPlot <- renderPlot({
if(is.null(fileData())){
return(NULL)
}else{
validate(
need(input$fruit, 'Check at least one fruit'),
need(input$tube, 'Check at least one Fertilizer'),
need(input$color1, "Check at least one !"),
need(input$color2, "Check at least one !")
)
plot.dat$main
}})
})
}
shinyApp(ui = ui, server = server
)
You need to update the data that gets plotted. See the following working code. I extracted the data to filter in a reactive expression myFilter. This needs to be called before creating the table as well as before creating the plot.
library(shiny)
library(data.table)
library(DT)
library(ggplot2)
tdata <- data.table(fruit = c("Apple", "Apple", "Apple", "Apple", "Apple", "Apple", "Apple", "Apple","Banana", "Banana","Banana","Banana","Banana", "Banana","Banana","Banana"),
Fertilizer = c(1,2,4,3,2,2,2,2,1,4,3,2,4,4,3,1),
amount = c(2,3,4,7,1,34,33,21,12,32,22,17,14,9,22,6),
red = rep(c("+","+","-","-"),4),
green = rep(c("+","-"),8))
tdata[, grp := do.call(paste, c(list(sep="\n"),.SD)),.SDcols = 4:5]
ui <- (fluidPage(tagList(
sidebarLayout(
sidebarPanel(uiOutput("file_input")),
mainPanel(
tabsetPanel(
tabPanel("Data",dataTableOutput('fruit_table') ),
tabPanel("Plot", plotOutput('boxPlot'))
))))))
server <- function(input, output) {
fileData <- tdata # static data, doesn't change, noneed to be reactive
output$file_input <- renderUI ({
validate(need(!is.null(fileData), ''))
tagList(
checkboxGroupInput(inputId = "fruit",
label = "fruit",
choices = c(unique(fileData[,get("fruit")])),
selected = fileData[1, 1, with = FALSE]),
checkboxGroupInput(inputId = "tube",
label = "Fertilizer",
choices = unique(fileData[,get("Fertilizer")]),
selected = fileData[1, 3, with = F]),
###build checkboxes from Loop:
lapply(seq(length(fileData)-4), function(i) {
checkboxGroupInput(inputId = paste0("color",i),
label = colnames(fileData[,i+3, with = FALSE]),
choices = c(unique(fileData[,get(colnames(fileData[,i+3, with = FALSE]))])),
inline = TRUE,
selected = fileData[1, i+3, with = FALSE])
})
)
})
# build a filter according to inputs
myFilter <- reactive({
validate(need(!is.null(fileData), ''))
validate(
need(input$fruit, 'Check at least one fruit'),
need(input$tube, 'Check at least one Fertilizer'),
need(input$color1, "Check at least one !"),
need(input$color2, "Check at least one !")
)
fileData[,fruit] %in% input$fruit & fileData[,Fertilizer] %in% input$tube &
fileData[,red] %in% input$color1 & fileData[,green] %in% input$color2
})
# print the datatable matching myFilter()
output$fruit_table <- renderDataTable({
datatable(fileData[myFilter(),],options = list(pageLength = 25))
})
# build a boxPLot according to myFilter()
output$boxPlot <- renderPlot({
validate(
need(!is.null(fileData), ''),
need(input$fruit, 'Check at least one fruit'),
need(input$tube, 'Check at least one Fertilizer'),
need(input$color1, "Check at least one !"),
need(input$color2, "Check at least one !")
)
data <- fileData[myFilter(),]
ggplot(data = data, mapping = aes( x = data[,grp], y =data[,amount]))+
geom_boxplot( stat = 'boxplot',
position = position_dodge(width=0.8),
width = 0.55)
})
}
shinyApp(ui = ui, server = server)

Resources