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])))
})
}
)
Related
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.
Hello Shiny dashboard experts,
Following reprex works.
i.e. Once the file is uploaded in sidebar: mod1,
we can navigate to sidebar: mod2 and see the uploaded data displayed.
Below is the code:
1. Module to display with its UI
2. Module to read data with its UI
Server and UI for calling modules.
Can we automate this ?
i.e. Once the data is uploaded in sidebar: mod1,
sidebar: mod2 should be seen to the user with uploaded data.
library(shiny)
library(tidyverse)
# Module UI to read content
mod_readUI <- function(id) {
ns <- shiny::NS(id)
shiny::tagList(
fileInput(ns("file1"),
h3("Choose xlsx file"),
accept=c(".xlsx")),
actionButton(ns("ref"), "Refresh")
)
}
# Server modules of reading content
mod_read <- function(input, output, session){
# Uploaded data as reactive element
getData <- reactive({
req(input$file1) # Ensure file is uploaded
if(!is.null(input$file1)){
my_data <- readxl::read_excel(input$file1$datapath)
my_data
}
else{
my_data <- "nothing" %>% as.data.frame()
my_data
}
})
### In order to pass data as reactive elements to other module:
# Created list
reactive({
# browser()
list("excl" = getData())
})
}
# Module UI to display content
mod_displayUI <- function(id) {
ns <- shiny::NS(id)
shiny::tagList(
DT::dataTableOutput(ns("contents"))
)
}
# Server functions
mod_display <- function(input, output, session, file) {
output$contents <- DT::renderDataTable({
req(file())
DT::datatable(file()$excl,
options = list(pageLength = 7,scrollX = TRUE))
})
}
ui <-
shinydashboard::dashboardPage(
shinydashboard::dashboardHeader(),
shinydashboard::dashboardSidebar(
shinydashboard::sidebarMenu(id = "menu1",
shinydashboard::menuItem('mod1',
tabName = 'mod1',
icon = shiny::icon('file')),
shinydashboard::menuItem('mod2',
tabName = 'mod2',
icon = shiny::icon('file'))
)),
shinydashboard::dashboardBody(
shinydashboard::tabItems(
shinydashboard::tabItem("mod1",
mod_readUI("sidemod1")),
shinydashboard::tabItem("mod2",
mod_displayUI("bodymod2")
)
)))
server <- function(input, output) {
# storing mod_read in a variable
readFile1 <- shiny::callModule(mod_read, "sidemod1")
# passing the output of readFile into mod_display module
displayFile <- shiny::callModule(mod_display, "bodymod2", file = readFile1)
}
shinyApp(ui,server)
I suppose you can add an observe to see when the sidemod1-file1 input is not NULL or changes. When that happens, you can use updateTabItems. Note you need to have session as a server function argument as well.
server <- function(input, output, session) {
# storing mod_read in a variable
readFile1 <- shiny::callModule(mod_read, "sidemod1")
# passing the output of readFile into mod_display module
displayFile <- shiny::callModule(mod_display, "bodymod2", file = readFile1)
observe({
req(input$`sidemod1-file1`)
updateTabItems(session, "menu1", "mod2")
})
}
I am trying to write my first Shiny App that reads a PDF file, extracts tables and saves it into Excel document.
I am failing to produce suitable code. So far I have:
1) For UI
shinyUI(fluidPage(
titlePanel("CMM Report"),
sidebarPanel(
fileInput("file", "Upload Report")
),
downloadButton("dl", "Download")
))
2) For Server
library(shiny)
library (tabulizer)
library(writexl)
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
file1 <- ExtractTable (file1)
})
## Download
output$dl <- downloadHandler(
filename = function() { "ae.xlsx"},
content = function(file) {write_xlsx(data, path = file)}
)
})
I am not sure If I need to put the code for extracting table in a function and where to call the function, to make it work. Any help REALLY appreciated.
The data file of the example is from here
report <- "http://www.stat.ufl.edu/~athienit/Tables/Ztable.pdf"
Function to extract data
ExtractTable <- function (report){
lst <- extract_tables(report, encoding="UTF-8")
# Delete blank columns
lst[[1]] <- lst[[1]][, -3]
lst[[2]] <- lst[[2]][, -4]
# Bind the list elements
table <- do.call(rbind, lst)
table <- as.data.frame(table[c(2:37, 40:nrow(table)), ],
stringsAsFactors=FALSE) # ...w/o obsolete rows
# Take over colnames, cache rownames to vector
colnames(table) <- table[1, ]
rn <- table[2:71, 1]
table <- table[-1,-1] # and bounce them out of the table
# Coerce to numeric
table <- as.data.frame(apply(table[1:70,1:10], 2,
function(x) as.numeric(as.character(x))))
rownames(table) <- rn
return(table)
}
Could you try:
shinyServer(function(input, output) {
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
ExtractTable(file1$datapath) # $datapath was missing
})
## Download
output$dl <- downloadHandler(
filename = function() { "ae.xlsx"},
content = function(file) {write_xlsx(data(), path = file)} # parentheses () were missing
)
})
I am doing the following:
using R ShinyUI, get client inputs on ranges of variables A, B, C;
in R ShinyServer, read in a csv file, and using the client inputs to slice the csv, and get the portion that I need;
Perform a loop calculation on the csv, calculate various statistics from the loop output, and plot all these statistics.
Pseudo code:
data = read.csv('file.csv')
shinyServer(function(input, output) {
data <- reactive({
data = data[data$A<INPUT1 & data$B> INPUT2 & data$C<INPUT3,]
})
for (i in 1:dim(data)[1]){
result1[i] = xxx
result2[i] = xxx
}
output$plot <- renderPlot({
plot(result1)
})
})
The above code does not work. I want to know:
How to correctly incorporate user input and get the variable "data,"
How to plot result1 and result2 from output$plot
Thanks!
The for loop should be inside a the renderPlot, so each time the input$month changes, the reactive data will change and then the for lop will update your variables. If you have the for loop outside a reactive expression, it will be executed only once when the app starts, but after changes in the input.
Below is simple example based on the pseudo code you provide in your original question to illustrate the possible solution.
library(shiny)
ui <- shinyUI( fluidPage(
fluidRow(
column(4,
numericInput("input1", "Speed >", 8),
numericInput("input2", "Dist >", 15)
),
column(8,
plotOutput("plot")
)
)
))
server <- shinyServer(function(input, output) {
dat0 <- cars
data <- reactive({
dat0[dat0$speed > input$input1 & dat0$dist > input$input2,]
})
output$plot <- renderPlot({
s <- dim(data())[1]
result1 <- numeric(s)
result2 <- numeric(s)
for (i in 1:s){
result1[i] <- data()[i, 1]
result2[i] <- data()[i, 2]
}
plot(result1, result2)
})
})
shinyApp(ui = ui, server = server)
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])))
})
}
)