Obtain contingecy table based on users input - Rshiny - r

If I want to obtain the fisher test first I need a contigency table. I can do that for the Arthritis package by simply:
library(vcd)
data(Arthritis)
freq <- as.data.frame.matrix(table(Arthritis$Treatment, Arthritis$Improved))
> freq
None Some Marked
Placebo 29 7 7
Treated 13 7 21
So I could do for example, a fisher test for:
Not marked Marked
Placebo 36 7
Treated 20 21
For now, what I want to do in shiny is allow the user to select two categorical variables (Treatment and Improved), and then filter by another one (Gender) and obtain the contingency table.
I could use later this one to obtain the 2x2 frequency. But for now this is what I have:
# Shiny
library(shiny)
library(shinyWidgets)
library(shinyjqui)
# Data
library(vcd)
library(readxl)
library(dplyr)
library(arules) # Discretization
# Plots
library(ggplot2)
not_sel <- "Not Selected"
ui <- fluidPage(
titlePanel("Plotter"),
sidebarPanel(
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)),
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
selectInput("biomarker", "Select Biomarker", choices = c(not_sel)), uiOutput("factor")
),
mainPanel(
tabsetPanel(
tabPanel(
verbatimTextOutput("test")
)
)
)
)
## Server ##
server <- function(input, output){
# Dynamic selection of the data. We allow the user to input the data that they want
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
Arthritis
})
# We update the choices available for each of the variables
observeEvent(data_input(),{
choices <- c(not_sel, names(data_input()))
updateSelectInput(inputId = "num_var_1", choices = choices)
updateSelectInput(inputId = "num_var_2", choices = choices)
updateSelectInput(inputId = "biomarker", choices = choices)
})
num_var_1 <- eventReactive(input$run_button, input$num_var_1)
num_var_2 <- eventReactive(input$run_button, input$num_var_2)
biomarker <- eventReactive(input$run_button, input$biomarker)
output$factor <- renderUI({
req(input$biomarker, data_input())
if (input$biomarker != not_sel) {
b <- unique(data_input()[[input$biomarker]])
pickerInput(inputId = 'selected_factors',
label = 'Select factors',
choices = c(b[1:length(b)]), selected=b[1], multiple = TRUE,
# choices = c("NONE",b[1:length(b)]), selected="NONE", If we want "NONE" to appear as the first option
# multiple = TRUE, ## if you wish to select multiple factor values; then deselect NONE
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
}
})
data_stats_discrete <- reactive({
req(data_input(), input$num_var_1, input$num_var_2, input$biomarker)
# We filter by biomarker in case user selected, otherwise data_input() remains the same
if (input$biomarker != "Not Selected") df <- data_input()[data_input()[[input$biomarker]] %in% input$selected_factors,]
else df <- data_input()
df <- as.data.frame.matrix(table(.data[[input$num_var_1]], .data[[input$num_var_2]]))
df
})
output$test <- renderPrint(data_stats_discrete())
}
shinyApp(ui = ui, server = server)
As you can see in this RepEx, no dataframe is being selected in the data_stats_discrete.

Change
df <- as.data.frame.matrix(table(.data[[input$num_var_1]], .data[[input$num_var_2]]))
to
df <- as.data.frame.matrix(table(df[[input$num_var_1]], df[[input$num_var_2]]))

Related

Filtering data according to column name and respective column's values in shiny

I am new in shiny, and maybe it can be easy but I could not make it, so I want to select column name firstly and in second box, it show unique values for selected column, and when choosing any values data table and plot appearing, plot will based on filtered part, thats why it is not hard but my main difficulties to extract interactive filter for data and and in default version, it should be whole data. I share what I have dont it is not working and not correct (this code is without data, I can not share data), I corrected some codes, now I can filter according to one value, but I want to see whole data in default version.
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
pickerInput("eda_col", "Select variable",
choices = c("col 1", "col 2", "col 3", "col 4"), selected = character(0)),
uiOutput("varselect"),
# selectInput("xSelector", label = "Select x axis", choices = xAxischoices),
# selectInput("ySelector", label = "Select the y axis", choices = yAxischoices),
# selectInput("cyLSelector", label = "Select a cylinder", choices = cylinderChoices),
actionButton("RefreshPlot", label = "Refresh")
),
mainPanel(
dataTableOutput("datatable1")
)
)
)
server <- function(input, output) {
output$varselect <- renderUI({
vars <- d[[as.name(input$eda_col)]]
checkboxGroupInput("level_choice", "Select factors to include", unique(vars))
})
# vars_r <- reactive({
# input$vars
# })
#
#
# res_mod <- callModule(
# module = selectizeGroupServer,
# id = "my-filters",
# data = d,
# vars = vars_r
# )
#
# output$table <- DT::renderDataTable({
# req(res_mod())
# res_mod()
# })
filteredData <- reactive({
filteredData <- d %>% filter((!! rlang:: sym(input$eda_col)) == input$level_choice)
return(filteredData)
})
output$datatable1 <- renderDataTable({
datatable(filteredData())
})
}
shinyApp(ui, server)
Please present a full MRE in the future. I have presented your requirements using available dataset gapminder. If this is not your expectation, please update your question using mtcars or gapminder data. Try this
library(gapminder)
choices <- names(gapminder)[1:2]
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
pickerInput("eda_col", "Select variable",
choices = choices, selected = character(0)),
uiOutput("varselect"),
# selectInput("xSelector", label = "Select x axis", choices = xAxischoices),
# selectInput("ySelector", label = "Select the y axis", choices = yAxischoices),
# selectInput("cyLSelector", label = "Select a cylinder", choices = cylinderChoices),
actionButton("RefreshPlot", label = "Refresh")
),
mainPanel(
dataTableOutput("datatable1")
)
)
)
server <- function(input, output) {
output$varselect <- renderUI({
if (is.null(input$eda_col)) vars <- names(gapminder)[1] ## define your default variable selection
else vars <- gapminder[[as.name(input$eda_col)]]
checkboxGroupInput("level_choice", "Select factors to include", unique(vars))
})
# vars_r <- reactive({
# input$vars
# })
#
#
# res_mod <- callModule(
# module = selectizeGroupServer,
# id = "my-filters",
# data = d,
# vars = vars_r
# )
#
# output$table <- DT::renderDataTable({
# req(res_mod())
# res_mod()
# })
filteredData <- reactive({
filteredData <- gapminder %>% filter((!! rlang:: sym(input$eda_col)) %in% input$level_choice)
return(filteredData)
})
output$datatable1 <- renderDataTable({
datatable(filteredData())
})
}
shinyApp(ui, server)

Create contingency tablel based on users input - Rshiny

For two categorical variables inside a dataframe I want to compute the fisher test based on the user selection for the variables, specific factors of these variables (and also filtering by another column).
For this, I need to obtain the contingency table, and then apply the fisher.test function.
Just to visualize it, here is how it can be done in R base:
library(vcd)
library(dplyr)
a <- Arthritis %>%
dplyr::filter(Treatment == "Treated") %>%
dplyr::filter(Improved == "Some") %>%
count() %>%
as.numeric()
b <- Arthritis %>%
dplyr::filter(Treatment == "Treated") %>%
dplyr::filter(Improved != "Some") %>%
count() %>%
as.numeric()
c <- Arthritis %>%
dplyr::filter(Treatment == "Placebo") %>%
dplyr::filter(Improved == "Some") %>%
count() %>%
as.numeric()
d <- Arthritis %>%
dplyr::filter(Treatment == "Placebo") %>%
dplyr::filter(Improved != "Some") %>%
count() %>%
as.numeric()
data <- as.data.frame(matrix(c(a,b,c,d), nrow= 2, ncol = 2, byrow = TRUE))
fisher.test(data)
For the RepEx below I just want to obtain the contingency table.
You can see it clearly, but just to explain a little bit:
First we create the UI, where we allow the user to select several variables (var1, var2, biomarker) and then the factors for the statistics.
Then we update this variables based on user input
We create the contingency table (dataframe) based on the users selection
# Shiny
library(shiny)
library(shinyWidgets)
library(shinyjqui)
# Data
library(vcd)
library(readxl)
library(dplyr)
# Plots
library(ggplot2)
# Stats cohen.d wilcox.test
library(effsize)
not_sel <- "Not selected"
## UI
ui <- navbarPage(
tabPanel(
title = "Plotter",
titlePanel("Plotter"),
sidebarLayout(
sidebarPanel(
title = "Inputs",
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)), # X variable num_var_1
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
selectInput("biomarker", "Select biomarker", choices = c(not_sel)), uiOutput("factor"),
uiOutput("Xgroup1"),uiOutput("Xgroup2"), uiOutput("Ygroup1"), uiOutput("Ygroup2"),
br(),
actionButton("run_button", "Run Analysis", icon = icon("play"))
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Statistics",
verbatimTextOutput("test")
)
)
)
)
)
)
## Server
server <- function(input, output){
# Dynamic selection of the data. We allow the user to input the data that they want
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
Arthritis
})
# We update the choices available for each of the variables
observeEvent(data_input(),{
choices <- c(not_sel, names(data_input()))
updateSelectInput(inputId = "num_var_1", choices = choices)
updateSelectInput(inputId = "num_var_2", choices = choices)
updateSelectInput(inputId = "biomarker", choices = choices)
})
num_var_1 <- eventReactive(input$run_button, input$num_var_1)
num_var_2 <- eventReactive(input$run_button, input$num_var_2)
biomarker <- eventReactive(input$run_button, input$biomarker)
## Update variables
# Factor for the biomarker
output$factor <- renderUI({
req(input$biomarker, data_input())
if (input$biomarker != not_sel) {
b <- unique(data_input()[[input$biomarker]])
pickerInput(inputId = 'selected_factors',
label = 'Select factors',
choices = c(b[1:length(b)]), selected=b[1], multiple = TRUE,
# choices = c("NONE",b[1:length(b)]), selected="NONE", If we want "NONE" to appear as the first option
# multiple = TRUE, ## if you wish to select multiple factor values; then deselect NONE
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
}
})
output$Xgroup1 <- renderUI({
req(input$num_var_1, data_input())
c <- unique(data_input()[[input$num_var_1]])
pickerInput(inputId = 'selected_Xgroup1',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Xgroup2 <- renderUI({
req(input$num_var_1, data_input())
d <- unique(data_input()[[input$num_var_1]])
pickerInput(inputId = 'selected_Xgroup2',
label = 'Select group for statistics',
choices = c(d[1:length(d)]), selected=d[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Ygroup1 <- renderUI({
req(input$num_var_2, data_input())
c <- unique(data_input()[[input$num_var_2]])
pickerInput(inputId = 'selected_Ygroup1',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Ygroup2 <- renderUI({
req(input$num_var_2, data_input())
c <- unique(data_input()[[input$num_var_2]])
pickerInput(inputId = 'selected_Ygroup1',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
##############################################################################
data_stats <- reactive({
req(data_input(), input$num_var_1, input$num_var_2, input$biomarker, input$selected_factors)
# We filter by biomarker in case user selected, otherwise data_input() remains the same
if (input$biomarker != "Not Selected") df <- data_input()[data_input()[[input$biomarker]] %in% input$selected_factors,]
else df <- data_input()
a <- df %>%
dplyr:filter(.data[[input$num_var_1]] %in% input$Xgroup1) %>%
dplyr:filter(.data[[input$num_var_2]] %in% input$Ygroup1) %>%
count()
b <- df %>%
dplyr:filter(.data[[input$num_var_1]] %in% input$Xgroup2) %>%
dplyr:filter(.data[[input$num_var_2]] %in% input$Ygroup1) %>%
count()
c <- df %>%
dplyr:filter(.data[[input$num_var_1]] %in% input$Xgroup1) %>%
dplyr:filter(.data[[input$num_var_2]] %in% input$Ygroup2) %>%
count()
d <- df %>%
dplyr:filter(.data[[input$num_var_1]] %in% input$Xgroup2) %>%
dplyr:filter(.data[[input$num_var_2]] %in% input$Ygroup2) %>%
count()
data <- as.data.frame(matrix(c(a,b,c,d), nrow= 2, ncol = 2, byrow = TRUE))
})
output$test <- renderPrint(data_stats())
}
shinyApp(ui = ui, server = server)
However, this app is not generating any results.
You have a few syntax errors. First, the inputID for Ygroup2 was still selected_Ygroup1. Second, dplyr:filter() will not reference the dplyr package as it should be dplyr::filter() - that is double colon. Lastly, your variables should not be input$Xgroup1 but actually be input$selected_Xgroup1, and so on. Also, it is better to have eventReactive instead of reactive. Try this
# Shiny
library(shiny)
library(shinyWidgets)
library(shinyjqui)
# Data
library(vcd)
library(readxl)
library(dplyr)
# Plots
library(ggplot2)
# Stats cohen.d wilcox.test
library(effsize)
not_sel <- "Not selected"
## UI
ui <- navbarPage(
tabPanel(
title = "Plotter",
titlePanel("Plotter"),
sidebarLayout(
sidebarPanel(
title = "Inputs",
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)), # X variable num_var_1
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
selectInput("biomarker", "Select biomarker", choices = c(not_sel)), uiOutput("factor"),
uiOutput("Xgroup1"),uiOutput("Xgroup2"), uiOutput("Ygroup1"), uiOutput("Ygroup2"),
br(),
actionButton("run_button", "Run Analysis", icon = icon("play"))
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Statistics",
verbatimTextOutput("test")
)
)
)
)
)
)
## Server
server <- function(input, output){
# Dynamic selection of the data. We allow the user to input the data that they want
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
Arthritis
})
# We update the choices available for each of the variables
observeEvent(data_input(),{
choices <- c(not_sel, names(data_input()))
updateSelectInput(inputId = "num_var_1", choices = choices)
updateSelectInput(inputId = "num_var_2", choices = choices)
updateSelectInput(inputId = "biomarker", choices = choices)
})
num_var_1 <- eventReactive(input$run_button, input$num_var_1)
num_var_2 <- eventReactive(input$run_button, input$num_var_2)
biomarker <- eventReactive(input$run_button, input$biomarker)
## Update variables
# Factor for the biomarker
output$factor <- renderUI({
req(input$biomarker, data_input())
if (input$biomarker != not_sel) {
b <- unique(data_input()[[input$biomarker]])
pickerInput(inputId = 'selected_factors',
label = 'Select factors',
choices = c(b[1:length(b)]), selected=b[1], multiple = TRUE,
# choices = c("NONE",b[1:length(b)]), selected="NONE", If we want "NONE" to appear as the first option
# multiple = TRUE, ## if you wish to select multiple factor values; then deselect NONE
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
}
})
output$Xgroup1 <- renderUI({
req(input$num_var_1, data_input())
c <- unique(data_input()[[input$num_var_1]])
pickerInput(inputId = 'selected_Xgroup1',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Xgroup2 <- renderUI({
req(input$num_var_1, data_input())
d <- unique(data_input()[[input$num_var_1]])
pickerInput(inputId = 'selected_Xgroup2',
label = 'Select group for statistics',
choices = c(d[1:length(d)]), selected=d[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Ygroup1 <- renderUI({
req(input$num_var_2, data_input())
c <- unique(data_input()[[input$num_var_2]])
pickerInput(inputId = 'selected_Ygroup1',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
output$Ygroup2 <- renderUI({
req(input$num_var_2, data_input())
c <- unique(data_input()[[input$num_var_2]])
pickerInput(inputId = 'selected_Ygroup2',
label = 'Select group for statistics',
choices = c(c[1:length(c)]), selected=c[1], multiple = TRUE,
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
})
##############################################################################
data_stats <- eventReactive(input$run_button, {
req(data_input(), input$num_var_1, input$num_var_2, input$biomarker, input$selected_factors)
req(input$selected_Xgroup1,input$selected_Xgroup2,input$selected_Ygroup1,input$selected_Ygroup2)
# We filter by biomarker in case user selected, otherwise data_input() remains the same
if (input$biomarker != "Not Selected") df <- data_input()[data_input()[[input$biomarker]] %in% input$selected_factors,]
else df <- data_input()
a <- df %>%
dplyr::filter(.data[[input$num_var_1]] %in% input$selected_Xgroup1) %>%
dplyr::filter(.data[[input$num_var_2]] %in% input$selected_Ygroup1) %>%
count()
b <- df %>%
dplyr::filter(.data[[input$num_var_1]] %in% input$selected_Xgroup2) %>%
dplyr::filter(.data[[input$num_var_2]] %in% input$selected_Ygroup1) %>%
count()
c <- df %>%
dplyr::filter(.data[[input$num_var_1]] %in% input$selected_Xgroup1) %>%
dplyr::filter(.data[[input$num_var_2]] %in% input$selected_Ygroup2) %>%
count()
d <- df %>%
dplyr::filter(.data[[input$num_var_1]] %in% input$selected_Xgroup2) %>%
dplyr::filter(.data[[input$num_var_2]] %in% input$selected_Ygroup2) %>%
count()
data <- as.data.frame(matrix(c(a,b,c,d), nrow= 2, ncol = 2, byrow = TRUE))
m <- matrix(unlist(data), 2)
fisher.test(m)
})
output$test <- renderPrint(data_stats())
}
shinyApp(ui = ui, server = server)

Rshiny not producing plots after user's input change

Roman history fan here, so I have a dataframe with the name of two legions (fifth and tirteenth), their casualties (numerical value), and the morale of the troops (high, medium, low).
I want to know (boxplot) the relationship between morale (x axis) and casualties (y axis), and also subset by legion.
Please notice that this is a toy example. In the real data (no romans) we have several variables for each of the axis, so we ask the user to load the data, and then select which variables he wants to use for each axis.
Here you have a RepEx:
Legion <- c("Fifth", "Fifth", "Fifth","Fifth","Fifth","Tirteenth","Tirteenth", "Tirteenth", "Tirteenth","Tirteenth")
Casualties <- c(13, 34,23,123,0,234,3,67,87,4)
Morale <- c("High", "Medium", "Low","High", "Medium", "Low","High", "Medium", "Low", "High")
romans <- data.frame(Legion, Casualties, Morale)
# Shiny
library(shiny)
library(shinyWidgets)
# Data
library(readxl)
library(dplyr)
# Data
library(effsize)
# Objects and functions
not_sel <- "Not Selected"
main_page <- tabPanel(
title = "Romans",
titlePanel("Romans"),
sidebarLayout(
sidebarPanel(
title = "Inputs",
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)),
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
selectInput("factor", "Select factor", choices = c(not_sel)), uiOutput("leg"), # This group will be the main against the one we will perform the statistics
br(),
actionButton("run_button", "Run Analysis", icon = icon("play"))
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Plot",
plotOutput("plot_1")
)
)
)
)
)
# Function for printing the plots with two different options
# When there is not a selection of the biomarker (we will take into account var_1 and var_2)
# And when there is a selection of the biomarker (we will take into account the three of them)
draw_boxplot <- function(data_input, num_var_1, num_var_2, biomarker){
print(num_var_1)
if(num_var_1 != not_sel & num_var_2 != not_sel & biomarker == not_sel){
ggplot(data = data_input, aes(x = .data[[num_var_1]], y = .data[[num_var_2]])) +
geom_boxplot() +
theme_bw()
}
else if(num_var_1 != not_sel & num_var_2 != not_sel & biomarker != not_sel){
ggplot(data = data_input, aes(x = .data[[num_var_1]], y = .data[[num_var_2]])) +
geom_boxplot() +
theme_bw()
}
}
################# --------------------------------------------------------------
# User interface
################# --------------------------------------------------------------
ui <- navbarPage(
main_page
)
################# --------------------------------------------------------------
# Server
################# --------------------------------------------------------------
server <- function(input, output){
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
romans
})
# We update the choices available for each of the variables
observeEvent(data_input(),{
choices <- c(not_sel, names(data_input()))
updateSelectInput(inputId = "num_var_1", choices = choices)
updateSelectInput(inputId = "num_var_2", choices = choices)
updateSelectInput(inputId = "factor", choices = choices)
})
# Allow user to select the legion
output$leg <- renderUI({
req(input$factor, data_input())
if (input$factor != not_sel) {
b <- unique(data_input()[[input$factor]])
pickerInput(inputId = 'selected_factors',
label = 'Select factors',
choices = c(b[1:length(b)]), selected=b[1], multiple = TRUE,
# choices = c("NONE",b[1:length(b)]), selected="NONE", If we want "NONE" to appear as the first option
# multiple = TRUE, ## if you wish to select multiple factor values; then deselect NONE
options = list(`actions-box` = TRUE)) #options = list(`style` = "btn-warning"))
}
})
num_var_1 <- eventReactive(input$run_button, input$num_var_1)
num_var_2 <- eventReactive(input$run_button, input$num_var_2)
factor <- eventReactive(input$run_button, input$factor)
## Plot
plot_1 <- eventReactive(input$run_button,{
#print(input$selected_factors)
req(input$factor, data_input())
if (!is.null(input$selected_factors)) df <- data_input()[data_input()[[input$factor]] %in% input$selected_factors,]
else df <- data_input()
draw_boxplot(df, num_var_1(), num_var_2(), factor())
})
output$plot_1 <- renderPlot(plot_1())
}
# Connection for the shinyApp
shinyApp(ui = ui, server = server)
This code works fine at the beginning. However, there is a major inconvenience.
As you can see, the user can choose three different panels. In the image attached we would be getting the plot for the morale over the casualties, filtering only for the fifth legion.
enter image description here
However, if after filtering by legion, we deselect this box, then we will be getting an empty plot, as I show in the image.
enter image description here
I don't really know where the issue may be comming from. I thought it may be in 'pickerInput', but that doesn't make much sense. I'm not getting any hints by R either. It is probably here:
req(input$factor, data_input())
if (!is.null(input$selected_factors)) df <- data_input()[data_input()[[input$factor]] %in% input$selected_factors,]
else df <- data_input()
Any help would be appreciated.
You correctly pinned down which part of the code was causing issues. What happens is that first you render the input$selected_factors by selecting an input$factor. The legion that you have selected in this input is now in memory (meaning not NULL) for the first time. Next you change the input$factor to "Not Selected" which hides the input$selected_factors UI, however it doesn't erase it's memory. Even if your UI is hidden your input$selected_factors will remain "fifth" which triggers your if condition. However data_input()[["Not Selected"]] will return an empty table.
My recommendation would be to change the if condition like so:
if (input$factor != "Not Selected") df <- data_input()[data_input()[[input$factor]] %in% input$selected_factors,]
else df <- data_input()

Shiny - adding/appending user-selected observations to a list of observations to analyze

The user interface of the Shiny app I'm working on is supposed to work in the following manner:
User finds the desired observation(s) after applying a set of filters.
User clicks "Add" action button, so selected observation(s) are added to a running list/vector/etc of observations to be analyzed.
User modifies filters to find other observations which are to be included as well.
Loop back to step 1 as many times as user desires.
I cannot seem to find a way to save this list of observations to be analyzed. In the example I attached, the "observation ID" is the name of the model of the car (mtcars is used). I also did not include any data analysis, since I do not think that's necessary. In essence, the entire dataset (mtcars) should be filtered using dplyr in a reactive environment to only include the running list of selected observations.
Here's the code:
data("mtcars")
mtcars$model <- rownames(mtcars)
ui <- fluidPage(
titlePanel("sample"),
sidebarLayout(
sidebarPanel(
uiOutput("disp"),
uiOutput("qsec"),
uiOutput("model"),
actionButton("add", "Add"),
uiOutput("selectedModel")
),
mainPanel(
plotOutput("data_analysis")
)
)
)
server <- function(input, output) {
output$disp <- renderUI({
selectInput(
"disp_sel",
"Select disp:",
unique(mtcars$disp),
selected = NULL,
multiple = T,
selectize = T
)
})
output$qsec <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
selectInput(
"qsec_sel",
"Select qsec:",
unique(temp$qsec),
selected = NULL,
multiple = T,
selectize = T
)
})
output$model <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
if (!is.null(input$qsec_sel)){temp = temp %>% filter(qsec %in% input$qsec_sel)}
selectInput(
"model_sel",
"Select model:",
unique(temp$model),
selected = NULL,
multiple = T,
selectize = T
)
})
output$selectedModel <- renderUI({
req(input$add)
selectInput(
"list_of_selections",
"Selected models:",
unique(mtcars$model),
selected = NULL, # this should change when "Add" is pressed
multiple = T,
selectize = T
)
})
r_data = eventReactive(input$add,{
mtcars %>% filter(model %in% input$list_of_selections)
})
output$data_analysis <- renderPlot({
# do something with r_data (filtered data)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I've looked into modular code, reactive lists, and other stuff I don't even remember... Any help is greatly appreciated.
Try this
data("mtcars")
mtcars$model <- rownames(mtcars)
df1 <- mtcars
ui <- fluidPage(
titlePanel("sample"),
sidebarLayout(
sidebarPanel(
uiOutput("disp"),
uiOutput("qsec"),
uiOutput("model"),
actionButton("add", "Add"),
uiOutput("selectedModel")
),
mainPanel(
DTOutput("selecteddata"),
plotOutput("data_analysis")
)
)
)
server <- function(input, output) {
output$disp <- renderUI({
selectInput(
"disp_sel",
"Select disp:",
unique(mtcars$disp),
selected = NULL,
multiple = T,
selectize = T
)
})
output$qsec <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
selectInput(
"qsec_sel",
"Select qsec:",
unique(temp$qsec),
selected = NULL,
multiple = T,
selectize = T
)
})
output$model <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
if (!is.null(input$qsec_sel)){temp = temp %>% filter(qsec %in% input$qsec_sel)}
selectInput(
"model_sel",
"Select model:",
unique(temp$model),
selected = NULL,
multiple = T,
selectize = T
)
})
selected_data <- eventReactive(input$add,{
df1 %>% filter(model %in% input$model_sel)
})
output$selecteddata <- renderDT(
selected_data(), # reactive data
class = "display nowrap compact", # style
filter = "top", # location of column filters
options = list( # options
scrollX = TRUE # allow user to scroll wide tables horizontally
)
)
output$selectedModel <- renderUI({
req(input$add)
selectInput(
"list_of_selections",
"Selected models:",
choices = unique(selected_data()$model),
selected = unique(selected_data()$model), # this should change when "Add" is pressed
multiple = T,
selectize = T
)
})
r_data = eventReactive(input$add,{
mtcars %>% filter(model %in% input$list_of_selections)
})
output$data_analysis <- renderPlot({
ggplot(data=selected_data(), aes(x=disp, y=qsec)) + geom_point()
# do something with r_data (filtered data)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Found the answer. I included
selected <- reactiveValues(s = NULL)
observeEvent(input$add,{selected$s = c(selected$s, input$model})
into the server part. Then the selected models are stored in selected$s.

Shiny breaks if dynamically change datasets

I am trying to create a shiny app where depending on the dataset, ggvis will create a scatter plot. The app works fine at the beginning. But if I try to change the dataset to mtcars, shiny just disappears.
My ui.R -
library(ggvis)
library(shiny)
th.dat <<- rock
shinyUI(fluidPage(
titlePanel("Reactivity"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "mtcars")),
selectInput("xvar", "Choose x", choices = names(th.dat), selected = names(th.dat)[1]),
selectInput("yvar", "Choose y", choices = names(th.dat), selected = names(th.dat)[2]),
selectInput("idvar", "Choose id", choices = names(th.dat), selected = names(th.dat)[3])
),
mainPanel(
ggvisOutput("yup")
)
)
))
server.R -
library(ggvis)
library(shiny)
library(datasets)
shinyServer(function(input, output, session) {
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"mtcars" = mtcars)
})
obs <- observe({
input$dataset
th.dat <<- datasetInput()
s_options <- list()
s_options <- colnames(th.dat)
updateSelectInput(session, "xvar",
choices = s_options,
selected = s_options[[1]]
)
updateSelectInput(session, "yvar",
choices = s_options,
selected = s_options[[2]]
)
updateSelectInput(session, "idvar",
choices = s_options,
selected = s_options[[3]]
)
})
xvarInput <- reactive({
input$dataset
input$xvar
print("inside x reactive," )
print(input$xvar)
xvar <- input$xvar
})
yvarInput <- reactive({
input$dataset
input$yvar
print("inside y reactive,")
print(input$yvar)
yvar <- input$yvar
})
dat <- reactive({
dset <- datasetInput()
xvar <- xvarInput()
# print(xvar)
yvar <- yvarInput()
# print(yvar)
x <- dset[, xvar]
y <- dset[,yvar]
df <- data.frame(x = x, y = y)
})
dat %>%
ggvis(~x, ~y) %>%
layer_points() %>%
bind_shiny("yup")
})
I have tried many ways, but still stuck. Any help will be greatly appreciated.
I left some pointers in the comments but it seems that ggvis evaluates everything quite early so there is a need for some test cases.
rm(list = ls())
library(shiny)
library(ggvis)
ui <- fluidPage(
titlePanel("Reactivity"),
sidebarPanel(
selectInput("dataset", "Choose a dataset:", choices = c("rock", "mtcars")),
uiOutput("xvar2"),uiOutput("yvar2"),uiOutput("idvar2")),
mainPanel(ggvisOutput("yup"))
)
server <- (function(input, output, session) {
dataSource <- reactive({switch(input$dataset,"rock" = rock,"mtcars" = mtcars)})
# Dynamically create the selectInput
output$xvar2 <- renderUI({selectInput("xvar", "Choose x",choices = names(dataSource()), selected = names(dataSource())[1])})
output$yvar2 <- renderUI({selectInput("yvar", "Choose y",choices = names(dataSource()), selected = names(dataSource())[2])})
output$idvar2 <- renderUI({selectInput("idvar", "Choose id",choices = names(dataSource()), selected = names(dataSource())[3])})
my_subset_data <- reactive({
# Here check if the column names correspond to the dataset
if(any(input$xvar %in% names(dataSource())) & any(input$yvar %in% names(dataSource())))
{
df <- subset(dataSource(), select = c(input$xvar, input$yvar))
names(df) <- c("x","y")
return(df)
}
})
observe({
test <- my_subset_data()
# Test for null as ggvis will evaluate this way earlier when the my_subset_data is NULL
if(!is.null(test)){
test %>% ggvis(~x, ~y) %>% layer_points() %>% bind_shiny("yup")
}
})
})
shinyApp(ui = ui, server = server)
Output 1 for rocks
Output 2 for mtcars

Resources