R Shiny: Perform a series of functions on reactive input - r

I want to perform a series of tasks on a data.frame that will be loaded by the user via actionButton. Here is an example where I want to remove rows with NAs in the third column of the data.frame selected by the user. I get the error:
"Warning: Error in observeEventHandler: object 'df' not found
Stack trace (innermost first):
65: observeEventHandler [(file location).R#56]"
Why doesn't observeEvent recognize the variable f?
Server.R
library(shiny)
shinyServer <- function(input, output) {
filedata <- reactive({
infile <- input$Samples
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
df <- read.table(infile$datapath,sep="\t",skip =0, header = TRUE,na.strings = "NA",stringsAsFactors=FALSE)
})
observeEvent(input$Click, {
selectA <- df[complete.cases(f[,3]),]
}
}
ui.R
library(shiny)
shinyUI( <- fluidPage(
tabPanel("Inputs",
wellPanel(fileInput(inputId = "Samples", label = "Import File"),
actionButton(inputId = "Click", label = "Samples")),
h2('Results'),
dataTableOutput("Results")))

Maybe I didn't do a good job of articulating my question. Here is the answer that I was looking for.
Server.R
library(shiny)
shinyServer <- function(input, output) {
filedata <- reactive({
infile <- input$Samples
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.table(infile$datapath,sep="\t",skip =0, header = TRUE,na.strings = "NA",stringsAsFactors=FALSE)
})
observeEvent(input$Click, {
df <- filedata()
selectA <- df[complete.cases(df[,3]),]
}
}

Related

Downloading the outputs of a reactive table in R shiny

I have an R shiny app that gets a .csv import from a user and searches the imported data across a built-in data frame, then gives the % match in the output. The UI is very simple, with a few different inputs (import .csv, a slider, and some radio buttons). What I want is to be able to take the reactive table output and print this to a .csv that the user can download to their machine. The server side of the app looks something like this:
server <- function(input, output){
rvals <- reactiveValues()
observeEvent(input$file_1,{
req(input$file_1)
rvals$csv <<- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
if(input$select == 1){
x <- function
}else if(input$select == 2){
x <- function
}else if(input$select == 3){x <- function}
#some more data processing and formatting here
return(x)
},digits = 4)
}
I would like to have the data table x be able to become a .csv that can be downloaded by clicking a download button. In the server, I added the following code, but when I try to download the data it just downloads a blank file and says "SERVER ERROR" in my downloads manager on my machine.
output$downloadData <- downloadHandler(
filename = "thename.csv",
content = function(file){
write.csv(x, file)
}
In the console I also get the error message:
Warning: Error in is.data.frame: object 'x' not found [No stack trace available]
The object you create inside the expression of renderTable is not available outside of it. Instead you could assign it to the reactive values you set up. Below is a working example (note that I have tried to replicate your code so the data will not be available until you click on "Upload CSV", which here just calls mtcars).
library(shiny)
ui = fluidPage(
sidebarPanel(
actionButton(inputId = "uploadCsv", label = "Upload CSV:", icon = icon("upload")),
selectInput(inputId = "preProc", label = "Pre-processing", choices = c("Mean"=1,"Sum"=2)),
downloadButton("downloadData", label = "Download table")
),
mainPanel(
h4("My table:"),
tableOutput("contents")
)
)
server <- function(input, output) {
rvals <- reactiveValues(
csv=NULL,
x=NULL
)
observeEvent(input$uploadCsv,{
rvals$csv <- mtcars # using example data since I don't have your .csv
# rvals$csv <- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
# Assuing the below are functions applied to your data
req(
input$preProc,
!is.null(rvals$csv)
)
if(input$preProc == 1){
rvals$x <- data.frame(t(colMeans(mtcars)))
}else {
rvals$x <- data.frame(t(colSums(mtcars)))
}
return(rvals$x)
},digits = 4)
output$downloadData <- downloadHandler(
filename = "myFile.csv",
content = function(file){
write.csv(rvals$x, file)
}
)
}
shinyApp(ui,server)
EventReactive already outputs a reactive value, you don't need to create an extra reactiveVal, see example below :
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Test"),
mainPanel(
actionButton("show", "Download"),
textOutput("result")
)
)
server <- function(input, output) {
csvfile <- eventReactive(req(input$show), ignoreNULL = T, {
"Content of file"
})
output$result <- reactive(
paste("result : ",csvfile()))
}
# Run the application
shinyApp(ui = ui, server = server)
I would also avoid to use <<-operator in a reactive expression.

Unexpected behavior of req()

I experienced an unexpected behavior of my R shiny code and I'm asking myself if this is bug or if I don't understand how req() works.
I have an app where the user first uploads a *.txt file containing data with a location id, a date, and other data. Then the user has to choose two numerical values. The data is checked for NAs in the col date. If there are no NAs a text should appear telling the user everything is fine.
Below are two versions of my code. In output$txt <- renderText({ I use req() to test if all inputs are set and the file is loaded.
The differences between the two codes are the ordering of the last two arguments in req. Whereas in the first version, the green text appears already when both numeric inputs are set even the file is not uploaded, the second code behaves as expected; the user has to choose the numeric value and has to choose a file before the green bar with text appears.
Why makes the ordering of the arguments in req() a difference?
Code 1:
library(shiny)
library(lubridate)
# UI
ui <- fluidPage(
fluidRow(
column(4,
wellPanel(
fileInput("file1", label = h4("file upload")),
numericInput("in1", label = h4("first input"),value = 2.5, step=0.5),
numericInput("in2", label = h4("second input"),value = NULL, step=0.5)
)
),
column(8,
h4(textOutput("txt"), tags$style(type="text/css", "#txt {vertical-align:top;align:center;color:#000000;background-color: #4cdc4c;}")),
h2(""),
textOutput("fileinfo"),
tableOutput("tab_data")
)
)
)
# SERVER
server <- function(input, output) {
output$txt <- renderText({
req(input$in1, input$in2, fl_data(), input$file1)
"your data is ok and you have chosen input 1 and 2"
})
fl_data <- reactive({
validate(
need(input$file1 != "", "upload data and choose input 1 and 2...")
)
inFile <- input$file1
if (is.null(inFile)) {
return(NULL)
} else {
dd <- read.table(inFile$datapath, sep=";", stringsAsFactors=FALSE, header=TRUE)
dd[,2] <- ymd(dd[,2])
if (sum(is.na(dd[,2]))>0) dd <- NULL
}
})
output$tab_data <- renderTable({head(fl_data()[,1:4])})
output$fileinfo <- renderPrint({input$file1})
}
# Run the application
shinyApp(ui = ui, server = server)
Code 2:
library(shiny)
library(lubridate)
# UI
ui <- fluidPage(
fluidRow(
column(4,
wellPanel(
fileInput("file1", label = h4("file upload")),
numericInput("in1", label = h4("first input"),value = 2.5, step=0.5),
numericInput("in2", label = h4("second input"),value = NULL, step=0.5)
)
),
column(8,
h4(textOutput("txt"), tags$style(type="text/css", "#txt {vertical-align:top;align:center;color:#000000;background-color: #4cdc4c;}")),
h2(""),
textOutput("fileinfo"),
tableOutput("tab_data")
)
)
)
# SERVER
server <- function(input, output) {
output$txt <- renderText({
req(input$in1, input$in2, input$file1, fl_data())
"your data is ok and you have chosen input 1 and 2"
})
fl_data <- reactive({
validate(
need(input$file1 != "", "upload data and choose input 1 and 2...")
)
inFile <- input$file1
if (is.null(inFile)) {
return(NULL)
} else {
dd <- read.table(inFile$datapath, sep=";", stringsAsFactors=FALSE, header=TRUE)
dd[,2] <- ymd(dd[,2])
if (sum(is.na(dd[,2]))>0) dd <- NULL
}
})
output$tab_data <- renderTable({head(fl_data()[,1:4])})
output$fileinfo <- renderPrint({input$file1})
}
# Run the application
shinyApp(ui = ui, server = server)
req short-circuits, just like the && and || operators. As soon as it comes across an unavailable value (args evaluated left-to-right), it stops the reactive chain and doesn't care about any further args.
In the second example, input$file1 prevents fl_data() from ever executing if missing, so the validation in fl_data never occurs. But rather than order the req args like in the first example, I would just remove the check for input$file1 in output$txt, as it's already being checked in fl_data.

How to generate dataTableOutput dynamically by reading the .csv files in a loop in R shiny?

I have a function that generates "n" dataframes and saves it in a location as csv files and the function returns the file name of the saved CSVs.
I wish to take those csv files, read it using read.csv() and then display it on the UI using renderUI and renderDataTable()
While the code below has no syntax errors, but nothing is getting displayed on the screen.
Please suggest an appropriate method by which the tables generated in one part of the server.R can be used in output and display those data tables on the UI.
The code for the function is below :
Function
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
#--------------------------------------------------------------------
FilePath <- "D:/FolDerName/"
FullPath<-WriteStatement <- NULL
for(i in 1:NumOfDataFrames){
FullPath[i]<-paste0(FilePath,"sampleDat",i,".csv")
WriteStatement[i]<-paste0("write.csv(sampleDat",i,",file = '",FullPath[i],"')")
eval(parse(text=WriteStatement[i]))
}
return(FullPath)
}
The UI.r
library(shiny)
shinyUI(
fluidPage(
# Application title
navbarPage("Sample Data Display",
tabPanel("Data",
sidebarLayout(
sidebarPanel(
titlePanel("Sample"),
numericInput("sample1",label = "Some Label",value = 20),
numericInput("sample2",label = "Some Other Label",value = 20)
),
mainPanel(
uiOutput("result")
)
)
)
)
)
)
The server.R
library(shiny)
GenerateData <- function(){
#********************************************************************
# already mentioned above, please copy the contents to server.R
#--------------------------------------------------------------------
}
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
dataTab1<-NULL
MyFilePath <- dataSrc()
for (i in 1:length(MyFilePath)){
dataTab1 <- read.csv(MyFilePath[i])
# print(dataTab1)
renderDataTable(dataTab1)
dataTab1<-NULL
}
})
}
)
You can try
1) use list of df
GenerateData <- function(){
#********************************************************************
# some sample data (originally, my data comes from an external souce)
#--------------------------------------------------------------------
a <- 1:10
b<- 21:30
c<-41:50
sampleDat1 <- data.frame(a,b,c)
sampleDat2<- data.frame(c,a,b,a)
NumOfDataFrames <- 2
ls_df=list(sampleDat1,sampleDat2)
names(ls_df)=c("sampleDat1","sampleDat2")
#--------------------------------------------------------------------
FilePath <- "C:\\12324\\files\\"
FullPath=character()
for(i in 1:length(ls_df)){
FullPath[i]<-paste0(FilePath,names(ls_df)[i],".csv")
write.csv(x=ls_df[[i]],file = FullPath[[i]])
}
return(FullPath)
}
2) Server.R( create dinamic ui and render DT in two step)
shinyServer(function(input, output,session) {
dataSrc <- reactive({
paths <- GenerateData()
return(paths)
})
output$result <- renderUI({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i)dataTableOutput(paste0('tbl',i)))
})
observe({
MyFilePath <- dataSrc()
lapply(1:length(MyFilePath),function(i) output[[paste0("tbl",i)]]<-renderDataTable(read.csv(MyFilePath[i])))
})
}
)

shiny fileinput r dataframe

Using R shiny, I am developing a simple app that allows user to input data from a file. With csv or txt files everything works fine, but I can not make R dataframes to load.
## SERVER.R
shinyServer(function(input, output) {
infile <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
infile<load(input$datafile$datapath)
})
myData <- reactive({
df<-infile()
if (is.null(df)) return(NULL)
})
output$value1 <- renderPrint({
names(iris)
})
output$value2 <- renderPrint({
names(myData())
})
load("iris.Rdata") ## data loaded for testing
})
## UI.R
shinyUI(fluidPage(
fileInput("datafile", label = h3("File input")),
fluidRow(column(4, verbatimTextOutput("value1"))),
fluidRow(column(4, verbatimTextOutput("value2")))
))
When I run this app I can see the names of the iris dataset loaded only for testing, but respect the names of the loaded file (which should be rendered as value2) only shows "NULL"
Any help?? thanks in advance!
I think this is what you want. You had a couple of typos, and you probably didn't quite understand what load actually does, it loads a set of objects into memory.
I did the following things:
added some initialization code to save a couple of .Rdata for testing, they both have exactly one object in them, a dataframe. The code needs this.
add a line to parse out the first object in that loaded datafile and return it
Here is the code:
server.r
## SERVER.R
#Initialization
library(datasets)
save(iris,file="iris.Rdata")
save(mtcars,file="m.Rdata")
shinyServer(function(input, output) {
infile <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
objectsLoaded <- load(input$datafile$name)
# the above returns a char vector with names of objects loaded
df <- eval(parse(text=objectsLoaded[1]))
# the above finds the first object and returns it
return(df)
})
myData <- reactive({
df<-infile()
if (is.null(df)) return(NULL)
return(df)
})
output$value1 <- renderPrint({
names(iris)
})
output$value2 <- renderPrint({
names(myData())
})
load("iris.Rdata") ## data loaded for testing
})
ui.r
## UI.R
shinyUI(fluidPage(
fileInput("datafile", label = h3("File input")),
fluidRow(column(4, verbatimTextOutput("value1"))),
fluidRow(column(4, verbatimTextOutput("value2")))
))
Here is the output:

Using read.xlsx in Shiny R App

I am trying to load an excel file and display the summary. The file is loading without any errors but not displaying anything.
Here is my code
ui.R
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Analysis"),
sidebarPanel(wellPanel(fileInput('file1', 'Choose XLSX File',
accept=c('sheetName', 'header'), multiple=FALSE))),
mainPanel(
tabsetPanel(
tabPanel("Tab1",h4("Summary"), htmlOutput("summary"))
)))
server.R
library(shiny)
shinyServer(function(input, output) {
dataset = reactive({
infile = input$file1
if (is.null(infile))
return(NULL)
infile_read = read.xlsx(infile$datapath, 1)
return(infile_read)
})
output$summary <- renderPrint({
summary = summary(dataset())
return(summary)
})
outputOptions(output, "summary", suspendWhenHidden = FALSE)
})
I haven't tested this, but it looks like you're not actually returning anything from dataset(). Change the function to:
dataset = reactive({
infile = input$file1
if (is.null(infile))
return(NULL)
read.xlsx(infile$datapath, 1)
})
When you do infile_read = read.xlsx(infile$datapath, 1), you're reading the file into infile_read but then you're not actually returning it. Reactives work just look any R function really. Try running this:
f <- function() x <- 10
f()
You should see that f() doesn't return anything. All it's doing is making an assignment that goes nowhere. To actually return 'hello' you would do:
f <- function() {
x <- 'hello'
x
}
Or just:
f <- function() 'hello'

Resources