How to update shiny data frame in real time using checkboxes? - r

I have the following app below, it takes a dataframe which is created in the shiny server, and uses this to generate tab Panels, which in turn checkboxes within each tab panel (3 checkboxes per tab panel) - within each tab panel there is a "select all" box which is supposed to essentially check all of the boxes in that tab panel
So what i need help with - is that i would like it so that if i am on tab 1 and "press" the "select all" button, then it will "check" all those boxes in that tab Panel (and of course "un-pressing" that button will deselect those boxes) - But i would also want the functionality, so that if you select a number of checkboxes in different tabs, then it would update accordingly and will not lose any information, (this includes pressing select all on different tabs also)
So for example i would want the following behaviour:
If you select the "Edibles" Tab > then press "select all" - all 3 checkboxes are selected
Now if you then select the "Fried" tab > then press "cheese" which is one of the options for the individual checkboxes - you will now have in total 4 checkboxes selected, all those from the "edibles" tab and just the one from the "fried" tab
So if we now de-select the "select all" button from the first tab "edibles", it loses all information and the checkbox in "Fried" which was "cheese" no longer is checked,
This is not the behaviour i would want - i would like it to update accordingly and have "cheese" still selected as we have unpressed select all
I have printed off the names of what is being selected where and when on the actual app
code is below:
Any thoughts?
library(shiny)
library(shinydashboard)
library(tidyverse)
library(magrittr)
header <- dashboardHeader(
title = "My Dashboard",
titleWidth = 500
)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
radioButtons("select_by", "Select by:",
c("Food Type" = "Food",
"Gym Type" = "Gym",
"TV show" = "TV"))
)
)
body <- dashboardBody(
fluidRow(
uiOutput("Output_panel")
),
tabBox(title = "RESULTS", width = 12,
tabPanel("Visualisation",
width = 12,
height = 800
)
)
)
ui <- dashboardPage(header, siderbar, body, skin = "purple")
server <- function(input, output, session){
nodes_data_1 <- data.frame(id = 1:15,
Food = as.character(c("Edibles", "Fried", "Home Cooked", "packaged", "vending machine")),
Product_name = as.character(c("Bacon", "Cheese", "eggs", "chips", "beans", "oast", "oats and beans", "fried beans", "chickpeas", "broad beans", "garbanzo", "oat bars", "dog meat", "cat food", "horse meat")),
Price = c(1:15), TV =
sample(LETTERS[1:3], 15, replace = TRUE))
# build a edges dataframe
edges_data_1 <- data.frame(from = trunc(runif(15)*(15-1))+1,
to = trunc(runif(15)*(15-1))+1)
# create reactive of nodes
nodes_data_reactive <- reactive({
nodes_data_1
}) # end of reactive
# create reacive of edges
edges_data_reactive <- reactive({
edges_data_1
}) # end of reactive"che
# The output panel differs depending on the how the data is selected
# so it needs to be in the server section, not the UI section and created
# with renderUI as it is reactive
output$Output_panel <- renderUI({
# When selecting by workstream and issues:
if(input$select_by == "Food") {
food <- unique(as.character(nodes_data_reactive()$Food))
food_panel <- lapply(seq_along(food), function(i) {
### filter the data only once
food_dt <- dplyr::filter(nodes_data_reactive(), Food == food[i])
### Use the id, not the price, as the id is unique
food_ids <- as.character(food_dt$id)
selected_ids <- food_ids[food_ids %in% isolate({chosen_food()})] ### use isolate, so as to not be reactive to it
tabPanel(food[i],
checkboxGroupInput(
paste0("checkboxfood_", i),
label = "Random Stuff",
choiceNames = as.character(food_dt$Product_name), ### for some reason it likes characters, not factors with extra levels
choiceValues = food_ids,
selected = selected_ids
),
checkboxInput(
paste0("all_", i),
"Select all",
value = all(food_ids %in% isolate({chosen_food()}))
)
)
})
box(title = "Output PANEL",
collapsible = TRUE,
width = 12,
do.call(tabsetPanel, c(id = 't', food_panel)),
"Items: ", renderText(paste0(chosen_food(), collapse = ", ")),
"Names: ", renderText(paste0(chosen_food_names(), collapse = ", "))
) # end of Tab box
}
}) # end of renderUI
observe({
lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
product_choices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE) %>%
as.character()
product_prices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Price) %>%
unlist(use.names = FALSE)
if(!is.null(input[[paste0("all_", i)]])){
if(input[[paste0("all_", i)]] == TRUE) {
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choiceNames = product_choices,
choiceValues = product_prices,
selected = product_prices)
} else {
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choiceNames = product_choices,
choiceValues = product_prices,
selected = c()
)
}
}
})
})
chosen_food <- reactive({
unlist(lapply(seq_along(unique(nodes_data_reactive()$Food)), function(i) {
# retrieve checkboxfood_NUMBER value
input[[paste0("checkboxfood_", i)]]
}))
})
chosen_food_names <- reactive({
# turn selected chosen food values into names
nodes_data_reactive()$Product_name[as.numeric(chosen_food())]
})
} # end of server
# Run the application
shinyApp(ui = ui, server = server)

The problem was that you were updating all checkbox groups that didn't have the select all option selected. The solution is to add an if condition that checks to see if all the options are selected or not by comparing the length of input[[paste0("checkboxfood_", i)]] with length of product_choices
Code:
library(shiny)
library(shinydashboard)
library(tidyverse)
library(magrittr)
#################################################
#################### UI.R #######################
#################################################
header <- dashboardHeader(
title = "My Dashboard",
titleWidth = 500
)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
radioButtons("select_by", "Select by:",
c("Food Type" = "Food",
"Gym Type" = "Gym",
"TV show" = "TV"))
)
)
body <- dashboardBody(
fluidRow(
uiOutput("Output_panel")
),
tabBox(title = "RESULTS", width = 12,
tabPanel("Visualisation",
width = 12,
height = 800
)
)
)
ui <- dashboardPage(header, siderbar, body, skin = "purple")
#################################################
################## Server.R #####################
#################################################
server <- function(input, output, session){
nodes_data_1 <- data.frame(id = 1:15,
Food = as.character(c("Edibles", "Fried", "Home Cooked", "packaged", "vending machine")),
Product_name = as.character(c("Bacon", "Cheese", "eggs", "chips", "beans", "oast", "oats and beans", "fried beans", "chickpeas", "broad beans", "garbanzo", "oat bars", "dog meat", "cat food", "horse meat")),
Price = c(1:15), TV =
sample(LETTERS[1:3], 15, replace = TRUE))
# build a edges dataframe
edges_data_1 <- data.frame(from = trunc(runif(15)*(15-1))+1,
to = trunc(runif(15)*(15-1))+1)
# create reactive of nodes
nodes_data_reactive <- reactive({
nodes_data_1
}) # end of reactive
# create reacive of edges
edges_data_reactive <- reactive({
edges_data_1
}) # end of reactive"che
# The output panel differs depending on the how the data is selected
# so it needs to be in the server section, not the UI section and created
# with renderUI as it is reactive
output$Output_panel <- renderUI({
#Select Food
if(input$select_by == "Food") {
food <- unique(as.character(nodes_data_reactive()$Food))
food_panel <- lapply(seq_along(food), function(i) {
### filter the data only once
food_dt <- dplyr::filter(nodes_data_reactive(), Food == food[i])
### Use the id, not the price, as the id is unique
food_ids <- as.character(food_dt$id)
selected_ids <- food_ids[food_ids %in% isolate({chosen_food()})] ### use isolate, so as to not be reactive to it
tabPanel(food[i],
checkboxGroupInput(
paste0("checkboxfood_", i),
label = "Random Stuff",
choiceNames = as.character(food_dt$Product_name), ### for some reason it likes characters, not factors with extra levels
choiceValues = food_ids,
selected = selected_ids
),
checkboxInput(
paste0("all_", i),
"Select all",
value = all(food_ids %in% isolate({chosen_food()}))
)
)
})
box(title = "Output PANEL",
collapsible = TRUE,
width = 12,
do.call(tabsetPanel, c(id = 't', food_panel)),
"Items: ", renderText(paste0(chosen_food(), collapse = ", ")),
"Names: ", renderText(paste0(chosen_food_names(), collapse = ", "))
) # end of Tab box
}
}) # end of renderUI
observe({
lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
product_choices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE) %>%
as.character()
product_prices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Price) %>%
unlist(use.names = FALSE)
if(!is.null(input[[paste0("all_", i)]])){
if(input[[paste0("all_", i)]] == TRUE) {
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choiceNames = product_choices,
choiceValues = product_prices,
selected = product_prices)
} else {
if((input[[paste0("all_", i)]] != TRUE) & (length(input[[paste0("checkboxfood_", i)]]) == length(product_choices)))
{
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choiceNames = product_choices,
choiceValues = product_prices,
selected = c()
)
}}
}
})
})
chosen_food <- reactive({
unlist(lapply(seq_along(unique(nodes_data_reactive()$Food)), function(i) {
# retrieve checkboxfood_NUMBER value
input[[paste0("checkboxfood_", i)]]
}))
})
chosen_food_names <- reactive({
# turn selected chosen food values into names
nodes_data_reactive()$Product_name[as.numeric(chosen_food())]
})
}
# Run the application
shinyApp(ui = ui, server = server)

Related

R Shiny: Can't access variables stored in a list in reactive element

I would like to select one sample from my dataset in a dropdown menu.
As there are many samples to choose from, I would like to narrow down the selectable samples by selecting the values of additional data columns in checkbox dropdown menus.
I can successfully create the checkbox dropdown menus and and print the selections made there.
I am struggling with feeding these same selected values into the dropdown menu that chooses the sample. I want to make the choices of the selectInput reactive but can't access the variables the same way as inside renderText().
See comments in the code for where I am stuck.
Thanks!
library(shiny)
library(dplyr)
##################################
#### checkbox dropdown module ####
##################################
mod_ui_checkbox_dropdown_ui <- function(id){
ns <- NS(id)
tagList(
uiOutput(ns("choice_dropdown"))
)
}
mod_ui_checkbox_dropdown_server <- function(id, dropdown_label = "Items", menu_choices = c("item1", "item2", "item3"), dropdown_status = "default"){
dropdownButton <- function(label = "", status = c("default", "primary", "success", "info", "warning", "danger"), ..., width = NULL) {
status <- match.arg(status)
# dropdown button content
html_ul <- list(
class = "dropdown-menu",
style = "max-width: 300px;",
#style = if (!is.null(width))
# paste0("width: ", validateCssUnit(width), ";"),
lapply(X = list(...), FUN = tags$li, style = "margin-left: 10px; margin-right: 10px;")
)
# dropdown button appearance
html_button <- list(
class = paste0("btn btn-", status," dropdown-toggle"),
style = "width: 100%; max-width: 300px; display: flex; justify-content: space-between;",
type = "button",
`data-toggle` = "dropdown"
)
html_button <- c(html_button, list(label))
html_button <- c(html_button, list(tags$span(class = "caret", style = "margin-top: 8px;")))
# final result
tags$div(
class = "dropdown",
do.call(tags$button, html_button),
do.call(tags$ul, html_ul),
tags$script(
"$('.dropdown-menu').click(function(e) {
e.stopPropagation();
});")
)
}
moduleServer( id, function(input, output, session){
ns <- session$ns
# output$selected_items <- renderPrint({
# input$dropdown_checkboxes
# })
output$choice_dropdown <- renderUI({
dropdownButton(
label = dropdown_label, status = dropdown_status, width = "100%",
actionButton(inputId = ns("all"), label = "all/none", class = "btn btn-sm", style = "margin-bottom: 8px;"),
checkboxGroupInput(inputId = ns("dropdown_checkboxes"), label = NULL, choices = menu_choices, selected = menu_choices)
)
})
# Select all / Unselect all
observeEvent(input$all, {
if (is.null(input$dropdown_checkboxes)) {
updateCheckboxGroupInput(
session = session, inputId = "dropdown_checkboxes", selected = menu_choices
)
} else {
updateCheckboxGroupInput(
session = session, inputId = "dropdown_checkboxes", selected = ""
)
}
})
# return selected values
return(reactive(input$dropdown_checkboxes))
})
}
##################
#### main app ####
##################
ui <- fluidPage(
textOutput("text"),
uiOutput("sample_dropdown"),
#uiOutput("manual_checks"),
br(),
br(),
uiOutput("sample_filters"),
)
server <- function(input, output, session) {
data <- tibble::tibble("Sample ID" = c("Sample1", "Sample2", "Sample3", "Sample4", "Sample5", "Sample6"),
"Group" = c("group1", "group1", "group2", "group2", "group3", "group3"),
"Name" = c("Aime", "Balthasar", "Charlotte", "Daniel", "Emilie", "Fiona"))
ns <- session$ns
# helper function. filters dataframe columns for only the entries listed in selected_values
# selected_values is a list with an entry for each filter dropdown that holds a reactive vector with the selected items from each dropdown
filter_selection <- function(data, selected_values){
# loop through list by names of the list items
for (val in names(selected_values)){
if(!is.null(val)){
data <- dplyr::filter(data, .data[[val]] %in% selected_values[[val]]())
}
}
return(data)
}
### select sample ###
# get selectable samples from study data
selectable_samples <- reactive({
##### HERE BE DRAGONS
##### THIS DOES NOT WORK: When I try to access the values from the checkboxes here in this reactive element, I only get the empty list().
##### How do I make this reactive element respond to the selected values?
### ONLY PRINTS EMPTY LIST ###
print(selected_values)
### THIS GIVES AN ERROR ###
#print(selected_values$Name())
data %>%
# filter the choices based on the selected values here
{if(length(selected_values) != 0) filter_selection(., selected_values) else .} %>%
dplyr::select(any_of("Sample ID")) %>%
unique() %>%
pull() %>%
sort()
})
output$sample_dropdown <- renderUI({
selectInput("sample_dropdown", label = NULL, choices = selectable_samples())
})
## ---- sample filters ##
## this dynamically creates checkbox dropdown menus for selected filter columns
sample_filter_cols <- c("Group", "Name")
# create filter module UI elements
output$sample_filters <- renderUI(
sapply(sample_filter_cols, function(fav){
mod_ui_checkbox_dropdown_ui(stringr::str_replace_all(fav, " ", "-")) #IDs don't like spaces
})
)
# capture filter module outputs in list
# solution using a list and observe() adapted from here
# https://stackoverflow.com/questions/57802428/looping-shiny-callmodule-only-exports-last-value
selected_values <- list()
observe(
selected_values <<- sapply(sample_filter_cols, function(x){
choices <- data %>%
select(any_of(x)) %>%
unique() %>%
pull() %>%
sort()
mod_ui_checkbox_dropdown_server(stringr::str_replace_all(x, " ", "-"), dropdown_label = x, menu_choices = choices)
}, USE.NAMES = TRUE)
)
##### THIS WORKS: I can access the selected values of the filter columns here and print them as text.
##### So why won't this propagate to the reactive element above?
output$text <- renderText(paste("selected values:",
paste(selected_values$Name(), collapse = " "),
paste(selected_values$Group(), collapse = " ")
))
}
shinyApp(ui, server)
Try this code. I built it without modules and it is a little bit simple, but it works.
I changed the 2nd SAMPLE ID -> to Sample 3 because I need to prove one sample with more than one group.
I hope this can help you.
library(shiny)
library(shinyWidgets)
require(tibble)
data_read <<-
tibble::tibble(
"Sample ID" = c("Sample1", "Sample3", "Sample3", "Sample4", "Sample5", "Sample6"),
"Group" = c("group1", "group1", "group2", "group2", "group3", "group3"),
"Name" = c("Aime", "Balthasar", "Charlotte", "Daniel", "Emilie", "Fiona"))
if (interactive()) {
reactive_data <- reactiveValues(
data_all = data_read,
data_sample_filter = data_read[0,],
vector_groups = NULL,
group_selected = c(),
vector_names = NULL,
)
ui <- fluidPage(
selectInput(
"sample_dropdown",
label = NULL,
choices = data_read$`Sample ID` %>% unique
),
uiOutput("group_dropdown"),
uiOutput("names_dropdown"),
verbatimTextOutput("texto"),
tableOutput("table")
)
server <- function(input, output) {
observe({
data_filter_group <<-
data_read %>%
filter(
`Sample ID` %in% input$sample_dropdown
)
output$group_dropdown <- renderUI({
pickerInput(
inputId = "group_dropdown",
label = "select group(s)",
choices = isolate(reactive_data$vector_groups),
options =
list(
`actions-box` = TRUE
),
multiple = TRUE
)
})
# Change reactive values
reactive_data$data_sample_filter <- data_filter_group
reactive_data$vector_groups <- data_filter_group$Group %>% unique
},
label = "group_dropdown UI"
)
observe({
# save reactive values input group
reactive_data$group_selected <- input[["group_dropdown"]]
data_filter_names <<-
isolate(reactive_data$data_sample_filter) %>%
filter(
Group %in% isolate(reactive_data$group_selected)
)
# Change reactive values
reactive_data$vector_names <- data_filter_names$Name %>% unique
output$names_dropdown <- renderUI({
pickerInput(
inputId = "names_dropdown",
label = "select group(s)",
choices = isolate(reactive_data$vector_names),
options = list(
`actions-box` = TRUE),
multiple = TRUE
)
})
},
label = "names_dropdown UI"
)
# example all data output
output$table <-
renderTable({
data_read
})
output$texto <-
renderText({
paste("selected values:\n",
input$sample_dropdown,"\n\t",
paste( input[["group_dropdown"]],sep="" ,collapse = "\n\t"),"\n\t\t",
paste( input[["names_dropdown"]],sep="" ,collapse = "\n \t\t")
)
})
}
shinyApp(ui, server)
}
SOLVED: Thanks to Yeyo's suggestion of using pickerInput I was able to do away with my monstrosity of a custom widget module and get this to work nicely with much less code!
library(shiny)
library(shinyWidgets)
library(dplyr)
#' Helper Function
#'
#' #description helper function to filter the choices of a dropdown menu based on selected data
#'
#' #return character vector with choices that remain after filtering the data
#'
#' #param data data frame to be filtered
#' #param choice_col name of the column that holds all possible values for the dropdown menu. e.g. if the dropdown menu chooses sample ids, this may be the "Sample ID" column
#' #param filter_selections list with selected values from all filter dropdown menus. e.g. list("Group" = c("group1", "group2), "Names" = c("Aime", "Balthasar")), will produce all samples that are in these two groups and belong to these two names.
#'
#' #noRd
filter_choices <- function(data, choice_col, filter_selections){
choices <- data
for (filter_col in names(filter_selections)){
choices <- choices %>%
dplyr::filter(., .data[[filter_col]] %in% filter_selections[[filter_col]])
}
choices <- choices %>%
dplyr::select(any_of(choice_col)) %>%
unique() %>%
pull() %>%
sort()
return(choices)
}
##################
#### main app ####
##################
ui <- fluidPage(
uiOutput("sample_dropdown"),
h3("Filters"),
uiOutput("sample_filters")
)
server <- function(input, output, session) {
data <- tibble::tibble("Sample ID" = c("Sample1", "Sample2", "Sample3", "Sample4", "Sample5", "Sample6"),
"Group" = c("group1", "group1", "group2", "group2", "group3", "group3"),
"Name" = c("Aime", "Balthasar", "Charlotte", "Daniel", "Emilie", "Fiona"))
### dropdown to select a sample from the data ###
selectable_samples <- reactive({
filter_choices(data, choice_col = "Sample ID", filter_selections = selected_values())
})
output$sample_dropdown <- renderUI({
shinyWidgets::pickerInput("sample_dropdown", label = "Select Sample", choices = selectable_samples())
})
### ---- dropdowns to narrow down choices of samples I am interested in ###
# specify which data columns you want to be able to filter by
sample_filter_cols <- c("Group", "Name")
# create picker UI elements for these columns
output$sample_filters <- renderUI(
div(
lapply(sample_filter_cols, function(x){
choices <- data %>%
select(any_of(x)) %>%
unique() %>%
pull() %>%
sort()
shinyWidgets::pickerInput(stringr::str_replace_all(x, " ", "-"),
label = x,
choices = choices,
multiple = TRUE,
selected = choices,
options = list(`actions-box` = TRUE))
})
)
)
# collect output of filter dropdown menus in a reactive list
selected_values <- reactive({
sapply(sample_filter_cols, function(x){
input[[stringr::str_replace_all(x, " ", "-")]]
}, USE.NAMES = TRUE)
})
}
shinyApp(ui, server)

DT output takes me to 1st page when i edit a reactive DT

I have a toy version of my code below. I have one of the columns (column 7) in my shiny DT output as editable. When i edit the a cell of the column it takes me back to the first row of of the column. I checked the data table object in environment, the edited cell does get update. So, that is good. But i want to stay on the same page after editing the cell. This is because a user may have applied a few filters to reach a certain page and then when he edits a cell he would like to continue from there rather than going back to start.
I am new to R so any help would be greatly appreciated.
I am using DT 0.7
My data frame has 7 columns: Continent, State, Country, Date, Rate (Pollution), Vehicles, Remark (editable column)
A user can filter the table output by select input, range and slider input. I want to make that output editable.
Thanks in advance!
library(shiny)
library(DT)
ui <- navbarPage("Hello",
tabPanel("Tab1",
sidebarLayout(
sidebarPanel( width = 4,
selectInput("continent", "Select:",
choices = ""),
selectInput("country" , "Select:",
choices = ""),
selectInput("state" , "Select:",
choices = ""),
dateRangeInput("date", "Select:",
startview = "month",
minview = "months",
maxview = "decades",
start = as.Date('1999-01-01'),
end = as.Date(today()),
separator = "-"),
sliderInput("rate", "Select:",
min = 1, max = 5, value = c(1,5),
dragRange = TRUE)),
mainPanel(
tabsetPanel(
tabPanel("Analysis",
dataTableOutput("Table1")
)))))
#server
server <- function(input, output, session)
{
observe({
updateSelectInput(session, "continent",
choices = c("All", unique(Df$Continent)))
})
observe({
updateSelectInput(session, "country",
choices = c("All", Df %>%
filter(`Continent` == input$continent) %>%
select(Country)))
})
observe({
updateSelectInput(session, "state",
choices = c("All", Df %>%
filter(`Continent` == input$continent &
`Country` == input$country) %>%
select(State)))
})
#create reactive table
RecTable <- reactive({
Df
if(input$continent != "All") {
Df <- Df[Df$Continent == input$continent,]
}
if(input$country != "All") {
Df <- Df[Df$Country == input$country,]
}
if(input$state != "All") {
Df <- Df[Df$State == input$state,]
}
Df <- Df %>%
filter(Date >= input$date[1] & Date <= input$date[2]) %>%
filter(Rate >= input$rate[1] & Rate <= input$rate[2])
Df})
output$Table1 <- DT::renderDT({
DT::datatable(RecTable(),
rownames = FALSE ,
editable = list(target = 'cell', disable = list(columns = c(0:6))))
})
proxy1 <- dataTableProxy('Table1')
observeEvent(input$Table1_cell_edit, {
Df <<- editData(Df, input$Table1_cell_edit, 'Table1', rownames = FALSE, resetPaging = FALSE)
})}
#run
shinyApp(ui = ui, server = server)

How to reset all checkboxes in a shiny dashboard?

Currently have the following code - is there any way in which I can reset all checkboxes within this app - regardless of being selected on one tab - or multiple tabs?
So I have introduced a select and deselect all button into the app as well so hopefully that feature will still remain in there?
code:
library(shiny)
library(shinydashboard)
library(tidyverse)
library(magrittr)
header <- dashboardHeader(
title = "My Dashboard",
titleWidth = 500
)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
radioButtons("select_by", "Select by:",
c("Food Type" = "Food",
"Gym Type" = "Gym",
"TV show" = "TV"))
)
)
body <- dashboardBody(
fluidRow(
uiOutput("Output_panel")
),
tabBox(title = "RESULTS", width = 12,
tabPanel("Visualisation",
width = 12,
height = 800
)
)
)
ui <- dashboardPage(header, siderbar, body, skin = "purple")
server <- function(input, output, session){
nodes_data_1 <- data.frame(id = 1:15,
Food = as.character(c("Edibles", "Fried", "Home Cooked", "packaged", "vending machine")),
Product_name = as.character(c("Bacon", "Cheese", "eggs", "chips", "beans", "oast", "oats and beans", "fried beans", "chickpeas", "broad beans", "garbanzo", "oat bars", "dog meat", "cat food", "horse meat")),
Gym_type = as.character(paste("Gym", 1:15)), TV =
sample(LETTERS[1:3], 15, replace = TRUE))
# build a edges dataframe
edges_data_1 <- data.frame(from = trunc(runif(15)*(15-1))+1,
to = trunc(runif(15)*(15-1))+1)
# create reactive of nodes
nodes_data_reactive <- reactive({
nodes_data_1
}) # end of reactive
# create reacive of edges
edges_data_reactive <- reactive({
edges_data_1
}) # end of reactive
# The output panel differs depending on the how the data is selected
# so it needs to be in the server section, not the UI section and created
# with renderUI as it is reactive
output$Output_panel <- renderUI({
# When selecting by workstream and issues:
if(input$select_by == "Food") {
box(title = "Output PANEL",
collapsible = TRUE,
width = 12,
do.call(tabsetPanel, c(id='t',lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
tabPanel(food[i],
checkboxGroupInput(paste0("checkboxfood_", i),
label = NULL,
choices = nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE)),
checkboxInput(paste0("all_", i), "Select all", value = TRUE)
)
})))
) # end of Tab box
# When selecting by the strength of links connected to the issues:
} else if(input$select_by == "Gym") {
box(title = "Output PANEL", collapsible = TRUE, width = 12,
checkboxGroupInput("select_gyms", "Select gyms you want to display", choices = unique(nodes_data_reactive()$Gym_type)
,
selected = NULL,
inline = FALSE
)# end of checkboxGroupInput
) # end of box
} else if(input$select_by == "TV") {
box(title = "Output PANEL", collapsible = TRUE, width = 12,
checkboxGroupInput("select_tvs",
"Select the tv shows you want to see",choices = sort(unique(nodes_data_reactive()$TV)),
selected = NULL,
inline = FALSE
)# end of checkboxGroupInput
) # end of box
} # end of else if
}) # end of renderUI
observe({
lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
product_choices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE)
if(!is.null(input[[paste0("all_", i)]])){
if(input[[paste0("all_", i)]] == TRUE) {
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choices = product_choices,
selected = product_choices)
} else {
updateCheckboxGroupInput(session,
paste0("checkboxfood_", i),
label = NULL,
choices =product_choices)
}
}
})
})
} # end of server
# Run the application
shinyApp(ui = ui, server = server)
Here is a solution based on a fixed naming convention for your checkboxes (I added the "chk_"-prefix)
Edit: distinguish updateCheckboxInput and updateCheckboxGroupInput
library(shiny)
library(shinydashboard)
library(tidyverse)
library(magrittr)
header <- dashboardHeader(
title = "My Dashboard",
titleWidth = 500
)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
radioButtons("select_by", "Select by:",
c("Food Type" = "Food",
"Gym Type" = "Gym",
"TV show" = "TV"))
)
)
body <- dashboardBody(
fluidRow(
uiOutput("Output_panel"),
tabBox(title = "RESULTS", width = 12,
tabPanel("Visualisation",
br(),
width = 12,
height = 800
)
),
column(12, actionButton(inputId ="resetBtn", label = "Reset Selection", icon = icon("times-circle")))
)
)
ui <- dashboardPage(header, siderbar, body, skin = "purple")
server <- function(input, output, session){
nodes_data_1 <- data.frame(id = 1:15,
Food = as.character(c("Edibles", "Fried", "Home Cooked", "packaged", "vending machine")),
Product_name = as.character(c("Bacon", "Cheese", "eggs", "chips", "beans", "oast", "oats and beans", "fried beans", "chickpeas", "broad beans", "garbanzo", "oat bars", "dog meat", "cat food", "horse meat")),
Gym_type = as.character(paste("Gym", 1:15)), TV =
sample(LETTERS[1:3], 15, replace = TRUE))
# build a edges dataframe
edges_data_1 <- data.frame(from = trunc(runif(15)*(15-1))+1,
to = trunc(runif(15)*(15-1))+1)
# create reactive of nodes
nodes_data_reactive <- reactive({
nodes_data_1
}) # end of reactive
# create reacive of edges
edges_data_reactive <- reactive({
edges_data_1
}) # end of reactive
# The output panel differs depending on the how the data is selected
# so it needs to be in the server section, not the UI section and created
# with renderUI as it is reactive
output$Output_panel <- renderUI({
# When selecting by workstream and issues:
if(input$select_by == "Food") {
box(title = "Output PANEL",
collapsible = TRUE,
width = 12,
do.call(tabsetPanel, c(id='t',lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
tabPanel(food[i],
checkboxGroupInput(paste0("chkgrp_checkboxfood_", i),
label = NULL,
choices = nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE)),
checkboxInput(paste0("chksingle_all_", i), "Select all", value = TRUE)
)
})))
) # end of Tab box
# When selecting by the strength of links connected to the issues:
} else if(input$select_by == "Gym") {
box(title = "Output PANEL", collapsible = TRUE, width = 12,
checkboxGroupInput("chkgrp_select_gyms", "Select gyms you want to display", choices = unique(nodes_data_reactive()$Gym_type)
,
selected = NULL,
inline = FALSE
)# end of checkboxGroupInput
) # end of box
} else if(input$select_by == "TV") {
box(title = "Output PANEL", collapsible = TRUE, width = 12,
checkboxGroupInput("chkgrp_select_tvs",
"Select the tv shows you want to see",choices = sort(unique(nodes_data_reactive()$TV)),
selected = NULL,
inline = FALSE
)# end of checkboxGroupInput
) # end of box
} # end of else if
}) # end of renderUI
observe({
lapply(1:length(unique(nodes_data_reactive()$Food)), function(i) {
food <- unique(sort(as.character(nodes_data_reactive()$Food)))
product_choices <- nodes_data_reactive() %>%
filter(Food == food[i]) %>%
select(Product_name) %>%
unlist(use.names = FALSE)
if(!is.null(input[[paste0("chksingle_all_", i)]])){
if(input[[paste0("chksingle_all_", i)]] == TRUE) {
updateCheckboxGroupInput(session,
paste0("chkgrp_checkboxfood_", i),
label = NULL,
choices = product_choices,
selected = product_choices)
} else {
updateCheckboxGroupInput(session,
paste0("chkgrp_checkboxfood_", i),
label = NULL,
choices =product_choices)
}
}
})
})
observeEvent(input$resetBtn, ignoreNULL = TRUE, ignoreInit = TRUE, {
resetChksingleInputs <- names(input)[grepl("^chksingle*", names(input))]
cat("Resetting single checkboxes:", resetChksingleInputs, sep = "\n")
lapply(resetChksingleInputs, updateCheckboxInput, session=session, value = FALSE)
resetChkgrpInputs <- names(input)[grepl("^chkgrp*", names(input))]
cat("Resetting checkbox groups:", resetChkgrpInputs, sep = "\n")
lapply(resetChkgrpInputs, updateCheckboxGroupInput , session=session, selected = character(0))
})
} # end of server
# Run the application
shinyApp(ui = ui, server = server)

Hide/Show table in R shiny based on input value

I am trying to show/hide a table based on the input selection. Based on my first dropdown if the user selects a value wave2 it should show the table 2 under the 1st tab else it should hide. I tried to use the react input select value to if else condition for output which is not how react works in R. Could someone please check and let me know on where I am wrong .
UI.r
library(shiny)
library(shinydashboard)
library(shinyBS)
library(shinythemes)
dashboardPage(
dashboardHeader(disable = F, title = "PATH Study"),
dashboardSidebar(
uiOutput("choose_wave"),
uiOutput("choose_category"),
uiOutput("choose_ethnicity"),
uiOutput("choose_age"),
uiOutput("choose_gender")
),
#S dashboardPage(header = dashboardHeader(), sidebar = dashboardSidebar(),body,title = NUll, skin = "yellow"),
dashboardBody(box(
width = 12,
tabBox(
width = 12,
id = "tabBox_next_previous",
tabPanel("Initiation",
fluidRow(
box(
title = "TABLE1",
width = 5,
solidHeader = TRUE,
status = "primary",
tableOutput("smoke"),
collapsible = T,
),
box(
title = "TABLE2",
width = 7,
solidHeader = TRUE,
status = "primary",
tableOutput("first_flov"),
collapsible = T
)
))
),
uiOutput("Next_Previous")
))
)
SERVER.r
library(shiny)
library(shinydashboard)
library(shinyBS)
library(knitr)
library(kableExtra)
library(plyr)
library(tidyverse)
library(DT)
library(dplyr)
shinyServer(function(input, output) {
print(sessionInfo())
with_demo_vars <- reactive({
data_selector(wave(), youth()) %>%
mutate(
ethnicity = !!ethnicity(),
age = !!age_group(),
gender = !!gender()
)
})
# Drop-down selection box for which Wave and User Type bracket to be selected
output$choose_wave <- renderUI({
# This can be static: it is the highest level and the options won't change
selectInput(
"selected_wave",
"Wave",
choices = list(
"Wave 1 Adult" = "wave1youthFALSE",
"Wave 1 Youth" = "wave1youthTRUE",
"Wave 2 Adult" = "wave2youthFALSE",
"Wave 2 Youth" = "wave2youthTRUE"
)
)
})
wave <- reactive({
as.integer(gsub("wave(\\d)youth.*", "\\1", input$selected_wave))
})
youth <- reactive({
as.logical(gsub("wave\\dyouth(.+)$", "\\1", input$selected_wave))
})
# Drop-down selection box for which Gender bracket to be selected
output$choose_ethnicity <- renderUI({
selectInput("selected_ethnicity", "Ethnicity", as.list(levels(with_demo_vars()$ethnicity)))
})
# Drop-down selection box for which Age bracket to be selected
output$choose_age <- renderUI({
selectInput("selected_age", "Age", as.list(levels(with_demo_vars()$age)))
})
# Drop-down selection box for which Gender bracket to be selected
output$choose_gender <- renderUI({
selectInput("selected_gender", "Gender", as.list(levels(with_demo_vars()$gender)))
})
output$selected_var <- renderText({
paste("You have selected", input$selected_wave)
})
myData <- reactive({
# wave_selected <- input$selected_wave
category_selected <- req(input$selected_category)
age_selected <- req(input$selected_age)
gender_selected <- req(input$selected_gender)
ethnicity_selected <- req(input$selected_ethnicity)
# TABLE 1
df<-data_selector(wave = 1, youth()) %>%
filter(!!is_ever_user(type = category_selected)) %>%
pct_first_flavored(type = category_selected)
df_sub <- names(df) %in% c("variable")
df <- df[!df_sub]
df
})
first_flov <- reactive({
category_selected <- req(input$selected_category)
age_selected <- req(input$selected_age)
gender_selected <- req(input$selected_gender)
ethnicity_selected <- req(input$selected_ethnicity)
first_flov_df <- data_selector(wave = 2, youth()) %>%
filter(!!is_new_user(type = category_selected)) %>% # this doesn't apply to wave 1
pct_first_flavored(type = category_selected)
first_flov_df_sub <- names(first_flov_df) %in% c("variable")
first_flov_df <- first_flov_df[!first_flov_df_sub]
first_flov_df
})
output$smoke <-
renderTable({
head(myData())
})
output$first_flov <-
if (wave() == 2) {
renderTable({
head(first_flov())
})
} else {
renderText({
paste("You have selected", input$selected_wave)
})
}
})

Output photos in shiny

Now I need to practice and build a recommender system by using R. Data set is from MovieLens. I want to output the movie photos as well, but not sure what to do. If there's 10000 movies, how should I save them and output them on my shiny APP? And suggestion is welcomed!
ui.R:
library(shiny)
library(shinydashboard)
library(proxy)
library(recommenderlab)
library(reshape2)
library(plyr)
library(dplyr)
library(DT)
library(RCurl)
setwd("C:\\Users\\lili\\Movieshiny")
movies <- read.csv("movies.csv", header = TRUE, stringsAsFactors=FALSE)
movies <- movies[with(movies, order(title)), ]
ratings <- read.csv("ratings100k.csv", header = TRUE)
shinyUI(dashboardPage(skin="blue",
dashboardHeader(title = "Movie Recommenders"),
dashboardSidebar(
sidebarMenu(
menuItem("Movies", tabName = "movies", icon = icon("star-o")),
menuItem("About", tabName = "about", icon = icon("question-circle")),
menuItem("Source code", icon = icon("file-code-o"),
href = "https://github.com/danmalter/Movielense"),
menuItem(
list(
selectInput("select", label = h5("Select 3 Movies That You Like"),
choices = as.character(movies$title[1:length(unique(movies$movieId))]),
selectize = FALSE,
selected = "Shawshank Redemption, The (1994)"),
selectInput("select2", label = NA,
choices = as.character(movies$title[1:length(unique(movies$movieId))]),
selectize = FALSE,
selected = "Forrest Gump (1994)"),
selectInput("select3", label = NA,
choices = as.character(movies$title[1:length(unique(movies$movieId))]),
selectize = FALSE,
selected = "Silence of the Lambs, The (1991)"),
submitButton("Submit")
)
)
)
),
dashboardBody(
tags$head(
tags$style(type="text/css", "select { max-width: 360px; }"),
tags$style(type="text/css", ".span4 { max-width: 360px; }"),
tags$style(type="text/css", ".well { max-width: 360px; }")
),
tabItems(
tabItem(tabName = "about",
h2("About this App"),
HTML('<br/>'),
fluidRow(
box(title = "Author: Danny Malter", background = "black", width=7, collapsible = TRUE,
helpText(p(strong("This application a movie reccomnder using the movielense dataset."))),
helpText(p("Please contact",
a(href ="https://twitter.com/danmalter", "Danny on twitter",target = "_blank"),
" or at my",
a(href ="http://danmalter.github.io/", "personal page", target = "_blank"),
", for more information, to suggest improvements or report errors.")),
helpText(p("All code and data is available at ",
a(href ="https://github.com/danmalter/", "my GitHub page",target = "_blank"),
"or click the 'source code' link on the sidebar on the left."
))
)
)
),
tabItem(tabName = "movies",
fluidRow(
box(
width = 6, status = "info", solidHead = TRUE,
title = "Other Movies You Might Like",
tableOutput("table")),
valueBoxOutput("tableRatings1"),
valueBoxOutput("tableRatings2"),
valueBoxOutput("tableRatings3"),
HTML('<br/>'),
box(DT::dataTableOutput("myTable"), title = "Table of All Movies", width=12, collapsible = TRUE)
)
)
)
)
)
)
server.R:
setwd("C:\\Users\\lili\\Movieshiny")
movies <- read.csv("movies.csv", header = TRUE, stringsAsFactors=FALSE)
movies <- movies[with(movies, order(title)), ]
ratings <- read.csv("ratings100k.csv", header = TRUE)
shinyServer(function(input, output) {
# Text for the 3 boxes showing average scores
formulaText1 <- reactive({
paste(input$select)
})
formulaText2 <- reactive({
paste(input$select2)
})
formulaText3 <- reactive({
paste(input$select3)
})
output$movie1 <- renderText({
formulaText1()
})
output$movie2 <- renderText({
formulaText2()
})
output$movie3 <- renderText({
formulaText3()
})
# Table containing recommendations
output$table <- renderTable({
# Filter for based on genre of selected movies to enhance recommendations
cat1 <- subset(movies, title==input$select)
cat2 <- subset(movies, title==input$select2)
cat3 <- subset(movies, title==input$select3)
# If genre contains 'Sci-Fi' then return sci-fi movies
# If genre contains 'Children' then return children movies
if (grepl("Sci-Fi", cat1$genres) | grepl("Sci-Fi", cat2$genres) | grepl("Sci-Fi", cat3$genres)) {
movies2 <- (movies[grepl("Sci-Fi", movies$genres) , ])
} else if (grepl("Children", cat1$genres) | grepl("Children", cat2$genres) | grepl("Children", cat3$genres)) {
movies2 <- movies[grepl("Children", movies$genres), ]
} else {
movies2 <- movies[grepl(cat1$genre1, movies$genres)
| grepl(cat2$genre1, movies$genres)
| grepl(cat3$genre1, movies$genres), ]
}
movie_recommendation <- function(input,input2,input3){
row_num <- which(movies2[,3] == input)
row_num2 <- which(movies2[,3] == input2)
row_num3 <- which(movies2[,3] == input3)
userSelect <- matrix(NA,length(unique(ratings$movieId)))
userSelect[row_num] <- 5 #hard code first selection to rating 5
userSelect[row_num2] <- 4 #hard code second selection to rating 4
userSelect[row_num3] <- 4 #hard code third selection to rating 4
userSelect <- t(userSelect)
ratingmat <- dcast(ratings, userId~movieId, value.var = "rating", na.rm=FALSE)
ratingmat <- ratingmat[,-1]
colnames(userSelect) <- colnames(ratingmat)
ratingmat2 <- rbind(userSelect,ratingmat)
ratingmat2 <- as.matrix(ratingmat2)
#Convert rating matrix into a sparse matrix
ratingmat2 <- as(ratingmat2, "realRatingMatrix")
#Create Recommender Model
recommender_model <- Recommender(ratingmat2, method = "UBCF",param=list(method="Cosine",nn=30))
recom <- predict(recommender_model, ratingmat2[1], n=30)
recom_list <- as(recom, "list")
recom_result <- data.frame(matrix(NA,30))
recom_result[1:30,1] <- movies2[as.integer(recom_list[[1]][1:30]),3]
recom_result <- data.frame(na.omit(recom_result[order(order(recom_result)),]))
recom_result <- data.frame(recom_result[1:10,])
colnames(recom_result) <- "User-Based Collaborative Filtering Recommended Titles"
return(recom_result)
}
movie_recommendation(input$select, input$select2, input$select3)
})
movie.ratings <- merge(ratings, movies)
output$tableRatings1 <- renderValueBox({
movie.avg1 <- summarise(subset(movie.ratings, title==input$select),
Average_Rating1 = mean(rating, na.rm = TRUE))
valueBox(
value = format(movie.avg1, digits = 3),
subtitle = input$select,
icon = if (movie.avg1 >= 3) icon("thumbs-up") else icon("thumbs-down"),
color = if (movie.avg1 >= 3) "aqua" else "red"
)
})
movie.ratings <- merge(ratings, movies)
output$tableRatings2 <- renderValueBox({
movie.avg2 <- summarise(subset(movie.ratings, title==input$select2),
Average_Rating = mean(rating, na.rm = TRUE))
valueBox(
value = format(movie.avg2, digits = 3),
subtitle = input$select2,
icon = if (movie.avg2 >= 3) icon("thumbs-up") else icon("thumbs-down"),
color = if (movie.avg2 >= 3) "aqua" else "red"
)
})
movie.ratings <- merge(ratings, movies)
output$tableRatings3 <- renderValueBox({
movie.avg3 <- summarise(subset(movie.ratings, title==input$select3),
Average_Rating = mean(rating, na.rm = TRUE))
valueBox(
value = format(movie.avg3, digits = 3),
subtitle = input$select3,
icon = if (movie.avg3 >= 3) icon("thumbs-up") else icon("thumbs-down"),
color = if (movie.avg3 >= 3) "aqua" else "red"
)
})
# Generate a table summarizing each players stats
output$myTable <- renderDataTable({
movies[c("title", "genres")]
})
}
)
For example, I want to insert this into my code:
library(shiny)
Define UI with external image call
ui <- fluidPage(
titlePanel("Look at the image below"),
sidebarLayout(sidebarPanel(),
mainPanel(htmlOutput("picture"))))
Define server with information needed to hotlink image
server <- function(input, output) {
output$picture <-
renderText({
c(
'<img src="',
"http://www.google.com.tw/search?biw=1536&bih=759&tbm=isch&sa=1&q=notebook+movie&oq=notebook+movie&gs_l=psy-ab.3..0l4.5729.7315.0.7708.6.6.0.0.0.0.223.623.4j1j1.6.0....0...1.1.64.psy-ab..0.6.622...0i67k1.0.P-BZX3u-bzo#imgrc=S0E91gxvZcgeMM:",
'">'
)
})
}
shinyApp(ui = ui, server = server)
Every movie has different poster images.

Resources