Shiny R: Modifying the variable class - r

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!

Related

How to hide multiple shiny ui by condition, and how to use session$userData?

I am a beginer of shiny, and I am building a shiny app using win10 system, rstudio, and shiny version 1.7.1. I would like to make it more user oriented. It means that other parts of the application will be hid unless user uploads correct data. After many attempts, I decided to use session$userData and shinyjs::toggle to develop this app. But I am confused by session$userData. In the beginning, by reading the official documentation, I think it just like the global environment of r. But obviously not. So I just want to know how to use it correctly, or how to realize the features I want. There are three examples I had tried, they are for your reference.
Please note that the third example is almost what I want, but I don't think it's elegant since the continue button is somewhat redundant.
Examples 1:
I would like to check whether there is data input or whether the input data is a csv format, if true, show the data, and if not, the rest part of the app will be hid. In this case you can see, although you data have passed the check, the tablepanel b will still show nothing, unless before input data you have clicked tablepanel b, or unless after data checking you clicked button go again.
##### 1. packages #####
library(shiny)
library(shinyjs)
##### 2. ui #####
ui <- fluidPage(
useShinyjs(),
tabsetPanel(
tabPanel("a",
sidebarLayout(
sidebarPanel(uiOutput("ui_p1_sidebar1"), uiOutput("ui_p1_sidebar2")),
mainPanel(uiOutput("ui_p1_main"))
)),
tabPanel("b",
sidebarLayout(
sidebarPanel(uiOutput("ui_p2_sidebar")),
mainPanel(uiOutput("ui_p2_main"))
))
)
)
##### 3. server #####
server <- function(input, output, session) {
output$ui_p1_sidebar1 <- renderUI({
fileInput(inputId = "p1s_inputdata",
label = "Input data",
multiple = FALSE,
accept = ".csv")
})
output$ui_p1_sidebar2 <- renderUI({
shiny::actionButton(inputId = "p1s_go",
label = "go",
icon = icon("play"))
})
observeEvent(input$p1s_go,{
isolate({
data <- input$p1s_inputdata
})
output$ui_p1_main <- renderUI({
tagList(
h3("Data check: "),
verbatimTextOutput(outputId = "p1m_datacheck", placeholder = T),
h3("Data show: "),
verbatimTextOutput(outputId = "p1m_datashow", placeholder = T),
)
})
output$p1m_datacheck <- renderPrint({
# data check part, the result of checking is stored by session$userData$sig
if(is.null(data)){
cat("There is no data input! \n")
session$userData$sig <- F
} else{
dataExt <- tools::file_ext(data$name)
if(dataExt != "csv"){
cat("Please input csv data! \n")
session$userData$sig <- F
} else{
cat("Data have passed the check!")
session$userData$data <- read.csv(data$datapath)
session$userData$sig <- T
}
}
})
output$p1m_datashow <- renderPrint({
if(session$userData$sig){
print(session$userData$data)
} else{
cat("Please check the data!")
}
})
output$ui_p2_sidebar <- renderUI({
radioButtons("aaa", "aaa", choices = c("a", "b", "c"))
})
output$ui_p2_main <- renderUI({
verbatimTextOutput(outputId = "p2m_print", placeholder = T)
})
output$p2m_print <- renderPrint({print(letters[1:10])})
observe({
toggle(id = "ui_p2_sidebar", condition = session$userData$sig)
toggle(id = "ui_p2_main", condition = session$userData$sig)
})
})
}
##### 4. app #####
shinyApp(ui = ui, server = server)
Example 2:
In this small case you can see, in a samle module, session$userData$... changed timely, but in another module, it will not change unless you click the button again. It that means session$userData$... could have different values at the same time?
##### 1. packages #####
library(shiny)
##### 2. ui #####
ui <- fluidPage(
sidebarLayout(
sidebarPanel(uiOutput("ui_sidebar")),
mainPanel(uiOutput("ui_main1"), uiOutput("ui_main2"))
)
)
##### 3. server #####
server <- function(input, output, session) {
output$ui_sidebar <- renderUI({
tagList(
radioButtons("s_letter", "letters", choices = c("a", "b", "c")),
shiny::actionButton(inputId = "go1",
label = "GO1",
icon = icon("play"))
)
})
observeEvent(input$go1, {
output$ui_main1 <- renderUI({
tagList(
h3("module 1: shared value changes timely."),
verbatimTextOutput(outputId = "m1", placeholder = T),
h3("module 2: shared value changes by button."),
verbatimTextOutput(outputId = "m2", placeholder = T)
)
})
output$m1 <- renderPrint({
out <- switch (input$s_letter,
"a" = "choose a",
"b" = "choose b",
"c" = "choose c")
session$userData$sharedout <- out
cat("out: \n")
print(out)
cat("sharedout: \n")
print(session$userData$sharedout)
})
output$m2 <- renderPrint({
cat("sharedout: \n")
print(session$userData$sharedout)
})
})
}
##### 4. app #####
shinyApp(ui = ui, server = server)
Example 3: I also tried other solutions. There is a modification of example 1, I have added a continue button to realize my thought. It works well, but I hope the hidden action is based on conditions rather than events. So how to remove the button and let the rest part displayed automatically if data passed checking?
##### 1. packages #####
library(shiny)
##### 2. ui #####
ui <- fluidPage(
tabsetPanel(
tabPanel("a",
sidebarLayout(
sidebarPanel(uiOutput("ui_p1_sidebar1"), uiOutput("ui_p1_sidebar2")),
mainPanel(uiOutput("ui_p1_main"))
)),
tabPanel("b",
sidebarLayout(
sidebarPanel(uiOutput("ui_p2_sidebar")),
mainPanel(uiOutput("ui_p2_main"))
))
)
)
##### 3. server #####
server <- function(input, output, session) {
output$ui_p1_sidebar1 <- renderUI({
fileInput(inputId = "p1s_inputdata",
label = "Input data",
multiple = FALSE,
accept = ".csv")
})
output$ui_p1_sidebar2 <- renderUI({
shiny::actionButton(inputId = "p1s_go",
label = "go",
icon = icon("play"))
})
observeEvent(input$p1s_go,{
isolate({
data <- input$p1s_inputdata
})
output$ui_p1_main <- renderUI({
tagList(
h3("Data check: "),
verbatimTextOutput(outputId = "p1m_datacheck", placeholder = T),
uiOutput("ispass"),
h3("Data show: "),
verbatimTextOutput(outputId = "p1m_datashow", placeholder = T)
)
})
output$p1m_datacheck <- renderPrint({
if(is.null(data)){
cat("There is no data input! \n")
session$userData$sig <- F
} else{
dataExt <- tools::file_ext(data$name)
if(dataExt != "csv"){
cat("Please input csv data! \n")
session$userData$sig <- F
} else{
cat("Data have passed the check!")
session$userData$data <- read.csv(data$datapath)
session$userData$sig <- T
}
}
})
output$ispass <- renderUI({
if(isFALSE(session$userData$sig)){
return()
} else{
shiny::actionButton(inputId = "ispass",
label = "continue",
icon = icon("play"))
}
})
})
observeEvent(input$ispass,{
output$p1m_datashow <- renderPrint({
if(session$userData$sig){
print(session$userData$data)
} else{
cat("Please check the data!")
}
})
output$ui_p2_sidebar <- renderUI({
radioButtons("aaa", "aaa", choices = c("a", "b", "c"))
})
output$ui_p2_main <- renderUI({
verbatimTextOutput(outputId = "p2m_print", placeholder = T)
})
output$p2m_print <- renderPrint({print(letters[1:10])})
})
}
##### 4. app #####
shinyApp(ui = ui, server = server)
I hope the following refactoring will help and does what you want.
An essential tool for hiding,showing and updating UI elements can be the renderUI, but often this is overkill because of rerenderings.
But I would suggest using the shinyjs-package which gives you functions like shinyjs::show and shinyjs::hide for showing and hiding. For updating UI-elements, there are functions like shiny::updateActionButton,shiny::updateCheckboxInput, shiny::updateRadioButtons, ....
It is (always) useful to give your UI-elements IDs, like the tabsetPanel.
Moreover, a nice tool too is shiny::conditionalPanel, but you will dive into all this stuff when programming more apps. :)
##### 1. packages #####
library(shiny)
myapp <- function() {
##### 2. ui #####
ui <- fluidPage(
tabsetPanel(
tabPanel("a",
sidebarLayout(
sidebarPanel(
fileInput(inputId = "p1s_inputdata", label = "Input data", multiple = FALSE, accept = ".csv")
),
mainPanel(uiOutput("ui_p1_main"))
)),
tabPanel("b",
sidebarLayout(
sidebarPanel(radioButtons("aaa", "aaa", choices = c("some", "placeholder", "stuff"))),
mainPanel(verbatimTextOutput(outputId = "p2m_print", placeholder = T))
)),
id = "TABSETPANEL"
)
)
##### 3. server #####
server <- function(input, output, session) {
shiny::hideTab(inputId = "TABSETPANEL", target = "b", session = session)
observeEvent(input$p1s_inputdata, {
data <- input$p1s_inputdata
dataCheckText <- NULL
if(is.null(data)){
dataCheckText <- "There is no data input!"
session$userData$sig <- F
} else{
dataExt <- tools::file_ext(data$name)
if(dataExt != "csv"){
dataCheckText <- "Please input csv data!"
session$userData$sig <- F
} else{
dataCheckText <- "Data have passed the check!"
session$userData$data <- read.csv(data$datapath)
session$userData$sig <- T
}
}
output$p1m_datacheck <- renderPrint(dataCheckText)
if(session$userData$sig) shiny::showTab(inputId = "TABSETPANEL", target = "b", session = session)
else shiny::hideTab(inputId = "TABSETPANEL", target = "b", session = session)
main1Taglist <- tagList(
h3("Data check: "),
verbatimTextOutput(outputId = "p1m_datacheck", placeholder = T)
)
if(session$userData$sig) {
shiny::showTab(inputId = "TABSETPANEL", target = "b", session = session)
output$p1m_datashow <- renderPrint({
print(session$userData$data)
})
main1Taglist <- c(main1Taglist, tagList(
h3("Data show: "),
verbatimTextOutput(outputId = "p1m_datashow", placeholder = T)
))
#Update stuff in panel b according to the new data
updateRadioButtons(session = session, inputId = "aaa", choices = names(session$userData$data))
output$p2m_print <- renderPrint({print(letters[1:10])})
}
output$ui_p1_main <- renderUI(main1Taglist)
})
}
##### 4. app #####
shinyApp(ui = ui, server = server)
}
myapp()
You're somewhat on the right track. Try something like this:
observeEvent(input$go1, {
# Perform data validation here.
# This would look similar to what you have inside output$p1m_datacheck <- renderPrint({})
# If data file is no good, do nothing, exit this function: return()
# Else, data file is good, continue
# Do your output$* <- render*() functions here
})
You don't need to isolate() inside the handlerExpr of observeEvent(). It will already be executed in an isolate() scope.

How to make an interactive checklist in Rstudio Shiny

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)

How to add comment to a reactive data table in shiny

This question is an extension of the question I posted: this question
I created a dataframe with 3 columns: num, id and val. I want my shiny app to do the following:
a dataframe dat is filtered by num column
select an value from id column from dat (selectInput).
add text comment in a text box (textInput)
click on an action button
A new column called comment is created in the data table, text comments are added to the comment column in the row where id equals the value selected.
The code is below. I cannot figure out why it's not working.
Thank a lot in advance!
library(shiny)
library(DT)
dat = data.frame(num=rep(1:2, each=5), id=rep(LETTERS[1:5],2), val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df = reactive ({ dat %>% filter(num %in% input$selectNum) })
df_current <- reactiveVal(df())
observeEvent(input$button, {
req(df_current())
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
shinyApp(ui=ui, server=server)
Instead of using a reactive/eventReactive statement for df, it might be more natural to keep track of previously inputted comments in the Comment column using a reactiveVal object for df. See also the responses to this question: R Shiny: reactiveValues vs reactive. If you prefer to use a reactive/eventReactive statement for df it is probably better to work with a separate object to store previous input comments (instead of incorporating it into the reactive statement for df).
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10)),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current <- reactiveVal(dat)
observeEvent(input$button, {
req(df_current(), input$selectID %in% dat$id)
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
shinyApp(ui=ui, server=server)
Edit: below an edited server function that using df_current <- reactive({...}) instead of df_current <- reactiveVal({...}) and defining a separate reactiveVal object to keep track of the comments.
server <- function(input, output, session) {
## initialize separate reactive object for comments
df_comments <- reactiveVal({
data.frame(
id = character(0),
Comment = character(0),
stringsAsFactors = FALSE
)
})
## reactive object df
df_current <- reactive({
## reactivity that df depends on
## currently df = dat does not change
df <- dat
## merge with current comments
if(nrow(df_comments()) > 0)
df <- merge(df, df_comments(), by = "id", all.x = TRUE)
return(df)
})
observeEvent(input$button, {
req(input$selectID)
## update df_comments by adding comments
df_comments_new <- rbind(df_comments(),
data.frame(id = input$selectID, Comment = input$comment)
)
## if duplicated id's keep only most recent rows
df_comments_new <- df_comments_new[!duplicated(df_comments_new$id, fromLast = TRUE), , drop = FALSE]
df_comments(df_comments_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
There you have got a working example.
I think the thing is that you are trying to update a value through an observeEvent which is not good according to the documentation. ?observeEvent
Use observeEvent whenever you want to perform an action in response to an event. (Note that "recalculate a value" does not generally count as performing an action–see eventReactive for that.)
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current = reactive({
df = dat %>% filter(num %in% input$selectNum)
if(input$button != 0) {
input$button
df[df$id %in% input$selectID, "Comment"] <- isolate(input$comment)
}
return(df)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
}
shinyApp(ui=ui, server=server)
So you can either go with your reactive value or using eventReactive as stated in the doc.

Filter a table in Shiny

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")
)
)
))

R Shiny Make slider value dynamic

I've got a dropdown selector and a slider scale. I want to render a plot with the drop down selector being the source of data. - I've got this part working
I simply want the slider's max value to change based on which dataset is selected.
Any suggestions?
server.R
library(shiny)
shinyServer(function(input, output) {
source("profile_plot.R")
load("test.Rdata")
output$distPlot <- renderPlot({
if(input$selection == "raw") {
plot_data <- as.matrix(obatch[1:input$probes,1:36])
} else if(input$selection == "normalised") {
plot_data <- as.matrix(eset.spike[1:input$probes,1:36])
}
plot_profile(plot_data, treatments = treatment, sep = TRUE)
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Profile Plot"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("selection", "Choose a dataset:",
choices=c('raw', 'normalised')),
hr(),
sliderInput("probes",
"Number of probes:",
min = 2,
max = 3540,
value = 10)
),
mainPanel(
plotOutput("distPlot")
)
)
))
As #Edik noted the best way to do this would be to use an update.. type function. It looks like updateSliderInput doesnt allow control of the range so you can try using renderUI on the server side:
library(shiny)
runApp(list(
ui = bootstrapPage(
numericInput('n', 'Maximum of slider', 100),
uiOutput("slider"),
textOutput("test")
),
server = function(input, output) {
output$slider <- renderUI({
sliderInput("myslider", "Slider text", 1,
max(input$n, isolate(input$myslider)), 21)
})
output$test <- renderText({input$myslider})
}
))
Hopefully this post will help someone learning Shiny:
The information in the answers is useful conceptually and mechanically, but doesn't help the overall question.
So the most useful feature I found in the UI API is conditionalPanel() here
This means I could create a slider function for each dataset loaded and get the max value by loading in the data initially in global.R. For those that don't know, objects loaded into global.R can be referenced from ui.R.
global.R - Loads in a ggplo2 method and test data objects (eset.spike & obatch)
source("profile_plot.R")
load("test.Rdata")
server.R -
library(shiny)
library(shinyIncubator)
shinyServer(function(input, output) {
values <- reactiveValues()
datasetInput <- reactive({
switch(input$dataset,
"Raw Data" = obatch,
"Normalised Data - Pre QC" = eset.spike)
})
sepInput <- reactive({
switch(input$sep,
"Yes" = TRUE,
"No" = FALSE)
})
rangeInput <- reactive({
df <- datasetInput()
values$range <- length(df[,1])
if(input$unit == "Percentile") {
values$first <- ceiling((values$range/100) * input$percentile[1])
values$last <- ceiling((values$range/100) * input$percentile[2])
} else {
values$first <- 1
values$last <- input$probes
}
})
plotInput <- reactive({
df <- datasetInput()
enable <- sepInput()
rangeInput()
p <- plot_profile(df[values$first:values$last,],
treatments=treatment,
sep=enable)
})
output$plot <- renderPlot({
print(plotInput())
})
output$downloadData <- downloadHandler(
filename = function() { paste(input$dataset, '_Data.csv', sep='') },
content = function(file) {
write.csv(datasetInput(), file)
}
)
output$downloadRangeData <- downloadHandler(
filename = function() { paste(input$dataset, '_', values$first, '_', values$last, '_Range.csv', sep='') },
content = function(file) {
write.csv(datasetInput()[values$first:values$last,], file)
}
)
output$downloadPlot <- downloadHandler(
filename = function() { paste(input$dataset, '_ProfilePlot.png', sep='') },
content = function(file) {
png(file)
print(plotInput())
dev.off()
}
)
})
ui.R
library(shiny)
library(shinyIncubator)
shinyUI(pageWithSidebar(
headerPanel('Profile Plot'),
sidebarPanel(
selectInput("dataset", "Choose a dataset:",
choices = c("Raw Data", "Normalised Data - Pre QC")),
selectInput("sep", "Separate by Treatment?:",
choices = c("Yes", "No")),
selectInput("unit", "Unit:",
choices = c("Percentile", "Absolute")),
wellPanel(
conditionalPanel(
condition = "input.unit == 'Percentile'",
sliderInput("percentile",
label = "Percentile Range:",
min = 1, max = 100, value = c(1, 5))
),
conditionalPanel(
condition = "input.unit == 'Absolute'",
conditionalPanel(
condition = "input.dataset == 'Normalised Data - Pre QC'",
sliderInput("probes",
"Probes:",
min = 1,
max = length(eset.spike[,1]),
value = 30)
),
conditionalPanel(
condition = "input.dataset == 'Raw Data'",
sliderInput("probes",
"Probes:",
min = 1,
max = length(obatch[,1]),
value = 30)
)
)
)
),
mainPanel(
plotOutput('plot'),
wellPanel(
downloadButton('downloadData', 'Download Data Set'),
downloadButton('downloadRangeData', 'Download Current Range'),
downloadButton('downloadPlot', 'Download Plot')
)
)
))
I think you're looking for the updateSliderInput function that allows you to programmatically update a shiny input:
http://shiny.rstudio.com/reference/shiny/latest/updateSliderInput.html. There are similar functions for other inputs as well.
observe({
x.dataset.selection = input$selection
if (x.dataset.selection == "raw") {
x.num.rows = nrow(obatch)
} else {
x.num.rows = nrow(eset.spike)
}
# Edit: Turns out updateSliderInput can't do this,
# but using a numericInput with
# updateNumericInput should do the trick.
updateSliderInput(session, "probes",
label = paste("Slider label", x.dataset.selection),
value = c(1,x.num.rows))
})
Another alternative can be applying a renderUI approach like it is described in one of the shiny gallery examples:
http://shiny.rstudio.com/gallery/dynamic-ui.html

Resources