dealing with an input dataset in R Shiny - r

I'm new to R-Shiny and my question might be very simple. After hours of thinking and searching, I couldn't solve the issue. Here is the problem:
1) My app asks user to upload his dataset.
2) Then in the server file, I read the dataset and I did some analyses and I report back the results into the user interface.
3)My user interface has 4 different out puts.
4) I read the dataset in the "render" function of each output. ISSUE: by doing so, the data is locally defined in the scope of each function which means that I need to read it over again for each output.
5) This is very in-efficient, Is there any alternative? using reactive ?
6) Below is a sample code showing how I wrote my server.R:
shinyServer(function(input, output) {
# Interactive UI's:
# %Completion
output$myPlot1 <- renderPlot({
inFile <- input$file
if (is.null(inFile)) return(NULL)
data <- read.csv(inFile$datapath, header = TRUE)
# I use the data and generate a plot here
})
output$myPlot2 <- renderPlot({
inFile <- input$file
if (is.null(inFile)) return(NULL)
data <- read.csv(inFile$datapath, header = TRUE)
# I use the data and generate a plot here
})
})
How can I just get the input data once and just use the data in my output functions ?
Thanks very much,

You can call the data from the file in a reactive function. It can then be accessed for example as
myData() in other reactive functions:
library(shiny)
write.csv(data.frame(a = 1:10, b = letters[1:10]), 'test.csv')
runApp(list(ui = fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv'))
),
mainPanel(
tableOutput('contents')
)
)
)
, server = function(input, output, session){
myData <- reactive({
inFile <- input$file1
if (is.null(inFile)) return(NULL)
data <- read.csv(inFile$datapath, header = TRUE)
data
})
output$contents <- renderTable({
myData()
})
}
)
)

Related

Shiny plots from user loaded data

I am building a shinydashboard that I want to allow a user to be able to load an excel file and then generate plots and additional output items. The problem I am running into is I can load the data:
ui <- dashboardPage(
dashboardBody(
tabItems(
tabItem(tabName = "data_file",
fluidPage(
titlePanel("Upload_Data_File"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
multiple = TRUE,
accept = c(".xlsx"))
),
mainPanel(
tableOutput('contents'))
),
DT::dataTableOutput("sample_table"))
))))
server <- function(input, output) {
df_products_upload <- reactive({
inFile <- input$file1
if(is.null(inFile))
return(NULL)
file.rename(inFile$datapath,
paste(inFile$datapath, ".xlsx", sep=""))
read_excel(paste(inFile$datapath, ".xlsx", sep=""), 1)
})
output$sample_table <- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
shinyApp(ui = ui, server = server)
If I'd like to do some analysis on this dataframe I can do this inside of the server option:
output$plot <- renderPlot({
data <- df_products_upload() ........ #Some Analysis
data2, data3.... # Items generated during analysis
plot(data2)})
and then complete the analysis inside of the output function and create my additional data frames that will eventually be utilized in calls. But if I want to create multiple output plots that will be generated in the dashboard, is there better efficiency to allow the analysis to be run so future output plots can be generated this way?
output$plot2 <- renderPlot({
plot(data3) })
Currently I can only get it work by duplicating the analysis for all outputs in the server which is very inefficient.
output$plot2 <- renderPlot({
data <- df_products_upload() ........ #Some Analysis
data2, data3.... # Items generated during analysis
plot(data3)})
Thanks!
It seems to me that what you need is
data<-reactive({
data <- df_products_upload() ........ #Some Analysis
data #data should be a vector, list or whatever containg all the itmes
})
and then
output$plot <- renderPlot({
plot(data()[1])
})
output$plot2 <- renderPlot({
plot(data()[2])
})

RShiny diplaying multiple csvs which were uploaded in different manners

I have been referencing the following post which has been tremendously helpful in helping me understand Rshiny functionality:
How can I update plot from rhandsontable with uploaded data, without clicking into the table first?
I am still having some trouble grasping the concept of "Observe" so that may be the issue here. I want to upload 2 csvs where one is static (saving it in a separate tab) and one that can be edited (with edits reflected in the corresponding plot after hitting a button). My end goal is to be able to plot these data sets together on the same axes, but for now, I am having difficulty getting my table display which makes me think it's not uploading properly. I am using the following code:
library(shiny)
library(rhandsontable)
#sample data
year <- substr(Sys.Date(),1,4)
empty_dat=as.data.frame(matrix(1,nrow = 3,ncol = 4,dimnames = list(c("Cat A", "Cat B", "Cat C"),
c(paste("May",year),paste("June",year),paste("July",year),
paste("August",year)))))
ui = fluidPage(sidebarLayout(
sidebarPanel(
#static data input
fileInput('file1_new', 'Choose CSV File'),
#reactive data inut
fileInput('file1', 'Choose CSV File'),
#display reactive data
rHandsontableOutput('contents'),
actionButton("go", "Plot Update"),
width=7
),
mainPanel(
tabsetPanel(
#plot reactive data first tab
tabPanel("Plot", plotOutput("plot1")),
#table static data second tab
tabPanel("Table", tableOutput("table"))
)
)
))
server = function(input, output) {
#static input
output$table <- renderTable({
inFile <- input$file_new
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header,
sep = input$sep, quote = input$quote)
})
indat <- reactiveValues(data=empty_dat)
#reactive input
observe({
inFile = input$file1
if (is.null(inFile))
return(NULL)
data1 = read.csv(inFile$datapath)
indat$data <- data1
})
observe({
if(!is.null(input$contents))
indat$data <- hot_to_r(input$contents)
})
output$contents <- renderRHandsontable({
rhandsontable(indat$data)
})
#***example uses only one column-why I attempt multiple columns (indat$data[,1:4],indat$data[],indat$data) I get an error
#update data when user hits button
test <- eventReactive(input$go, {
return(indat$data[,3])
})
output$plot1 <- renderPlot({
#plot updated data
plot(test(),type = "l")
})
}
shinyApp(ui, server)
Any help would be greatly appreciated.
I made few changes to the code, and now the second tab displays the static table.
I am not sure if this is what you want but here's the code. The changes that I made are below the code.
library(shiny)
library(rhandsontable)
#sample data
year <- substr(Sys.Date(),1,4)
empty_dat=as.data.frame(matrix(1,nrow = 3,ncol = 4,dimnames = list(c("Cat A", "Cat B", "Cat C"),
c(paste("May",year),paste("June",year),paste("July",year),
paste("August",year)))))
ui = fluidPage(sidebarLayout(
sidebarPanel(
#static data input
fileInput('file1_new', 'Choose CSV File'),
#reactive data inut
fileInput('file1', 'Choose CSV File'),
#display reactive data
rHandsontableOutput('contents'),
actionButton("go", "Plot Update"),
width=7
),
mainPanel(
tabsetPanel(
#plot reactive data first tab
tabPanel("Plot", plotOutput("plot1")),
#table static data second tab
tabPanel("Table", tableOutput("table"))
)
)
))
server = function(input, output) {
#static input
output$table <- renderTable({
inFile <- input$file1_new
if (is.null(inFile))
{return(mtcars)}
else{
read.csv(inFile$datapath)}
})
indat <- reactiveValues(data=empty_dat)
#reactive input
observe({
inFile = input$file1
if (is.null(inFile))
return(NULL)
data1 = read.csv(inFile$datapath)
indat$data <- data1
})
observe({
if(!is.null(input$contents))
indat$data <- hot_to_r(input$contents)
})
output$contents <- renderRHandsontable({
rhandsontable(indat$data)
})
#***example uses only one column-why I attempt multiple columns (indat$data[,1:4],indat$data[],indat$data) I get an error
#update data when user hits button
test <- eventReactive(input$go, {
return(indat$data[,3])
})
output$plot1 <- renderPlot({
#plot updated data
plot(test(),type = "l")
})
}
shinyApp(ui, server)
So in the part where you do the renderTable, the variable name was slightly wrong :p, and in the read.csv, there were too many arguments.
output$table <- renderTable({
inFile <- input$file1_new
if (is.null(inFile))
{return(mtcars)}
else{
read.csv(inFile$datapath)}
})
Please let me know if this works for you... Cheers!

Retrieve file information (name, size, rows and cols number) in Shiny R

I need a shiny app to retrieve some file information as filename, size, numbers of rows and columns. My final ideia it is to build a box that automatically shows the metadata and if I import another dataset, it updates too. The original code I found here, but I tried to modify. Any help? I am new in Shiny R.
ui <- fluidPage(
titlePanel("Grabbing my file name"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Select your file",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv",".xlsx")),
),
mainPanel(
textOutput("myFileName"),
textOutput("myFileSize"),
textOutput("myFileRow"),
textOutput("myFileCol"),
)
)
)
server <- function(input, output) {
file_name <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return(NULL)
}else{
return (inFile$name)
}
})
output$myFileName <- renderText({ file_name() })
file_size <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return(NULL)
}else{
return (file.size(inFile$name))
}
})
output$myFileSize <- renderText({ file_size() })
file_row <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return(NULL)
}else{
return (nrow(inFile))
}
})
output$myFileRow <- renderText({ file_row() })
file_col <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return(NULL)
}else{
return (ncol(inFile))
}
})
output$myFileCol <- renderText({ file_col() })
}
# Run the application
shinyApp(ui = ui, server = server)
We need to read the dataset to get the ncol/nrow. It would be more efficient to read the data once and get the ncol/nrow (here we used dim to get that instead of repeating ncol/nrow.
library(shiny)
-ui
ui <- fluidPage(
titlePanel("Grabbing my file name"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Select your file',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)
)
),
mainPanel(
textOutput("myFileName"),
textOutput("myFileSize"),
textOutput("myFileColrow")
)
)
)
-server
server <- function(input, output) {
file_name <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL) else return (tools::file_path_sans_ext(inFile$name))
})
file_colrowsize <- reactive({
inFile <- input$file1
if (is.null(inFile)){
return(NULL)
}else{
tmp <- read.csv(inFile$datapath)
return (list(dim(tmp), object.size(tmp)))
}
})
output$myFileName <- renderText({ file_name() })
output$myFileColrow <- renderText({ file_colrowsize()[[1]] })
output$myFileSize <- renderText({file_colrowsize()[[2]]})
}
-Run the application
shinyApp(ui = ui, server = server)
Output from running
NOTE: We could also combine the two reactive into a single one and then return a list with 3 elements - 1) file name, 2) file size 3) dimensions
I know you said you want an R solution, but I think your options are pretty limited if you only consider this. How about an Excel-VBA solution. Go to the link below and download the sample file. That should do all you want, and a whole lot more.
http://learnexcelmacro.com/wp/2011/11/how-to-get-list-of-all-files-in-a-folder-and-sub-folders/

Shiny server functions with 2 outputs

I'm trying to return two tables based on one input. Basically, I'm reading in a CSV and I want to display the values in the CSV in a table, then in a second table display a count of the number of rows in the CSV.
Right now I have
ui.R
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
mainPanel(
tableOutput("rawData"),
tableOutput("rawDataSize")
)
)
)
and server.R
server <- function(input, output) {
output$rawData <- renderTable({
inFile <- reactive({input$file1})
data <- reactive({
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header)
})
})
output$rawDataSize <- renderTable({
dim(data)[1]
})
}
Unfortunately, this returns Warning: Error in as.data.frame.default: cannot coerce class "c("reactiveExpr", "reactive")" to a data.frame
Move inFile <- reactive({input$file1}) outside of renderTable. Then, to use this reactive object, you need to treat it like a function. inFile()$datapath. Same for your data reactive object.
So, your server() ends up looking something like:
server <- function(input, output) {
inFile <- reactive({input$file1})
data <- reactive({
if (is.null(inFile())) return(NULL)
read.csv(inFile()$datapath, header = input$header)
})
output$rawData <- renderTable({
data()
})
output$rawDataSize <- renderTable({
dim(data())[1]
})
}
1- A reactive is a function, so always add () when calling it.
2- Avoid nesting reactives:
server <- function(input, output) {
inFile <- reactive(input$file1)
data <- reactive({
if (is.null(inFile()))
return(NULL)
read.csv(inFile()$datapath, header = input$header)
})
output$rawData <- renderTable(data())
output$rawDataSize <- renderTable(dim(data())[1])
}

Downloading pdf plot using shiny app after reading excel files

As, I am new to shiny apps need some assistance, uploading excel file and generating table output in shiny app works fine, but can't able to download the plot to a pdf format
Here is my code
library(shiny)
library(openxlsx)
library(lattice)
runApp(
list(
ui = fluidPage(
titlePanel("plots"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")),
tags$hr(),
downloadButton('down',"download plot")
),
mainPanel(
tableOutput('contents'),
plotOutput('plot'))
)
),
server = function(input, output){
output$contents <- renderTable({
inFile <- input$file1
if(is.null(inFile))
return(NULL)
else
read.xlsx(inFile$datapath)
})
plotInput <- reactive({
df <- input$file1
xyplot(df[,2]~df[,1],df(),xlim=c(0,10),ylim=c(0,100),type = "b")
})
output$plot <- renderPlot({
print(plotInput())
})
output$down <- downloadHandler(
filename = function(){paste("plot",".pdf",sep=".") },
content = function(file) {
pdf(file)
xyplot(df[,2]~df[,1],df(),xlim=c(0,10),ylim=c(0,100),type = "b")
dev.off()
}
)
}
)
)
The problem was that in some parts of your code you were accessing a dynamic data frame via df() but you had never defined it.
In this kind of problem, it is best to create a reactive data frame, say, df which contains the uploaded data and is passed to other reactive parts of the code via df().
Full example:
library(shiny)
library(openxlsx)
library(lattice)
runApp(
list(
ui = fluidPage(
titlePanel("plots"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")),
tags$hr(),
downloadButton('down',"download plot")
),
mainPanel(
tableOutput('contents'),
plotOutput('plot'))
)
),
server = function(input, output){
df <- reactive({
inFile <- input$file1
req(inFile) # require that inFile is available (is not NULL)
# (a user has uploaded data)
# read.xlsx(inFile$datapath)
head(iris, 10)
})
output$contents <- renderTable({
# access uploaded data via df()
df()
})
plotInput <- reactive({
df <- df()
xyplot(df[,2]~df[,1], df ,xlim=c(0,10),ylim=c(0,100),type = "b")
})
output$plot <- renderPlot({
plotInput()
})
output$down <- downloadHandler(
filename = function(){paste("plot",".pdf",sep=".") },
content = function(file) {
pdf(file)
#xyplot(df[,2]~df[,1],df(),xlim=c(0,10),ylim=c(0,100),type = "b")
# you have to print the plot so that you can open pdf file
print(plotInput())
dev.off()
}
)
}
)
)

Resources