I am trying to understand the reactive part in R shiny. In that process I am trying to update an output table based on the input change while selecting values from the age drop down. It seems to do it by the first value but when I change any value from the age drop down it won't update my table. The input I am using is chooseage. Below is the code which I am using.
library(shiny)
library(shinydashboard)
library(shinyBS)
library(knitr)
library(kableExtra)
library(shiny)
library(shinythemes)
ui <- dashboardPage(
dashboardHeader(disable = F, title = "PATH Study"),
dashboardSidebar(sidebarMenu(
menuItem(
"Population Filter",
uiOutput("choose_age")
)
)),
dashboardBody(box(
width = 12,
tabBox(
width = 12,
id = "tabBox_next_previous",
tabPanel("Initiation",
fluidRow(
box(
width = 5,
solidHeader = TRUE,
status = "primary",
tableOutput("smoke"),
collapsible = F
)
))
),
uiOutput("Next_Previous")
))
)
server <- function(input, output, session) {
# Drop-down selection box for which Age bracket to be selected
age_levels <- c("18 to 24 years old","25 to 34 years old","35 to 44 years old")
output$choose_age <- renderUI({
selectInput("selected_age", "Age", as.list(age_levels))
})
myData <- reactive({
with_demo_vars %>%
filter(age == input$choose_age) %>%
pct_ever_user(type = "SM")
})
output$smoke <-
renderTable({
head(myData())
})
}
shinyApp(ui = ui, server = server)
Here is a quick prototype for your task
library(shiny)
library(tidyverse)
library(DT)
# 1. Dataset
df_demo <- data.frame(
age = c(16, 17, 18, 19, 20),
name = c("Peter", "Mary", "Mike", "Nick", "Phillipe"))
# 2. Server
server <- function(input, output, session) {
# 1. UI element 'Age'
output$ui_select_age <- renderUI({
selectInput("si_age", "Age", df_demo$age)
})
# 2. Reactive data set
df_data <- reactive({
# 1. Read UI element
age_selected <- input$si_age
# 2. Filter data
df <- df_demo %>%
filter(age == age_selected)
# 3. Return result
df
})
# 3. Datatable
output$dt_table <- renderDataTable({
datatable(df_data())
})
}
# 3. UI
ui <- fluidPage(
fluidRow(uiOutput("ui_select_age")),
fluidRow(dataTableOutput("dt_table"))
)
# 4. Run app
shinyApp(ui = ui, server = server)
I think youre shinyApp is over-reactive, as all functions in the server are executed straight away, without waiting for any selected input. So either it will break down or behave weird. So you have to delay the reactivity with req(), validate() / need() or with any observeEvent or eventReactive() function.
Maybe this snippet might help you, although there would be several ways to achieve the desired behaviour.
library(shiny)
library(shinydashboard)
library(dplyr)
data(mtcars)
mtcars$age <- sample(x = c(10,20,30,40,50), size = nrow(mtcars), replace = T)
with_demo_vars <- mtcars
ui <- dashboardPage(
dashboardHeader(disable = F, title = "PATH Study"),
dashboardSidebar(sidebarMenu(
menuItem(text = "Population Filter",
uiOutput("choose_age")
)
)
),
dashboardBody(
tableOutput("smoke")
)
)
server <- function(input, output, session) {
output$choose_age <- renderUI({
selectInput("selected_age", "Age", with_demo_vars$age)
})
myData <- reactive({
with_demo_vars %>%
dplyr::filter(age == input$selected_age)
})
output$smoke <- renderTable({
req(input$selected_age)
head(myData())
})
}
shinyApp(ui = ui, server = server)
Related
Hello and thanks for reading me. I am currently trying to make a simple app in shiny that allows you to filter a dataframe, but I would like the filter to update every time I press the button. It works the first time, but apparently afterwards the observeEvent stays activated and the information is filtered even if you don't press the button. Is there any way to avoid this?
The code is the following:
library(shiny)
library(dplyr)
library(shinyWidgets)
x <- tibble(
val1 = 1:5,
val2 = sample(letters,5)
)
shinyApp(
ui = fluidPage(
column(width = 3, pickerInput("filt", "filter",
choices = x$val1,
selected = x$val1,
multiple = TRUE
),
actionButton("ready", "filter data")
),
column(width = 6, textOutput("text"))
),
server = function(input, output, session){
observeEvent(input$ready,{
output$text <- renderText({
x <- x |>
filter(val1 %in% input$filt)
print(x$val2)
})
})
}
)
I think the problem is in this part:
observeEvent(input$ready,{
output$text <- renderText({
x <- x |>
filter(val1 %in% input$filt)
print(x$val2)
})
})
Thanks a lot for the help
Use the bindEvent function in shiny
library(shiny)
library(dplyr)
library(shinyWidgets)
x <- tibble(
val1 = 1:5,
val2 = sample(letters,5)
)
shinyApp(
ui = fluidPage(
column(width = 3, pickerInput("filt", "filter",
choices = x$val1,
selected = x$val1,
multiple = TRUE
),
actionButton("ready", "filter data")
),
column(width = 6, textOutput("text"))
),
server = function(input, output, session){
output$text <- renderText({
x <- x |>
filter(val1 %in% input$filt)
print(x$val1)
}) |>
bindEvent(input$ready)
}
)
Try putting it in an eventReactive() call instead of observeEvent(). Your server function would look like this instead:
server = function(input, output, session) {
filter_data <- eventReactive(input$ready, {
x <- x %>%
filter(val1 %in% input$filt)
})
output$text <- renderText({
filter_data()$val2
})
}
I am trying to create my first shiny app but I am facing a difficulty: in the reproducible example below I am creating a reactive pickerInput (i.e. only show brands proposing a cylindre equal to the input visitors select).
I then want that based on the combination input_cyl and picker_cny (remember that picker_cny depends on input_cyl) to display a table which shows the relevant data for the observation matching the combination input_cyl and picker_cny.
Thank you for your help!
df <- mtcars
df$brand <- rownames(mtcars)
df$brand <- gsub("([A-Za-z]+).*", "\\1", df$brand)
if (interactive()) {
library(shiny)
library(shinyWidgets)
library(shinythemes)
library(shinycssloaders)
# Define UI -----------------------------------------------
ui <- fluidPage(
# Application title
titlePanel("Reproducible Example"),
# Parameters
sidebarLayout(
sidebarPanel(
selectInput(inputId = "input_cyl", label = "Cyl",
choices = c("6", "4", "8")),
pickerInput(
inputId = "picker_cny",
label = "Select Company",
choices = paste0(unique(df$brand)),
options = list(`actions-box` = TRUE),
multiple = TRUE),
width = 2),
# Show Text
mainPanel(
tableOutput("table"),
width = 10)
))
# Define Server ------------------------------------------
server <- function(input, output, session) {
# Reactive pickerInput ---------------------------------
observeEvent(input$input_cyl, {
df_mod <- df[df$cyl == paste0(input$input_cyl), ]
# Method 1
disabled_choices <- !df$cyl %in% df_mod$cyl
updatePickerInput(session = session,
inputId = "picker_cny",
choices = paste0(unique(df$brand)),
choicesOpt = list(
disabled = disabled_choices,
style = ifelse(disabled_choices,
yes = "color: rgba(119, 119, 119, 0.5);",
no = "")
))
}, ignoreInit = TRUE)
output$table <- renderTable(df)
}
}
# Run the application
shinyApp(ui = ui, server = server)
You need a reactive that will handle the change in the input and subset the dataframe before giving it to the output table. For that, you just need to add this block to your server:
data <- reactive({
if (length(input$picker_cny) > 0)
df[df$brand %in% input$picker_cny,]
else
df
})
and update the output$table like this:
output$table <- renderTable(data())
Note: feel free to remove the if else in the reactive to get that:
data <- reactive({
df[df$brand %in% input$picker_cny,]
})
The only difference in that case is: would you show all or nothing when no input has been entered yet. That's a matter of taste.
I am new to r and shiny and suspect that I am stuck with a simple problem.
I want 2 infoboxes which show me in one the maximum amount over all categories and in the second infobox only the category with the most amount and its total amount.
I have tried a lot of things but nothing brought me success.
## app.R ##
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
uiOutput("info_box1"),
uiOutput("info_box2"),
uiOutput("rawdata")
)
)
set.seed(24)
mydf <- data.frame(Type = sample(LETTERS[1:5], 30, replace = TRUE),
Amount = sample(10:200, 30, replace = TRUE),
stringsAsFactors= FALSE, check.names = FALSE)
server <- function(input, output) {
output$info_box1 <- renderUI({
infoBox("Amount in Total here", input$ "???")
})
output$info_box2 <- renderUI({
infoBox("Class with the hightest amount and amount in total of that class", "input$ function needed?")
})
output$rawdata = renderTable({
mydf
})
}
# Run the application
shinyApp(ui = ui, server = server)
Could someone please show me how to do this?
Thanks a lot. Appreciate your help.
You should use approriate functions, see here : https://rstudio.github.io/shinydashboard/structure.html
app.R
library(shiny)
library(shinydashboard)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
infoBoxOutput("info_box1"),
infoBoxOutput("info_box2"),
tableOutput("rawdata")
)
)
set.seed(24)
mydf <- data.frame(Type = sample(LETTERS[1:5], 30, replace = TRUE),
Amount = sample(10:200, 30, replace = TRUE),
stringsAsFactors= FALSE, check.names = FALSE)
server <- function(input, output) {
output$info_box1 <- renderInfoBox({
infoBox("Amount in Total here", sum(mydf$Amount))
})
output$info_box2 <- renderInfoBox({
df_output <- mydf %>% group_by(Type) %>% tally()
infoBox("Class with the hightest amount and amount in total of that class", paste(df_output$Type[df_output$n == max(df_output$n)],max(df_output$n)) )
})
output$rawdata = renderTable({
mydf
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have a shiny app that displays a number of products depending on the search.
It subsets a large dataset and shows me the products I want that match.
I have another dataframe that has the reviews of said products.
I would like that when a specific row is clicked the review information appears in a different datatable.
The second datatable also needs to be a subset based on the Catalog Number (here is Acolumn.
All help appreciated.
df1 <- data.frame(A= c("BX002","BX006", "BX008"),
B= c("Actin","Tubulin", "GAPDH"),
C = c("Mouse","Human", "Human"),
D = c("WB","WB", "IHC"))
df2 <- data.frame(A= c("BX002","BX006", "BX008"),
B= c("Actin","Tubulin", "GAPDH"),
C = c("5","5", "4"),
D = c("Good","Good", "Bad"),
E = c("Kidney", "Liver", "Heart"))
library(shinydashboard)
library(shiny)
app <- shinyApp(
ui = dashboardPage(
dashboardHeader(
title = "Search"),
dashboardSidebar(
sidebarMenu(
menuItem("Search Product", tabName = "product", icon = icon("search")))),
dashboardBody(
tabItems(
tabItem("product",
fluidPage(
sidebarLayout(
sidebarPanel(textInput("name", "Protein name", value = ""),
submitButton("Search")),
mainPanel(
tabsetPanel(
tabPanel("Products", dataTableOutput("table1")))))))))),
server = shinyServer(function(input, output, session) {
output$table1 <- DT::renderDataTable({
validate(need(input$name != "", "Please select a Protein Name"))
search <- input$name
df <- subset(df1, grepl(search, df1$B, ignore.case = TRUE)==TRUE)
datatable(df, escape = FALSE, selection = "single")
})
observeEvent(input$table1_rows_selected,
{
df <- subset(df2, df2$A == input$table1_rows_selected$A)
showModal(modalDialog(
title = "Reviews",
df
))
})
})
)
I have tried a few methods but cant make it work.
This is my last atempt, no box popup, no error message nothing.
best
I took some liberties with your formatting to make it simpler to recreate.
This should give you the jist of how the modalDialogfunction works with DT.
Here's a working example:
library(shiny)
library(DT)
ui <- fluidPage(
textInput('name','Protein Name'),
dataTableOutput('table1')
)
server <- function(input, output,session) {
df1 <- data.frame(A= c("BX002","BX006", "BX008"),
B= c("Actin","Tubulin", "GAPDH"),
C = c("Mouse","Human", "Human"),
D = c("WB","WB", "IHC"))
df2 <- data.frame(A= c("BX002","BX006", "BX008"),
B= c("Actin","Tubulin", "GAPDH"),
C = c("5","5", "4"),
D = c("Good","Good", "Bad"),
E = c("Kidney", "Liver", "Heart"))
tbl1 <- reactive({
if(nchar(input$name)>0){
df1[which(tolower(input$name) == tolower(df1$B)),]
}
})
output$table1 <- renderDataTable({
if(nchar(input$name)>0){
datatable(tbl1(),selection = 'single')
}
})
review_tbl <- reactive({
df2[which(df1[input$table1_rows_selected,1]==df2$A),]
})
observeEvent(input$table1_rows_selected,{
showModal(
modalDialog(
renderDataTable({
review_tbl()
})
))
})
}
# Run the application
shinyApp(ui = ui, server = server)
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!