About shiny branch processing using outputUI - r

We are currently developing Shiny APP.
When Option A or Option B is selected from pickerinput
If you select Option A, an open file dialog opens. Then select the text file. When I select a text file, I want the title of the text file to be displayed.
When I select OptionB, I want to display nothing and do nothing.
I wrote a sample codee.
library(shiny)
library(shinyWidgets)
library(shinyFiles)
ui <- fluidPage(
pickerInput(
inputId = "Pi1",
label = "SELECT!!",
choices = list(c("OptionA"),
c("OptionB")),
options = list(`actions-box` = TRUE,size = 7),
multiple = FALSE,
),
uiOutput("button"),
uiOutput("Message")
)
server <- function(input, output, session) {
OutputUi_func(input,output)
observeEvent(input$file, {
volumes <- c("Documents"=Sys.getenv("HOME"))
shinyFileChoose(input,'file', session=session,roots=volumes, filetypes=c('', 'txt'))
if(length(input$file) <= 1) return({})
fname <- unlist(input$file)
fname <- c(fname[2][1])
ftitle <- "FileName:"
fname <- paste0(ftitle,fname)
output$filename <- renderText({
paste0(fname)
})
})
}
OutputUi_func <- function(input,output){
output$button <- renderUI({
req(input$Pi1)
if(input$Pi1 %in% c("OptionA")){
shinyFilesButton('file', 'Read File', 'select file', FALSE)
}else return(NULL)})
output$Message <- renderText({
req(input$Pi1)
if(input$Pi1 %in% c("OptionA")){
textOutput("filename")
}else return(NULL)})
}
shinyApp(ui, server)
The code has a problem.
・When I execute the code, I get an error about "cat".
・ Even if you select a text file,The file title is not displayed.
What should I do to avoid the above two errors?

Try :
library(shiny)
library(shinyWidgets)
library(shinyFiles)
ui <- fluidPage(
pickerInput(
inputId = "Pi1",
label = "SELECT!!",
choices = list(c("OptionA"),
c("OptionB")),
options = list(`actions-box` = TRUE,size = 7),
multiple = FALSE,
),
uiOutput("button"),
uiOutput("Message")
)
server <- function(input, output, session) {
OutputUi_func(input,output)
observeEvent(input$file, {
if(input$Pi1 %in% "OptionB") return(NULL)
volumes <- c("Documents"=Sys.getenv("HOME"))
shinyFileChoose(input,'file', session=session,roots=volumes, filetypes=c('', 'txt'))
if(length(input$file) <= 1) return(NULL)
output$Message <- renderText({
if(length(input$file) <= 1 || input$Pi1 %in% "OptionB") return(NULL)
sprintf("FileName:%s", unlist(input$file$files)[[3]])
})
})
}
OutputUi_func <- function(input,output){
output$button <- renderUI({
if(input$Pi1 %in% "OptionA")
shinyFilesButton('file', 'Read File', 'select file', FALSE)
else return(NULL)
})
}
shinyApp(ui, server)

Related

Multiple UI Output Based on File Upload Using Shiny Modules

Dataset Viewer
Hello, I am attempting to create a shiny application that allows to user to view their uploaded datasets individually.
When there is no file uploaded a message appears asking the user to upload their file...once a csv file is uploaded, the message disappears and shows the users uploaded datasets.
What I've tried
I've tried: using conditionalPanels in app.R & upload.R, creating a separate R file exclusively for each ui condition. I believe my issue is that output$table (function that renders mainpanel ui) is not being triggered after the file uploads.
My issue
Once the user uploads a csv file(any readable csv file), the pre-existing message is not being replaced by the uploaded datasets.
upload.R
data = list()
numDatasets = 0
uploadSideUI <- function(id) {
ns <- NS(id)
tagList(
h2("Dataset Viewer"),
fileInput(ns("file"),label = "Upload File", multiple = FALSE, accept = ".csv")
)
}
uploadMainUI <- function(id) {
ns <- NS(id)
uiOutput(ns("table"))
}
uploadServer <- function(id) {
moduleServer(id, function(input,output,session){
observeEvent(eventExpr = input$file,
handlerExpr = {
df <- read.csv(file = input$file$datapath,header = FALSE)
data <<- c(data,list(df))
numDatasets <<- numDatasets + 1
})
output$table <- renderUI({
if(numDatasets ==0){
h2("please upload file")
}else{
req(input$file)
print(numDatasets)
lapply(1:numDatasets,function(i) {
dataframe = data[[i]]
tagList(
h2(paste("dataset",i)),
hr(),
datatable(dataframe,rownames = FALSE, option = list(scrollY="300px",searching=FALSE)),
br()
)
})
}
})
})
}
app.R
#app.R
library(DT)
library(shiny)
source("testModule.R")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uploadSideUI("uploadPage")
),mainPanel(
uploadMainUI("uploadPage")
)
)
)
server <- function(input, output, session) {
uploadServer("uploadPage")
}
shinyApp(ui = ui, server = server)
I am new to the modulization process in shiny, so if you have any other suggestions please point them out! Thanks in advance!
Try this
uploadServer <- function(id) {
moduleServer(id, function(input,output,session){
rv <- reactiveValues(numDatasets = 0)
observeEvent(eventExpr = input$file,
handlerExpr = {
df <- read.csv(file = input$file$datapath,header = FALSE)
data <<- c(data,list(df))
rv$numDatasets <<- rv$numDatasets + 1
})
output$table <- renderUI({
if(rv$numDatasets == 0){
h2("please upload file")
}else{
req(input$file)
print(rv$numDatasets)
lapply(1:rv$numDatasets,function(i) {
dataframe = data[[i]]
tagList(
h2(paste("dataset",i)),
hr(),
datatable(dataframe,rownames = FALSE, option = list(scrollY="300px",searching=FALSE)),
br()
)
})
}
})
})
}

How to dynamically update dropdown within a modulized shinyalert for each iteration of a for loop, when using html = TRUE?

I'm creating a shiny module, where I wish to display some pop-up messages to the user via shinyalerts and include dropdown menus via htlm = TRUE and shinyWidgets::pickerInput. For each shinyalert the options should be different and the alerts should appear right after each other when the user has selected the relevant option.
However, when running the shinyalerts within a for loop, only the first alert shows the drop-down, the following does not. Please have a look at the example below and screenshots. Any ideas what I'm doing wrong?
Module UI:
mod_match_columns_ui <- function(id){
ns <- NS(id)
tagList(
shinyalert::useShinyalert(),
actionButton(ns("run"), label = "Start!")
)
}
Module server:
mod_match_columns_server <- function(input, output, session){
ns <- session$ns
options <- list(c("option_1","option_2"),
c("option_3","option_4"))
observeEvent(input$run, {
for(col in 1:2){
nms <- options[[i]]
output[[paste0("dropdown",col)]] <- renderUI({
shinyWidgets::pickerInput(
inputId = ns(paste0("options",col)),
label = "Options listed below",
choices = nms,
selected = "",
multiple = FALSE,
options = shinyWidgets::pickerOptions(size = 15)
)
})
shinyalert::shinyalert(
title = "Pick an option!",
html = TRUE,
text = tagList(
uiOutput(ns(paste0("dropdown", col)))
),
inputId = ns(paste0("modal", col))
)
}
})
}
Run module:
library(shiny)
ui <- fluidPage(
mod_match_columns_ui("match_columns_ui_1")
)
server <- function(input, output, session) {
callModule(mod_match_columns_server, "match_columns_ui_1")
}
shinyApp(ui = ui, server = server)
First iteration:
Second iteration:
Why is the dropdown not shown in the second iteration?? Thanks
Try this
library(shiny)
library(shinyalert)
mod_match_columns_ui <- function(id){
ns <- NS(id)
tagList(
shinyalert::useShinyalert(),
actionButton(ns("run"), label = "Start!")
)
}
mod_match_columns_server <- function(id) {
moduleServer(id,
function(input, output, session) {
ns <- session$ns
options <- list(c("option_1","option_2"),
c("option_3","option_4"))
lapply(1:2, function(col){
output[[paste0("dropdown",col)]] <- renderUI({
shinyWidgets::pickerInput(
inputId = ns(paste0("options",col)),
label = paste("Options",col,"listed below"),
choices = options[[col]],
selected = "",
multiple = FALSE,
options = shinyWidgets::pickerOptions(size = 15)
)
})
})
observeEvent(input$run, {
shinyalert::shinyalert(
title = "Pick an option!",
html = TRUE,
text = tagList(
lapply(1:2, function(i){uiOutput(ns(paste0("dropdown",i)))})
)
# callbackR = function(x) { message("Hello ", x) },
# inputId = ns(paste0("modal"))
)
})
observe({
print(input$options1)
print(input$options2)
print(input$shinyalert)
})
})
}
ui <- fluidPage(
tagList(
mod_match_columns_ui("match_columns_ui_1")
)
)
server <- function(input, output, session) {
mod_match_columns_server("match_columns_ui_1")
}
shinyApp(ui = ui, server = server)

R/Shiny - Transfer checkbox labels to function field

I need the selected checkbox labels to fill in the "[,c("checkbox1","checkbox2")]" field (where both "checkbox1" and "checkbox2" are written). Thank you.
This is my code.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(tidyverse)
library(readxl)
library(stringr)
ui <- fluidPage(
br(),
fileInput("archive", "Upload file", accept = c(
".xlsx")),
# Itens Selection
checkboxGroupInput("additem", "Select Items", choices = NULL)
)
box(
width = 2000,
verbatimTextOutput("calfa")
)
server <- function(input, output, session) {
# Upload Data Sheet
csv <- reactive({
req(input$archive)
inFile <- input$archive
df <- read_xlsx(inFile$datapath)
return(df)
})
#reactive value that will hold the name of the file
reactive_my_path <- reactive({
# Test if file is selected
req(input$archive)
return(sub(".xlsx$", "", basename(input$archive$name)))
})
observe({
input$archive
# update the choices in input$additem
updateCheckboxGroupButtons(session,
"additem",
paste('Column names in:', reactive_my_path()),
choices = names(csv()))
})
# Alpha
output$calfa <-
renderPrint({
int<-csv()[,c("checkbox1","checkbox2")]
int <- na.omit(int)
psych::alpha(int, check.keys = TRUE)
})
}
# App
shinyApp(ui, server)
You can use input$additem to include all the checkbox that are selected. Also I have included another condition to run the psych::alpha code only when there is more than one column.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(readxl)
library(tidyverse)
library(readxl)
library(stringr)
ui <- fluidPage(
br(),
fileInput("archive", "Upload file", accept = c(
".xlsx")),
# Itens Selection
checkboxGroupInput("additem", "Select Items", choices = NULL),
box(
width = 2000,
verbatimTextOutput("calfa")
)
)
server <- function(input, output, session) {
# Upload Data Sheet
csv <- reactive({
req(input$archive)
inFile <- input$archive
df <- read_xlsx(inFile$datapath)
return(df)
})
#reactive value that will hold the name of the file
reactive_my_path <- reactive({
# Test if file is selected
req(input$archive)
return(sub(".xlsx$", "", basename(input$archive$name)))
})
observe({
input$archive
# update the choices in input$additem
updateCheckboxGroupButtons(session,
"additem",
paste('Column names in:', reactive_my_path()),
choices = names(csv()))
})
# Alpha
output$calfa <-
renderPrint({
req(length(input$additem) > 1)
int<-csv()[,input$additem]
int <- na.omit(int)
psych::alpha(int, check.keys = TRUE)
})
}
# App
shinyApp(ui, server)

Shiny Selectinput for every non-numeric column of a Filteinput data

I would like to create a Shiny dashboard where:
1) The user selects an excel file
2) A Selectinput option is created for every non-numeric column of the obtained dataframe is created that gives users the option to select every unique value in this column. This is how my code looks so far:
library(shiny)
library(dplyr)
library(openxlsx)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose xlsx file',
accept = c(".xlsx")),
lapply(names("varselect"), function(i) {
selectInput(paste0(i), paste0(i),
choices = "varselect"[i],
multiple = TRUE,
selected = "")})),
mainPanel()))
server <- function(input, output,session) {
Data <- reactive({
infile <- input$datafile
if (is.null(infile)) {
return(data.frame())
}
read.xlsx(infile$datapath,
sheetIndex = 1) %>% select_if(colSums(!is.na(.)) > 0%>% select_if(~!is.numeric(.x)) %>% head())
})
output$varselect <- renderUI({
})
observe({
lapply(names(Data()), function(i) {
selectInput(paste0(i), paste0(i),
choices = Data()[i],
multiple = TRUE,
selected = "")})})
}
shinyApp(ui = ui, server = server)
I am aware of the fact that the code is not working and that there are some grave mistakes, but I hope that somebody can help me to find an approach that does work for this problem. I am rather new to Shinny and that is why i honestly have no clue how to solve this problem.
Many thanks.
In your ui, you can include a uiOutput which will contain all of the dynamically created selectInput widgets.
Then, in output$varselect you can create the selectInput based on the number of columns in Data().
library(shiny)
library(dplyr)
library(openxlsx)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose xlsx file',
accept = c(".xlsx")),
uiOutput("varselect")
),
mainPanel()
)
)
server <- function(input, output, session) {
Data <- reactive({
infile <- input$datafile
if (is.null(infile)) {
return(data.frame())
}
read.xlsx(infile$datapath, sheet = 1) %>%
select_if(colSums(!is.na(.)) > 0) %>%
select_if(~!is.numeric(.x)) %>%
head()
})
output$varselect <- renderUI({
if (ncol(Data() > 0)) {
lapply(1:ncol(Data()), function(i) {
selectInput(inputId = paste0("si_", i),
label = paste0("Input #", i),
choices = Data()[,i],
multiple = TRUE)
})
}
})
}
shinyApp(ui = ui, server = server)

Output more than 1 datatables in shiny main panel

I have a shiny app that a user can check whether they want the data table displayed in the main panel. Depending on the numericinput, if they select 1, only 1 datatable be displayed or if they select 2 it will display 2 datatables I am not so sure how to code this in shiny R since I am new to this. Thank you for looking into this.
Here is my code
library("shiny")
df1 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df1<-rbind(df1,setNames(as.list(c(10,20,30,40)), names(df2)))
df2 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df2<-rbind(df2,setNames(as.list(c(100,200,300,400)), names(df2)))
df3 <- data.frame("2010-01"=double(),
"2010-02"=double(),
"2010-03"=double(),
"2010-04"=double()
)
df3<-rbind(df3,setNames(as.list(c(1000,2000,3000,4000)), names(df2)))
ui <-fluidPage(
sidebarPanel(
checkboxInput("add_data", "Add Data Table(s)"),
conditionalPanel(condition="input.add_data === true",
numericInput("numofdata",
label="Number of Data Table(s):",
min = 1,
max = 3,
value = 1,
step = 1),
uiOutput("num_of_data"),
textOutput("see_ranges")
),
actionButton("submit", "Submit")
),
mainPanel(
titlePanel("Output Data Table"),
DT::dataTableOutput("datatable.view", width = "95%")
) # end of main panel
)
server <- function(input, output, session) {
output$num_of_data <- renderUI({
lapply(1:input$numofdata, function(i) {
print(trend_list())
})
})
output$see_ranges <- renderPrint({
print(trend_list())
})
data.filter <- reactive({
df(i)
})
output$datatable.view <- DT::renderDataTable(
{
input$submit
if (input$submit==0) return()
isolate({
for(i in 1:input$numoftrends) {
datatable(data.filter(i),
rownames=FALSE,
extensions = c("FixedColumns", "FixedHeader", "Scroller"),
options = list(searching=FALSE,
autoWidth=TRUE,
rownames=FALSE,
scroller=TRUE,
scrollX=TRUE,
pagelength=1,
fixedHeader=TRUE,
class='cell-border stripe',
fixedColumns =
list(leftColumns=2,heightMatch='none')
)
)
}
})
})
}
shinyApp(ui = ui, server = server)
You should look at this article:
http://shiny.rstudio.com/gallery/creating-a-ui-from-a-loop.html
You will seen then that one has to create multiple renderDataTable instead of muliple datatable within one renderDataTable().
Also in your code you call df like a function df() but it is only defined as a variable.
See a generic running example below.
EDIT: Changed dynamic part of UI.
library(DT)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("amountTable", "Amount Tables", 1:10, 3)
),
mainPanel(
# UI output
uiOutput("dt")
)
)
)
server <- function(input, output, session) {
observe({
lapply(1:input$amountTable, function(amtTable) {
output[[paste0('T', amtTable)]] <- DT::renderDataTable({
iris[1:amtTable, ]
})
})
})
output$dt <- renderUI({
tagList(lapply(1:input$amountTable, function(i) {
dataTableOutput(paste0('T', i))
}))
})
}
shinyApp(ui, server)

Resources