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()
}
)
}
)
)
Related
I am working on a data cleaning app. The app is supposed to take a file from the user clean it, and be able to download the cleaned data. For some reason my app will only download the html of the app and not a csv. Any Help would be awesome. Here is what I have so far.
The interface is asking me to add more details but this is all I got
ui.R
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
navbarPage(
"Astute App",
tabPanel(
"Clean Data",
fluidRow(
fileInput('target_upload', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
radioButtons("separator","Separator: ",choices = c(";",",",":"), selected=",",inline=TRUE),
DT::dataTableOutput("sample_table")),
downloadButton("cleaned_data", label = "Download Data"),
),
tabPanel(
"Time Series Analysis",
fluidPage(
)
),
tabPanel(
"Prediction",
fluidPage(
)
),
collapsible = TRUE
)
The interface is asking me to add more details but this is all I got
server.R
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
function(input, output, session){
########Reads in uplaoded Data
df_products_upload <- reactive({
inFile <- input$target_upload
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = input$separator)
return(df)
})
######Clean the data#####
Cleaned_data <- df
download_cleaned_data <- downloadHandler(
filename = Cleaned_data,
content = function(file){
file.copy("data/", file)}
)
###Displays Uploaded data unclean
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
}
Not sure what else to add
A couple of issues in the downloadHandler section. It should look like this:
output$cleaned_data <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_products_upload(), file)}
)
Here is a minimal working example, showing uploading and downloading a file:
library(shiny)
ui <- fluidPage(
#Select file
fileInput('myfileinput', 'Choose file to upload'),
#Download file
downloadButton("myfiledownload", label = "Download file"),
#Data table of loaded file
tableOutput("mydatatable")
)
server <- function(input, output, session) {
#Create a reactive dataframe to hold our loaded file
df_fileuploaded <- reactive({
#If no file selected set the dataframe to null and exit
if (is.null(input$myfileinput)) return(NULL)
#Load the selected file
return(read.csv(input$myfileinput$datapath))
})
#Download handler
output$myfiledownload <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_fileuploaded(), file)}
)
#Data table
output$mydatatable <- renderTable({
df_fileuploaded()
})
}
shinyApp(ui, server)
Here is your full app with those changes:
ui.r
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
navbarPage(
"Astute App",
tabPanel(
"Clean Data",
fluidRow(
fileInput('target_upload', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
radioButtons("separator","Separator: ",choices = c(";",",",":"), selected=",",inline=TRUE),
DT::dataTableOutput("sample_table")),
downloadButton("cleaned_data", label = "Download Data"),
),
tabPanel(
"Time Series Analysis",
fluidPage(
)
),
tabPanel(
"Prediction",
fluidPage(
)
),
collapsible = TRUE
)
server.r
library(shiny)
library(DT)
###Allows up to 60 mgs of data
options(shiny.maxRequestSize = 60*1024^2)
function(input, output, session){
########Reads in uplaoded Data
df_products_upload <- reactive({
inFile <- input$target_upload
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = input$separator)
return(df)
})
output$cleaned_data <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(df_products_upload(), file)}
)
###Displays Uploaded data unclean
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
}
I would like to implement an App which takes a .csv file as input (the user selects the file from his computer), then I want to take this file as a parameter in a function "f" that I've implemented previously.
I can give you the ui.R and server.R
ui.R
library(shiny)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file",
"Put your portfolio data here",
accept=c(".csv")
)
),
mainPanel(tableOutput("table"))
)
))
server.R
library(shiny)
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
read.csv2(file=file1$datapath)
})
#to view the data
output$table <- renderTable({
if(is.null(data())){return ()}
data()
})
})
Finally my function "f" is supposed to give a .csv file as output.
ui.R
library(shiny)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file",
"Put your portfolio data here",
accept=c(".csv")
),
downloadButton(download_data.csv, "Download File")
),
mainPanel(tableOutput("table"))
)
))
server.R
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
read.csv2(file=file1$datapath)
})
#to view the data
output$table <- renderTable({
if(is.null(data())){return ()}
data()
})
# to download the tadata
output$download_data.csv <- downloadHandler(
filename = "download_data.csv",
content = function(file){
data <- data() # At this point you should have done the transformation
# to the data
write.csv(data, file, row.names = F)
}
)
})
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!
I have a function Identify_IP() that returns a list of 1- dataframe
2-ggplot. I need to renderTable and renderPlot in ShinyApp. This shinyApp code renders only the dataframe. But I can't render the plot. Any help?
library(shiny)
source('InflectionP2.R', local = TRUE)
runApp(
list(
ui = fluidPage(
titlePanel("Upload your file"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose xls file',
accept = c(".XLS")),
actionButton("btn", "Update Table"),
actionButton("btn1", "Display Plot"),
downloadButton('downloadData', 'Download')
),
mainPanel(
tableOutput('what'),
plotOutput('pl'))
)
)
,
server = function(input, output, session){
dataOP <- reactive({
inFile <- input$file1
if (is.null(input$file1))
return(NULL)
Identify_IP(read.table(inFile$datapath))
list(tble = df1, txt = inflection_points, plt = p )
})
observeEvent(input$btn, output$what <- renderTable({dataOP()$tble}))
observeEvent(input$btn1, output$pl <- renderPlot({
plot(dataOP()$plt)
}))
}
))
Using the following server worked for me:
server = function(input, output, session){
dataOP <- reactive({
inFile <- input$file1
if(is.null(input$file1)){
return(NULL)
}
#Identify_IP(read.table(inFile$datapath))
list(tble = c(1:20), txt = c(1:10), plt = rnorm(100))
})
observeEvent(input$btn,{
output$what <- renderTable({
dataOP()$tble
})
})
observeEvent(input$btn1,{
output$pl <- renderPlot({
plot(dataOP()$plt)
})
})
}
Note that I commented out your function Identify_IP and replaced the results with arbitrary values.
If this still doesn't work your problem probably is probably related to this function or with the values returned by the function, respectively.
I am trying to upload a file to Shiny to crunch it and then view it.
I already was able to create a table with a CSV document, but the output myData can't be used as an input for a boxplot or any other graph.
SERVER
shinyServer(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()
})
}
UI
library(shiny)
write.csv(data.frame(a = 1:10, b = letters[1:10]), 'test.csv')
shinyUI(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'),
plotOutput('distPlot')
)
)
)
)
How can I use the data from the file I uploaded out of the function myData?
You should use the functions renderDataTable and dataTableOutput from the DT package for rendering your tables. Your code works fine like this:
library(shiny)
library(DT)
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 <- DT::renderDataTable({
DT::datatable(myData())
})
}
write.csv(data.frame(a = 1:10, b = letters[1:10]), 'test.csv')
ui<- shinyUI(fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv'))
),
mainPanel(
DT::dataTableOutput('contents'),
plotOutput('distPlot')
)
)
)
)
shinyApp(ui,server)
Also see the article below:
It is also possible to have an user upload csv's to your Shiny app. The code below shows a small example on how this can be achieved. It also includes a radioButton input so the user can interactively choose the separator to be used.
library(shiny)
library(DT)
# Define UI
ui <- shinyUI(fluidPage(
fileInput('target_upload', 'Choose file to upload',
accept = c(
'text/csv',
'text/comma-separated-values',
'.csv'
)),
radioButtons("separator","Separator: ",choices = c(";",",",":"), selected=";",inline=TRUE),
DT::dataTableOutput("sample_table")
)
)
# Define server logic
server <- shinyServer(function(input, output) {
df_products_upload <- reactive({
inFile <- input$target_upload
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = TRUE,sep = input$separator)
return(df)
})
output$sample_table<- DT::renderDataTable({
df <- df_products_upload()
DT::datatable(df)
})
}
)
# Run the application
shinyApp(ui = ui, server = server)