I have this working app: It is a follow-up question of some previous questions:
library(shiny)
library(vtree)
df <- tibble(A = c(rep("nature", 18), rep("not nature", 9)),
B = rep(c("animal", "plant", "machine"), each=9),
C = c(rep(c("dog", "cat", 'mouse'), 3),
rep(c("tree", "flower", "grass"), 3),
rep(c("car", "plane", "train"), 3)
)
)
# Define UI ----
ui <- pageWithSidebar(
# App title ----
headerPanel("my app"),
# Sidebar panel for inputs ----
sidebarPanel(
selectizeInput("levels", label = "Levels", choices = NULL, multiple = TRUE),
selectizeInput("valuesA", label= "Values_A", choices = NULL, multiple=TRUE),
selectizeInput("valuesB", label= "Values_B", choices = NULL, multiple=TRUE),
selectizeInput("valuesC", label= "Values_C", choices = NULL, multiple=TRUE),
),
# Main panel for displaying outputs ----
mainPanel(
vtreeOutput("VTREE")
)
)
# Define server logic to plot ----
server <- function(input, output,session) {
df <- reactiveVal(df)
vector <- c("A","B", "C")
observe({
updateSelectizeInput(session, "levels", choices = colnames(df()[vector]), selected = NULL)
updateSelectizeInput(session, "valuesA", choices = unique(df()$A))
updateSelectizeInput(session, "valuesB", choices = unique(df()$B))
updateSelectizeInput(session, "valuesC", choices = unique(df()$C))
})
output[["VTREE"]] <- renderVtree({
vtree(df(), c(input$levels),
sameline = TRUE,
keep=list(A=input$valuesA,
B = input$valuesB,
C = input$valuesC),
pngknit=FALSE,
horiz=TRUE,height=450,width=850)
})
}
shinyApp(ui, server)
I want to control the selectizeInput fields in that way that they dependent on each other:
Let me explain:
Scenario 1:
If Levels == A the user should be able to select from Values_A, not Values_B and not Values_C.
Scenario 2:
If Levels==A and Values_A == nature then in Values_B only animal and plant should be visible to select and not machine because machine is not nature.
Scenario 3:
If Levels == A and Values_A == nature and Values_B == animal then in Values_C only dog cat mouse should be visible:
Hi I think this does what you are looking for
library(shiny)
library(vtree)
library(dplyr)
df <- tibble(A = c(rep("nature", 18), rep("not nature", 9)),
B = rep(c("animal", "plant", "machine"), each=9),
C = c(rep(c("dog", "cat", 'mouse'), 3),
rep(c("tree", "flower", "grass"), 3),
rep(c("car", "plane", "train"), 3)
)
)
# Define UI ----
ui <- pageWithSidebar(
# App title ----
headerPanel("my app"),
# Sidebar panel for inputs ----
sidebarPanel(
selectizeInput("levels", label = "Levels", choices = NULL, multiple = TRUE),
selectizeInput("valuesA", label= "Values_A", choices = NULL, multiple=TRUE),
selectizeInput("valuesB", label= "Values_B", choices = NULL, multiple=TRUE),
selectizeInput("valuesC", label= "Values_C", choices = NULL, multiple=TRUE),
),
# Main panel for displaying outputs ----
mainPanel(
vtreeOutput("VTREE")
)
)
# Define server logic to plot ----
server <- function(input, output,session) {
df_A <- reactive({
filtered_df <- df
if(!is.null(input$valuesA)){
filtered_df <- filtered_df %>%
filter(A %in% input$valuesA)
}
filtered_df
})
df_B <- reactive({
if(!is.null(input$valuesB)){
filtered_df <- df_A() %>%
filter(B %in% input$valuesB)
} else {
df_A()
}
})
df_C <- reactive({
if(!is.null(input$valuesC)){
df_B() %>%
filter(C %in% input$valuesC)
} else {
df_B()
}
})
vector <- c("A","B", "C")
observe({
# browser()
updateSelectizeInput(session, "levels", choices = colnames(df[vector]), selected = input$levels)
updateSelectizeInput(session, "valuesA", choices = unique(df$A), selected = input$valuesA)
updateSelectizeInput(session, "valuesB", choices = unique(df_A()$B), selected = input$valuesB)
updateSelectizeInput(session, "valuesC", choices = unique(df_B()$C), selected = input$valuesC)
})
output[["VTREE"]] <- renderVtree({
vtree(df_C(), c(input$levels),
sameline = TRUE,
keep=list(A=input$valuesA,
B = input$valuesB,
C = input$valuesC),
pngknit=FALSE,
horiz=TRUE,height=450,width=850)
})
}
shinyApp(ui, server)
Hope this helps,
Bertil
Related
I have a set of inputs inside bs_accordion and would like to output a plot based on the selected inputs and active/expanded panel, but I'm not sure how to link the selected input based on this active/expanded panel. Is there a way to know which panel is active? My code is below and thank you in advance.
library(shiny)
library(bsplus)
library(shinyjs)
month_data <- data.frame(Region = c(rep("Region M1", 20), rep("Region M2", 20)),
Value = runif(40))
day_data <- data.frame(Region = c(rep("Region D3", 20), rep("Region D4", 20)),
Value = runif(40))
m1 <- selectInput(inputId = "in_month_region", label = "Region", choices = c("Region M1", "Region M2"))
d1 <- selectInput(inputId = "in_day_region", label = "Region", choices = c("Region D3", "Region D4"))
ui <- fluidPage(
useShinyjs(),
actionButton(inputId = "toggle_menu", label = "Options"),
br(),
sidebarLayout(
div(id = "Sidebar",
sidebarPanel(width = 3,
bs_accordion(id = "input_panel") %>%
bs_set_opts(panel_type = "success", use_heading_link = TRUE) %>%
bs_append(title = "Monthly",
content = m1) %>%
bs_append(title = "Daily",
content = d1))),
mainPanel(plotOutput("myplot"))
)
)
server <- function(input, output, session){
observeEvent(input$toggle_menu, {
shinyjs::toggle(id = "Sidebar")
})
get_data <- reactive({
if(!input$in_month_region %in% c(NULL, "")){
a <- subset(month_data, Region %in% input$in_month_region)
} else if(!input$in_day_region %in% c(NULL, "")){
a <- subset(day_dat, Region %in% input$in_day_region)
}
return(a)
})
output$myplot <- renderPlot({
mydat <- get_data()
plot(mydat$Value, main = unique(mydat$Region))
})
}
shinyApp(ui, server)
I'm trying to build a checklist that will show me different parts of my data in Rstudio using Shiny.
For example:
If I check question A:
Row 1:2 should show in my table
If I check question B while A is still checked:
I want to see row 1:2 & 5.
If I uncheck question B but check question C while A is still checked:
I want to see row 1:2 & 3:4
I made 2 versions but I'm stuck on both
Version 1 (were I'm having trouble with the if statements in the server):
if (interactive()) {
library(shiny)
library(readxl)
Sheet2 <- read_excel("Sheet2.xlsx")
Sheet3 <- read_excel("Sheet3.xlsx")
Sheet4 <- read_excel("Sheet4.xlsx")
ui <- fluidPage(
title = "Checklist",
sidebarLayout(
sidebarPanel(
checkboxInput(inputId = "A",
label = strong("A"),
value = FALSE),
conditionalPanel(condition = "input.A == true",
checkboxInput(inputId = "B",
label = strong("B"),
value = FALSE)),
checkboxInput(inputId = "C",
label = strong("C"),
value = FALSE)
),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Sheet2", DT::dataTableOutput("mytable1")),
tabPanel("Sheet3", DT::dataTableOutput("mytable2")),
tabPanel("Sheet4", DT::dataTableOutput("mytable3"))
)
)
)
)
server <- function(input, output) {
output$mytable1 <-
DT::renderDataTable({
if (input$A){
DT::datatable(Sheet2[1:2,])}
if (input$C){
DT::datatable(Sheet2[3:4,])}
if (input$B){
DT::datatable(Sheet2[5,])
}
})
output$mytable3 <-
DT::renderDataTable({if ((input$A)){
DT::datatable(Sheet3[3:4,])}
})
}
shinyApp(ui, server)
}
And version 2 (were i cant add multiple rows to my groupinput):
if (interactive()) {
library(shiny)
library(readxl)
Sheet2 <- read_excel("Sheet2.xlsx")
Sheet3 <- read_excel("Sheet3.xlsx")
Sheet4 <- read_excel("Sheet4.xlsx")
B3 <- 3:4
ui2 <- fluidPage(
title = "M&A Checklist",
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Sheet1", checkboxGroupInput(inputId = "show_vars",
label = "Questions:",
choiceNames = c("AAAAAAAAAA","BBBBBBBBBB","CCCCCCCCCCC"),
choiceValues = c("1","B3","5") )),
tabPanel("Sheet2", DT::dataTableOutput("mytable1")),
tabPanel("Sheet3", DT::dataTableOutput("mytable2")),
tabPanel("Sheet4", DT::dataTableOutput("mytable3"))
)
)
)
server2 <- function(input, output) {
# choose columns to display
output$mytable1 <- DT::renderDataTable({
DT::datatable(Sheet2[input$show_vars,])
})
# sorted columns are colored now because CSS are attached to them
output$mytable2 <- DT::renderDataTable({
DT::datatable(Sheet3[input$show_vars,])
})
# customize the length drop-down menu; display 5 rows per page by default
output$mytable3 <- DT::renderDataTable({
DT::datatable(Sheet4[input$show_vars,] )
})
}
shinyApp(ui2, server2)
}
Any suggestions, on how this can be done efficiently?
One way to approach this, is to create an empty vector that will contain the rows of data to filter your data on. Then, for each if statement, you can add the additional rows to this vector.
This example is based on your first version. Let me know if this achieves what you need.
library(shiny)
library(DT)
df <- data.frame(
a = 1:5,
b = 6:10
)
Sheet2 <- Sheet3 <- Sheet4 <- df
ui <- fluidPage(
title = "Checklist",
sidebarLayout(
sidebarPanel(
checkboxInput(inputId = "A",
label = strong("A"),
value = FALSE),
conditionalPanel(condition = "input.A == true",
checkboxInput(inputId = "B",
label = strong("B"),
value = FALSE)),
checkboxInput(inputId = "C",
label = strong("C"),
value = FALSE)
),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("Sheet2", DT::dataTableOutput("mytable1")),
tabPanel("Sheet3", DT::dataTableOutput("mytable2")),
tabPanel("Sheet4", DT::dataTableOutput("mytable3"))
)
)
)
)
server <- function(input, output) {
selected_rows <- reactive({
my_rows <- c()
if (input$A) {
my_rows <- c(my_rows, 1:2)
}
if (input$C) {
my_rows <- c(my_rows, 3:4)
}
if (input$B) {
my_rows <- c(my_rows, 5)
}
return(my_rows)
})
output$mytable1 <-
DT::renderDataTable({
DT::datatable(Sheet2[selected_rows(),])
})
output$mytable2 <-
DT::renderDataTable({
DT::datatable(Sheet3[selected_rows(),])
})
output$mytable3 <-
DT::renderDataTable({
DT::datatable(Sheet4[selected_rows(),])
})
}
shinyApp(ui, server)
I am trying to build a 'data explorer' shiny app which contains DataTables, ggplot2 graphs and wilcox.test results. I can't seem to make the wilcox.test to work though.
Outside the shiny app, things work as it should:
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
wilcox.test(dat$s ~ dat$outcome)
Results:
Wilcoxon rank sum test
data: dat$s by dat$outcome
W = 25, p-value = 0.3301
alternative hypothesis: true location shift is not equal to 0
Within the shiny app, the code below gives an 'Error: grouping factor > must have exactly 2 levels'. (graphs & tables work fine; I have omitted these for clarity).
library(shiny)
library(dplyr)
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
ui <- navbarPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("s"="s", "t"="t"),
selected = "s"),
selectInput(inputId = "z",
label = "Color by:",
choices = c("outcome", "cntr"),
selected = "outcome")
),
mainPanel(
tabsetPanel(id="tabspanel", type = "tabs",
tabPanel(title = "Wilcox"),
h4(textOutput(outputId = "p")))
)
)
)
server <- function(input, output, session) {
df <- reactive({
data.frame(input$y, input$z)
})
output$p <- renderText({
wilcox.test(df()[,1] ~ df()[,2])
})
}
shinyApp(ui=ui, server=server)
If the code is rewritten:
wilcox.test(dat$s, dat$outcome)
then the error is 'Error: 'x' must be numeric'.
Can someone help?
The issue you are having is that the line
data.frame(input$y, input$z)
gets translated to something like
data.frame("s", "outcome")
which can't be reasonably handeled by wicox.text. You should use the following instead
data.frame(dat[[input$y]], dat[[input$z]])
There were also some other minor issues. See the code code below for a full fix.
library(shiny)
library(dplyr)
dat <- data.frame(outcome=sample(c("died","survived",NA), 20, TRUE),
cntr=sample(c("hospa","hospb"), 20, TRUE),
s=rnorm(20),
t=rnorm(20), stringsAsFactors=FALSE)
ui <- navbarPage(
sidebarLayout(
sidebarPanel(
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("s"="s", "t"="t"),
selected = "s"),
selectInput(inputId = "z",
label = "Color by:",
choices = c("outcome", "cntr"),
selected = "outcome")
),
mainPanel(
tabsetPanel(id="tabspanel", type = "tabs",
tabPanel(title = "Wilcox",
verbatimTextOutput(outputId = "p")))
)
)
)
server <- function(input, output, session) {
df <- reactive({
data.frame(dat[[input$y]], dat[[input$z]])
})
output$p <- renderPrint({
wilcox.test(df()[,1] ~ df()[,2])
})
}
shinyApp(ui=ui, server=server)
Gregor's guess is quite spot on; below snippet from the server codes:
dat_subset <- reactive({
req(input$selected_type)
filter(dat, outcome %in% input$selected_type)
})
output$scatterplot <- renderPlot({
ggplot(data = dat_subset(), aes_string(x = input$x, y = input$y, color = input$z)) + geom_boxplot() + labs()
})
output$nsdtable <- DT::renderDataTable({
DT::datatable(data = dat_subset()[, 1:4],
options = list(pageLength = 10),
rownames = FALSE)
})
I am trying to create a shiny-app that load data-set, present the variable list and their classes and allow the user to modify the class of a selected variable. All the functions in the following code are working except to the last function in the server- observeEvent which not working when trying to modify the variable class. Any suggestions?
Thank you in advance,
Rami
`
rm(list = ls())
library(shiny)
library(shinydashboard)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Shiny Example"),
#--------------------------------------------------------------------
dashboardSidebar(
sidebarMenu(
menuItem("Data", tabName = "data", icon = icon("th"))
)
),
#--------------------------------------------------------------------
dashboardBody(
#--------------------------------------------------------------------
tabItem(tabName = "data",
fluidPage(
fluidRow(
box(
selectInput('dataset', 'Select Dataset', list(GermanCredit = "GermanCredit",
cars = "cars",
iris = "iris")),
title = "Datasets",width = 4, status = "primary",
checkboxInput("select_all", "Select All Variable", value = TRUE),
conditionalPanel(condition = "input.select_all == false",
uiOutput("show.var"))
),
box(
title = "Variable Summary", width = 4, status = "primary",
DT::dataTableOutput('summary.data')
),
box(
title = "Modify the Variable Class", width = 4, status = "primary",
radioButtons("choose_class", label = "Modify the Variable Class",
choices = list(Numeric = "numeric", Factor = "factor",
Character = "character"),
selected = "numeric"),
actionButton("var_modify", "Modify")
)
)
)
)
)
)
#--------------------------------------------------------------------
# Server Function
#--------------------------------------------------------------------
server <- function(input, output,session) {
#--------------------------------------------------------------------
# loading the data
get.df <- reactive({
if(input$dataset == "GermanCredit"){
data("GermanCredit")
GermanCredit
}else if(input$dataset == "cars"){
data(cars)
cars
}else if(input$dataset == "iris"){
data("iris")
iris
}
})
# Getting the list of variable from the loaded dataset
var_list <- reactive(names(get.df()))
# Choosing the variable - checkbox option
output$show.var <- renderUI({
checkboxGroupInput('show_var', 'Select Variables', var_list(), selected = var_list())
})
# Setting the data frame based on the variable selction
df <- reactive({
if(input$select_all){
df <- get.df()
} else if(!input$select_all){
df <- get.df()[, input$show_var, drop = FALSE]
}
return(df)
})
# create list of variables
col.name <- reactive({
d <- data.frame(names(df()), sapply(df(),class))
names(d) <- c("Name", "Class")
return(d)
})
# render the variable list into table
output$summary.data <- DT::renderDataTable(col.name(), server = FALSE, rownames = FALSE,
selection = list(selected = 1, mode = 'single'),
options = list(lengthMenu = c(5, 10, 15, 20), pageLength = 20, dom = 'p'))
# storing the selected variable from the variables list table
table.sel <- reactive({
df()[,which(colnames(df()) == col.name()[input$summary.data_rows_selected,1])]
})
# Trying to modify the variable class
observeEvent(input$var_modify,{
modify.row <- which(colnames(df()) == col.name()[input$summary.data_rows_selected,1])
if( input$choose_class == "numeric"){
df()[, modify.row] <- as.numeric(df()[, modify.row])
} else if( input$choose_class == "factor"){
df()[, modify.row] <- as.factor(df()[, modify.row])
} else if( input$choose_class == "character"){
df()[, modify.row] <- as.character(df()[, modify.row])
}
})
}
shinyApp(ui = ui, server = server)
`
I would use reactiveValues() instead.
library(shiny)
# Define UI for application that draws a histogram
ui <- shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("classType", "Class Type:", c("as.numeric", "as.character"))
),
mainPanel(
textOutput("class")
)
)
))
server <- shinyServer(function(input, output) {
global <- reactiveValues(sample = 1:9)
observe({
global$sample <- get(input$classType)(global$sample)
})
output$class <- renderText({
print(class(global$sample))
})
})
shinyApp(ui = ui, server = server)
In case you are interested:
Concerning your attempt: reactive() is a function and you called the output of the function by df()[, modify.row]. So in your code you try to change the output of the function, but that does not change the output of futures calls of that function.
Maybe it is easier to see in a simplified version:
mean(1:3) <- 1
The code can not change the mean function to output 1 in future. So thats what reactiveValues() help with :). Hope that helps!
The following data set is given (in reality much more cases):
data_test = data.frame(ID = c ("1","2","3","4","5"),
product = c("A","B","C","A","C"),
milieu = c("good","medium","bad","medium","bad"),
online = c(1,0,1,1,0),
ooh = c(0,1,0,1,1),
event = c(1,1,0,0,0))
Now I want to built a shiny app where someone can choose a milieu lets say "good" and a product "A" and all online which have "1" and the data table with these settings is given back. In the Example ID 1.
I tried the following
ui:
shinyUI(fluidPage(
titlePanel("product milieu"),
sidebarLayout(
sidebarPanel("select",
selectInput("select_milieu",
label = "Milieu",
choices = list("good",
"medium",
"bad")
),
selectInput("select_product",
label = "Product",
choices = list("A",
"B",
"C")
),
selectInput("select_online",
label = "Online",
choices = list(1,
0)
),
selectInput("select_ooh",
label = "ooh",
choices = list(1,
0)
),
selectInput("select_Event",
label = "Event",
choices = list(1,
0)
)
),
mainPanel("My table",
textOutput("output_milieu"),
textOutput("output_product"),
textOutput("output_event"),
textOutput("output_online"),
textOutput("output_ooh"),
tableOutput("gapminder_table")
)
)
))
server:
shinyServer(function(input, output) {
output$gapminder_table <- renderTable({
subset(data_test,
milieu == input$select_milieu & product == input$select_product &
online == input$select_online)
})
output$output_milieu <- renderText({
paste("milieu", input$select_milieu)
})
output$output_product <- renderText({
paste("product", input$select_product)
})
output$output_event <- renderText({
paste("Event", input$select_Event)
})
output$output_online <- renderText({
paste("Online", input$select_Online)
})
output$output_ooh <- renderText({
paste("out of Home", input$select_ooh)
})
})
My problem is now how to filter for "event" and "ooh". Does anyone has an advice?
Thanks in advance!
You can make this much simpler if you begin to explore the DT package for datatables with shiny. With this, you can just type in whatever filter criteria you like above the respective columns.
server.R
library(shiny)
library(DT)
data_test = data.frame(ID = c ("1","2","3","4","5"),
product = c("A","B","C","A","C"),
milieu = c("good","medium","bad","medium","bad"),
online = c(1,0,1,1,0),
ooh = c(0,1,0,1,1),
event = c(1,1,0,0,0))
shinyServer(function(input, output) {
output$gapminder_table <- renderDataTable({
data_test
},
filter = 'top',
rownames = FALSE)
})
ui.R
library(shiny)
library(DT)
shinyUI(fluidPage(
titlePanel("product milieu"),
sidebarLayout(
sidebarPanel("Place for other criteria"
),
mainPanel("My table",
dataTableOutput("gapminder_table")
)
)
))