Shiny App reactivity issue and scoping issue - r

I am new to shiny and I am trying to build an app but I have been stuck on this one issue for a while. The purpose of the app is so users can upload their data, select their independent and dependent variables, select their number of trees...etc and eventually have that run through a random forest script and display the outputs.
However, right now I am stuck on setting up the drop-down input where users can select their variables (headers from the data they uploaded). It needs to be reactive so they first upload their data and then the app automatically knows what to put in the drop-down menu because it would be NULL otherwise. Here are copies of my ui.R and server.R files. If you know what may be wrong, your help would greatly be appreciated. Also, thank you to the people who helped me last week. I did not upload the actual R code (just images) so it was extra challenging for them.
ui.R
library(shiny)
shinyUI(fluidPage(
headerPanel(title = "Upload File"),
sidebarLayout(
sidebarPanel(
fileInput("file","Upload the file"),
h5("Max file size is 5 MB"),
tags$hr(),
radioButtons("sep","Seperator", choices = c(Comma = ",", Period = ".", Tilde = "~",minus = "-")),
tags$hr(),
checkboxInput("header","Header", TRUE),
tags$hr(),
uiOutput("vx"),
tags$hr(),
uiOutput("vy"),
tags$hr(),
numericInput("MTRY", "Set the MTRY", 0, min = 0, max = 500, step = 1,
width = 100),
helpText("The MTRY should default to 0"),
numericInput("numtree", "Number of Trees", 500, min = 30, max = 10000, step = 100,
width = 100)
),
mainPanel(
tableOutput("input_file")
)
)
)
)
Server.R
library(shiny)
shinyServer(function(input, output) {
output$input_file <- renderTable({
file_to_read = input$file
if(is.null(file_to_read)){
return()
}
dat1 <- read.table(file_to_read$datapath, sep = input$sep, header = input$header)
return(dat1)
})
reactive1 = reactive({
if(is.null(dat1))
return()
D <- colnames(dat1)
reactive1[[1]] = D
reactive1[[2]] = D[1]
reactive1
})
output$vx <- renderUI({
selectInput("cols", "Select Dependent Variable",
choices = colnames(reactive1()[[1]]), selected = reactive1()[[2]][1])
})
output$vy <- renderUI({
selectInput("cols", "Select Independent Variables",
choices = colnames(reactive1()[[1]]), selected = reactive1()[[2]][1], multiple = T)
})
})
Here is what the app looks like after uploading a csv:
App

The key is to make the input data reactive and updateSelectInput based off of the reactive data frame. See below:
ui <- fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE),
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
tags$hr(),
selectInput("vars", "Label",choices = c("NULL"))
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output, session) {
df1 <- reactive({
req(input$file1)
read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
})
observeEvent(df1(), {
updateSelectInput(session, "vars", choices = names(df1()))
})
}
shinyApp(ui, server)
Please comment if this answers your question.

Related

fileInput function not responding in r Shiny

I am new to R and R shiny, and have been working on putting together a statistics application that will allow the user to import files, and then run different statistics programs on the data. The fileData function had been working fine for me until recently, and now whenever I attempt to upload a file, nothing opens. I have tried everything I can think of to get it to run, but it appears the file won't attach to the function. Any help will be very much appreciated!
library(shiny)
library(shinyFiles)
library(dplyr)
library(shinythemes)
ui <- fluidPage(theme = shinytheme("cosmo"),
# Application title
titlePanel("Stats"),
# Sidebar
sidebarLayout(
sidebarPanel(
tabsetPanel(type = "tab",
tabPanel("SCI",
fileInput("file1", "Insert File", multiple = TRUE, accept = c("text/csv", "text/comma-separated-values, text/plain", ".csv")),
selectInput("statChoice", "Choose Stats", c("None" = "None", "ANOVA 0 w/in 1 btw" = "A1btw", "ANOVA 0 w/in 2 btw" = "A2btw")),
conditionalPanel("statChoice == 'A1btw'",
uiOutput("ind1"),
uiOutput("dep1")),
conditionalPanel("statChoice == 'A2btw'",
uiOutput("ind1"),
uiOutput("ind2"),
uiOutput("dep1")),
)
)
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(type = "tab",
tabPanel("Data",
dataTableOutput("fileData")),
tabPanel("Summary Statistics"),
tabPanel("Graphs"))
)
)
)
server <- function(input, output) {
fileData <- eventReactive(input$file1,{
read.csv(input$file1$dataPath, header = TRUE, sep = ",", dec = ".")
})
output$fileData <- renderDataTable(
fileData()
)
vars <- reactive({
names(fileData())
})
output$ind1 <- renderUI({
selectInput("var1", "Independent 1", choices = vars())
})
output$ind2 <- renderUI({
selectInput("var2", "Independent 2", choices = vars())
})
output$dep1 <- renderUI({
selectInput("var3", "Dependent 1", choices = vars())
})
}
shinyApp(ui = ui, server = server)
Tricky because Shiny doesn't give any warning about this :
shiny app will not work if the same "output" is used two times in Ui.R.
Everything looks OK, except the double use of uiOutput("dep1") and uiOutput("ind1") :
conditionalPanel("statChoice == 'A1btw'",
uiOutput("ind1"), # Used once
uiOutput("dep1")), # Used once
conditionalPanel("statChoice == 'A2btw'",
uiOutput("ind1"), # Used twice
uiOutput("ind2"),
uiOutput("dep1")), # Used twice
You should use an output only once.

R Shiny: read data file, get user to select variable, plot with ggplot

As stated in the title, I'm trying to use Shiny in R to create a program that reads a csv file uploaded by the user, after which the user can select a variable from that file to view a plot that is plotted by ggplot. I'm trying to achieve this over two tabs, the first tab will read the file and the second tab will get the user to select the variable to view the plot.
My codes are as below. Currently, I am able to successfully read the user's file but I am not able to plot based on the variable selected (I currently only have 1 variable "Location" for demo). (HomeWTaxAmt is the y variable to plot against).
library(shiny)
library(ggplot2)
library(data.table)
library(RColorBrewer)
options(scipen=1000)
ui <- fluidPage(
navbarPage("User Interface:",tabPanel("Upload",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE),
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
tags$hr(),
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head"),
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"')),
mainPanel(
verbatimTextOutput("summary"),
tableOutput("contents")
))),
tabPanel("Graphing",
titlePanel("Plotting Graphs"),
sidebarLayout(
sidebarPanel(
selectInput("variable", "Variable:",
list("Location"))),
mainPanel(
h3(textOutput("caption")),
plotOutput("ggplot")
)
))
))
server <- function(input, output) {
output$contents <- renderTable({
req(input$file1)
library(data.table)
data <- fread(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
if(input$disp == "head") {
return(head(data))
}
else {
return(data)
}
})
output$summary <- renderPrint({
summary(data)
})
formulaText <- reactive(function() {
paste("HomeWTaxAmt ~", input$variable)
})
output$caption <- renderText(function() {
formulaText()
})
output$ggplot <- renderPlot(function() {
data <- fread(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
if(is.null(data)) return(NULL)
# check for the input variable
ggplot(data, aes(x=reorder(factor(data[input$variable]), -abs(HomeWTaxAmt), function(x){sum(x)}),
weight = abs(HomeWTaxAmt), fill = factor(data[input$variable]))) + geom_bar(show.legend=FALSE) + xlab(input$variable) +
scale_fill_manual(values=brewer.pal(n = 12, name = "Paired"))
})
}
shinyApp(ui, server)
As I did not have access to your exact .csv files I had to make some adjustments to the plotting command, but I'm pretty sure you can go from there and get it to work with your data. Please note that not loading a .csv file now gives you errors on the first tab, which dissapear as soon as data is loaded. You might want to use some ifelse switches here to ensure the end-user doesn't have to see these R-errors.
Here's the code that plots a plot as intended based on some sample data I had:
library(shiny)
library(ggplot2)
library(data.table)
library(RColorBrewer)
options(scipen=1000)
#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# I didn't change anything in this section
ui <- fluidPage(
navbarPage("User Interface:",tabPanel("Upload",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE),
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
tags$hr(),
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head"),
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"')),
mainPanel(
verbatimTextOutput("summary"),
tableOutput("contents")
))),
tabPanel("Graphing",
titlePanel("Plotting Graphs"),
sidebarLayout(
sidebarPanel(
selectInput("variable", "Variable:",
list("Location"))),
mainPanel(
h3(textOutput("caption")),
plotOutput("ggplot")
)
))
))
#XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
server <- function(input, output, session) { # make sure to include "session" here, in order to update your inputs later
# create an reactive upload to access your data more quickly and easily
reactive_data <- reactive({
print(input$file1$datapath)
data <- fread(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
return(data)
})
# preview
# no library(data.table) required here, as its already loaded at the beginning of the script)
output$contents <- renderTable({
# load your data
data <- reactive_data()
if(input$disp == "head") {
return(head(data))
}
else {
return(data)
}
})
output$summary <- renderPrint({
summary(reactive_data())
})
formulaText <- reactive({ # no need for function() here
paste("HomeWTaxAmt ~", input$variable)
})
output$caption <- renderText({
formulaText()
})
output$ggplot <- renderPlot({
# load your data
data <- reactive_data()
# to only plot when data is not NULL, make sure to include the plotting command in the if-else statement
# no data
if(is.null(data)){
return(NULL)
}else{
# data
# update your selectInput first, so that all the variables match your .csv headers
updateSelectInput(session, "variable",
choices = colnames(data),
selected = input$variable) # this keeps the input on the last thing selected on tab-change
# check for the input variable
# I used aes_string here so that indexing the colnames works
# you'll have to adjust the plotting command to your needs as my .csv files aren't the same as yours
plot <- ggplot(data, aes_string(x=colnames(data)[colnames(data) == input$variable], colnames(data)[length(colnames(data))]))+
geom_bar(stat="identity")
# Display your plot
print(plot)
}
})
}
shinyApp(ui, server)
Modified your code a bit and i hope it helps you.
library(shiny)
library(ggplot2)
ui <- fluidPage(
navbarPage("User Interface:",tabPanel("Upload",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE),
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
tags$hr(),
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head"),
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"')),
mainPanel(
verbatimTextOutput("summary"),
tableOutput("contents")
))),
tabPanel("Graphing",
titlePanel("Plotting Graphs"),
sidebarLayout(
sidebarPanel( uiOutput("variable_x"),
uiOutput("variable_y")),
mainPanel(
h3(textOutput("caption")),
plotOutput("plot")
)
))
))
server <- function(input, output, session) {
onSessionEnded(stopApp)
data <- reactive({
req(input$file1)
df <- read.csv(input$file1$datapath, header = input$header, sep = input$sep, quote = input$quote)
return(df)
})
output$contents <- renderTable({
if (input$disp == "head") {
return(head(data()))
}
else {
return(data())
}
})
output$summary <- renderPrint({
summary(data())
})
output$variable_x <- renderUI({
selectInput("variableNames_x", label = "Variable_X", choices = names(data()))
})
output$variable_y <- renderUI({
selectInput("variableNames_y", label = "Variable_Y", choices = names(data()) )
})
dat <- reactive({
test <- data.frame(data()[[input$variableNames_x]], data()[[input$variableNames_y]])
colnames(test) <- c("X", "Y")
return(test)
})
output$plot <- renderPlot({
if (is.null(data)) { return(NULL)
} else {
ggplot(dat(),aes(x = X,y = Y)) + geom_point(colour = 'red',height = 400,width = 600) +
labs(y = input$variableNames_y,
x = input$variableNames_x,
title = "ggplot")
}
})
}
shinyApp(ui, server)
Note : I have changed your ggplot function but you can change as per your requirement.

Passing on data and input within a shiny app

I was trying to simplify my shiny app. However, as much as I try it is not working, as I would like it to.
My Idea was to load data to the app, perform some analyses and return intermediate results to the user. At the moment I have to load the data, choose the right columns etc. for each output I am generating:
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
output$tab <- renderTable({
req(input$file1)
df2 <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
df2 <- df2[, c(input$column_1,input$column_2), drop = FALSE]
return(head(df2))})
})
})
runApp(list(ui = ui, server = server))
It works, but as I usually have many data and I want to perform a couple of analyses, it is gets quite time-consuming to load and process the data for each “output content”.
Is there a way to avoid this? Could I for example load the data and choose the right columns globaly, as in the second example? (I crossed out the lines where the error occurs)
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
# df <- df[, c(input$column_1,input$column_2), drop = FALSE]
#
# output$tab <- renderTable({
# (head(df))})
})
})
runApp(list(ui = ui, server = server))
Input data example:
date time level
01.01.2000 00:00:00 0.3724
01.01.2000 01:00:00 0.192
01.01.2000 02:00:00 -0.0252
I would appreciate any help!
Aishe
From what I've understood, you are getting an error because the dataframe df that you have defined is not reactive. You should make it reactive as it will change every time the user selects input columns.
Refer this to read about reactivity. Change the deleted portion of your code to this:
df.selected.columns <- df[c(input$column_1,input$column_2)]
output$tab <- renderTable({
(head(df.selected.columns()))
})

Render and download data table in Rshiny app

I am unable to render a data table and allow users to download that data table with a shiny application. Here is my MWE
UI:
ui <- fluidPage(
# Application title
titlePanel("Tool v0.03"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
fileInput("dataset", "Choose CSV File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
helpText(em("Note:Select all the inputs and click on button as given below to exectute the app")),
checkboxInput("header", "Header", TRUE),
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
selectInput("select", "Select columns to display", c('col1', 'col2'), multiple = TRUE),
actionButton("update", "Update Data set", class = "btn-primary",style='padding:4px; font-size:120%')
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel(h2("Random Stratified Sample"), DT::dataTableOutput('out.Sample'),
fluidRow(downloadButton('SampleDownload', "Download sample data"))) # in a tabitem)
)
)
)
)
Server:
server <- function(session, input, output) {
data <- reactive({
req(input$dataset)
Cleaning_Fun(read.csv(input$dataset$datapath, header = input$header,sep =
input$sep))
})
filtereddata <- eventReactive({
input$update
data()
}, {
req(data())
if(is.null(input$select) || input$select == "")
data() else
data()[, colnames(data()) %in% input$select]
})
observeEvent(data(), {
updateSelectInput(session, "select", choices=colnames(data()))
})
output$out.Sample <-
DT::renderDataTable(DT::datatable((filtereddata())
))
output$SampleDownload <- downloadHandler(
filename = function() {
paste('Sample_data-', Sys.Date(), '.csv', sep = '')
},
content = function(file){
write.csv(filtereddata()[input[["SampleData_rows_all"]], ],file)
}
)
}
This example allows the user to render and download a dataset that they have uploaded. Unfortunately the file only contains the header of the data table. Unsure where this is going wrong but, any help appreciated
Thanks,
John

how to show some widgets based on the selection from one widget in shiny app

below is a shiny app to upload a rda or csv file. What I need is only show the checkboxinput and radiobutton widgets only when csv is selected as the file type in the selectinput. When rda is selected, do not show those widgets.
library(shiny)
library(DT)
##---------------------------------------------------------------
## ui
##---------------------------------------------------------------
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
# select a file type
selectInput('filetype', label = h5(strong('Please select a file type')),
choices = c('rda', 'csv'),
selected = 'rda'),
# Input: Select a file ----
fileInput("file1", "Choose a file",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
# Input: Checkbox if file has header ----
checkboxInput("header", "Header", TRUE),
# Input: Select separator ----
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
# Input: Select quotes ----
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"')
),
#------------------------------Main Panel--------------------
mainPanel(
DT::dataTableOutput("data.table")
)
)
)
##---------------------------------------------------------------------
# server
##---------------------------------------------------------------------
options(shiny.maxRequestSize=30*1024^2)
server <- function(input, output, session) {
dt <- reactive ({
if (input$filetype %in% 'rda') {
load (input$file1$datapath)
df
} else {
read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
}
})
output$data.table <- DT::renderDataTable({
req(input$file1)
DT::datatable(dt(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
}
runApp(shinyApp(ui=ui, server=server))
Really appreciate it if anyone can help me with that. I have no clue how to achieve that.
Here's a sample of how to do build a dynamic UI that will only show the radio buttons if the file type selected is 'csv'. Refer to https://shiny.rstudio.com/articles/dynamic-ui.html for more.
library(shiny)
ui <- fluidPage(
selectInput(
"select",
label = "File Type",
choices = list("csv", "rda"),
selected = c("csv")
),
conditionalPanel(
condition = "input.select == 'csv'",
radioButtons(
"radio",
label = "Separator",
choices = list("commas", "tabs", "spaces")
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

Resources