ObserveEvent in shiny app does not work with fileInput - r

my shiny example does not work with the observeEvent and I don't know how to fix it !
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File"),
checkboxInput("header", "Header", TRUE)
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output) {
myfile <- reactive({
if(is.null(input$file1)){return(NULL)}
f = read.csv(input$file1$datapath, header = input$header)
print(nrow(f))
return(f)
})
observeEvent(input$file1,{
if (nrow(myfile()) > 100){
shinyalert("error","file too long",type = "error")
}
},ignoreNULL = FALSE)
output$contents <- renderTable({
myfile()
})
}
shinyApp(ui, server)
I know that can be replaced by something like validate instead of shinyalrert and observeEvent, but I'm looking for a solution with observeEvent!

Related

Render table when user uploads csv file

I was wondering how to create a table with all the data from the user's csv file. I would like the data to be uploaded into a tabPanel. Currently, I am running into the issue that no data is being displayed.
library(shiny)
ui <- fluidPage(
navbarPage("Dashboard",
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose .csv file", #add red asterisks to make this mandatory
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"),
),
),
mainPanel(
tabsetPanel(
tabPanel("Data",
tableOutput("tableOne"))
)
)
)
)
)
)
server <- function(input,output){
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath)
})
output$filedf <- renderTable({
if(is.null(data())){return ()}
input$file
})
output$tableOne <- renderTable({
if(is.null(data())){return ()}
data()
})
output$data <- renderTable(output$tableOne)
}
shinyApp(ui,server)
I'm not sure why the output$data <- renderTable(output$tableOne is not allowing the data to be displayed.
The input should match i.e. file1 is the input and not just file
library(shiny)
ui <- fluidPage(
navbarPage("Dashboard",
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose .csv file", #add red asterisks to make this mandatory
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"),
),
),
mainPanel(
tabsetPanel(
tabPanel("Data",
tableOutput("tableOne"))
)
)
)
)
)
)
server <- function(input,output){
data <- reactive({
req(input$file1)
file1 <- input$file1
if(is.null(file1)){return()}
read.table(file=file1$datapath)
})
output$tableOne <- renderTable({
req(input$file1)
if(is.null(data())){return ()}
data()
})
#output$data <- renderTable(output$tableOne)
}
shinyApp(ui,server)
-output

How to show example data and then update user's data in shiny?

Here is an example. What I wanted is to display the example data if user click Show example or will display the data uploaded by user.
df<-data.frame(x=rnorm(9),
y=rnorm(9),
z=rnorm(9))
write.table(df, "test.txt", quote=F)
library(shiny)
ui <- shinyUI(pageWithSidebar(
headerPanel("test"),
sidebarPanel(
actionButton("evReactiveButton", "Show example"),
fileInput("file1", "Upload File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv"))
),
mainPanel(
tableOutput("matrix")
)
))
server <- function(input, output, session) {
#if action button show example
datobj<-reactive({
dat<-matrix(1:100, nrow=10)
return(dat)
})
#if user upload
datobj <- reactive({
req(input$file1)
dat <- read.table(input$file1$datapath)
return(dat)
})
### matrix file
output$matrix <- renderTable({
return(datobj())
})
}
shinyApp(ui=ui,server=server)
Here's one way to do it using observeEvent. I added an actionButton to switch more easily between the example data (not reactive here) and the data the user imports. If you want to remove this button, don't forget to replace also the second observeEvent environment by observe.
df<-data.frame(x=rnorm(9),
y=rnorm(9),
z=rnorm(9))
write.table(df, "test.txt", quote=F)
library(shiny)
ui <- shinyUI(pageWithSidebar(
headerPanel("test"),
sidebarPanel(
actionButton("example", "Show example"),
fileInput("file1", "Upload File",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
actionButton("import", "Show data imported")
),
mainPanel(
tableOutput("matrix")
)
))
server <- function(input, output, session) {
#if action button show example
datobj<- mtcars
#if user upload
datobj2 <- reactive({
req(input$file1)
dat <- read.table(input$file1$datapath, sep = " ")
return(dat)
})
### matrix file
observeEvent(input$example, {
output$matrix <- renderTable({
datobj
})
})
observeEvent(input$import, {
if (!is.null(datobj2())){
output$matrix <- renderTable({
datobj2()
})
}
else {}
})
}
shinyApp(ui=ui,server=server)

module for inputting csv/tsv/txt files in rshiny

I am developing a R Shiny application which will rely on a module in hopes that I can re-use the module for uploading and displaying two different data sets. As of now, my code works but I think I could make it a little bit cleaner as I don't think I have gotten the module correct. By that I mean, how do I move this code snippet (below) out of the app_server and into the module server and then use the callModule function for two different datasets. Similarly, I probably need to remove this code: tableOutput("metacontent") from the app ui and have that call in the module ui. See the module ui, module server, app ui, and app server below code snippet. Any suggestions? Thanks!
#code snippet
output$metacontents <- renderTable({
metafile()
})
# Module UI
mod_dataInput_ui <- function(id, label) {
# Create a namespace function using the provided id
ns <- NS(id)
tagList(
# Input: Select a file ----
fileInput(ns("id"), label,
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv",
".tsv")),
# Input: Select separator ----
radioButtons(ns("sep"), "Separator",
choices = c(Comma = ",",
Tab = "\t"),
selected = "\t"))
}
# Module Server
mod_dataInput_server <- function(input, output, session) {
userFile <- reactive({
validate(need(input$id !="", "Please import a data file"))
input$id
})
datafile <- reactive({
utils::read.table(userFile()$datapath,
header = FALSE,
sep = input$sep,
row.names = NULL,
skip = 1,
stringsAsFactors = FALSE)
})
}
#App UI
app_ui <- function() {
tagList(
# Leave this function for adding external resources
golem_add_external_resources(),
# List the first level UI elements here
navbarPage("Tinsel",
tabPanel("Load Data",
sidebarPanel(mod_dataInput_ui("dataInput_ui_meta", tags$div("User META data", tags$br(), "(.csv, .tsv, or .txt file format)")), helpText("Can add help text here"),
# Horizontal line ----
tags$hr(style="border-color: black;"),
mod_dataInput_ui("dataInput_ui_gene", tags$div("User GENETIC data", tags$br(), "(.csv, .tsv, or .txt file format)")),
tags$hr(style="border-color: black;")),
mainPanel(
tabsetPanel(
tabPanel("Meta Data",
tableOutput("metacontents")),
tabPanel("Genetic Data",
tableOutput("genecontents"))
)))
)
)
}
#App server
app_server <- function(input, output, session) {
# List the first level callModules here
metafile <- callModule(mod_dataInput_server, "dataInput_ui_meta")
output$metacontents <- renderTable({
metafile()
})
genefile <- callModule(mod_dataInput_server, "dataInput_ui_gene")
output$genecontents <- renderTable({
genefile()
})
}
As far as I see it, you've gotten the module correctly: you're reusing the UI and server on two different IDs for the data import.
You can optimize what you've done by creating a module for the table part, so writing:
# mod_table.R
mod_table_ui <- function(id, name){
ns <- NS(id)
tabPanel(
name,
tableOutput(ns("metacontents"))
)
}
# Module Server
#' #rdname mod_table
#' #export
#' #keywords internal
mod_table_server <- function(input, output, session, file){
ns <- session$ns
output$metacontents <- renderTable({
file()
})
}
And then in app_ui:
#' #import shiny
app_ui <- function() {
tagList(
# Leave this function for adding external resources
golem_add_external_resources(),
# List the first level UI elements here
navbarPage(
"Tinsel",
tabPanel(
"Load Data",
sidebarPanel(
mod_dataInput_ui(
"dataInput_ui_meta",
tags$div(
"User META data",
tags$br(),
"(.csv, .tsv, or .txt file format)"
)
),
helpText("Can add help text here"),
# Horizontal line ----
tags$hr(style="border-color: black;"),
mod_dataInput_ui(
"dataInput_ui_gene",
tags$div(
"User GENETIC data",
tags$br(),
"(.csv, .tsv, or .txt file format)"
)
),
tags$hr(style="border-color: black;")
),
mainPanel(
tabsetPanel(
mod_table_ui("table_ui_1", "Meta Data"),
mod_table_ui("table_ui_2", "Genetic Data")
)
)
)
)
)
}
And app_server:
app_server <- function(input, output, session) {
# List the first level callModules here
metafile <- callModule(mod_dataInput_server, "dataInput_ui_meta")
callModule(mod_table_server, "table_ui_1", metafile)
genefile <- callModule(mod_dataInput_server, "dataInput_ui_gene")
callModule(mod_table_server, "table_ui_2", genefile)
}
Let me know if that answers your question.
This is how I would do it.
library(shiny)
library(ggplot2)
#ui.R
ui <- fluidPage(
titlePanel("My shiny app"), sidebarLayout(
sidebarPanel(
helpText("This app shows how a user can upload a csv file. Then, plot the data.
Any file can be uploaded but analysis is only available
if the data is in same format as the sample file, downloadable below
"),
a("Data to be plotted", href="https://www.dropbox.com/s/t3q2eayogbe0bgl/shiny_data.csv?dl=0"),
tags$hr(),
fileInput("file","Upload the file"),
h5(helpText("Select the read.table parameters below")),
checkboxInput(inputId = 'header', label = 'Header', value = TRUE),
checkboxInput(inputId = "stringAsFactors", "stringAsFactors", FALSE),
br(),
radioButtons(inputId = 'sep', label = 'Separator', choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ',')
),
mainPanel(
uiOutput("tb"),
plotOutput("line")
)
)
)
#server.R
server <- function(input,output){
data <- reactive({
file1 <- input$file
if(is.null(file1)){return()}
read.table(file=file1$datapath, sep=input$sep, header = input$header, stringsAsFactors = input$stringAsFactors)})
output$filedf <- renderTable({
if(is.null(data())){return ()}
input$file
})
output$sum <- renderTable({
if(is.null(data())){return ()}
summary(data())
})
output$table <- renderTable({
if(is.null(data())){return ()}
data()
})
output$line <- renderPlot({
if (is.null(data())) { return() }
print(ggplot(data(), aes(x=date, y=aa)) + geom_line()+ facet_wrap(~station)) })
output$tb <- renderUI({if(is.null(data()))
h5()
else
tabsetPanel(tabPanel("About file", tableOutput("filedf")),tabPanel("Data", tableOutput("table")),tabPanel("Summary", tableOutput("sum")))
})
}
shinyApp(ui = ui, server = server)

Merge the uploaded csv with the current data frame in r shiny

The example that I'm working with is the iris data. If the current data contains iris[1:15,], how can I upload a .csv file with more iris data and click a button to combine the uploaded data with the current data and save everything in one dataframe?
Here is what I have so far based on what I've read. I was able to create the fileInput and action button but I think my issue is with the reactive button. I'm not sure how to use it properly to achieve what I need.
library(shiny)
library(DT)
data1<-data.frame(iris[1:15,])
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
numericInput('num','Number of rows',value=10,min=0),
actionButton("update", "Combine Data")),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output) {
output$table <- renderTable({
head(data1,n=input$num)
})
x<-reactive({
req(input$file1)
df_uploaded <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote,
stringsAsFactors = FALSE)
data2<-data.frame(df_uploaded)
return(data2)
})
merged_data<-eventReactive(input$update,{
datam<-rbind.data.frame(data1,x())
return(datam)
})
# output$table <- renderTable({
# head(merged_data(),n=input$num)})
}
shinyApp(ui, server)
Thanks!
The main issue is that read.csv receiving invalid argument i.e. NULL for header, sep, quote as you don't have input$header, input$sep, input$quote in UI.
library(shiny)
library(DT)
data1<-data.frame(iris[1:15,])
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
numericInput('num','Number of rows',value=10,min=0),
actionButton("update", "Combine Data")),
mainPanel(
tableOutput("table")
)
)
)
server <- function(input, output) {
# output$table <- renderTable({
# head(data1,n=input$num)
# })
x<-reactive({
req(input$file1)
df_uploaded <- read.csv(input$file1$datapath,
#you don't have these variables in the UI, so they will raise an error
#header = input$header,
#sep = input$sep,
#quote = input$quote,
stringsAsFactors = FALSE)
#No need data2 and return(data2) as read.csv returns data.frame by default
#data2<-data.frame(df_uploaded)
#return(data2)
})
merged_data<-eventReactive(input$update,{
datam<-rbind.data.frame(data1, x())
return(datam)
})
output$table <- renderTable({
head(merged_data(), n=input$num)})
}
shinyApp(ui, server)

paste clipboard into shiny app?

Here is an example that I could browse a file as input, but instead of browsing I would like to paste the data from clipboard. Any idea ?
if (interactive()) {
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("contents")
)
)
)
server <- function(input, output) {
output$contents <- renderTable({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header)
})
}
shinyApp(ui, server)
}
You can use textAreaInput() for user to paste his data and then do whatever you need to with it. See the doc page here.
ui <- fluidPage(
textAreaInput("caption", "Caption", "Data Summary", width = "1000px"),
verbatimTextOutput("value")
)
server <- function(input, output) {
output$value <- renderText({ input$caption })
}
shinyApp(ui, server)

Resources