Detect columns in an uploaded csv in R shiny app - r

I want to create a shiny app where one can upload a csv file and then select columns of that file. The problem is that after uploading a file, my code fails to update the column names for possible choices. Here is a reproducible example. Thank you!
ui <- fluidPage(
fileInput("file1",
"Please choose a csv File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
div(style="display:inline-block", selectInput('var',
'Select the first var',
"") )
)
server <- function( input, output, session ) {
data <- reactive({
inFile <- input$file1
req(inFile)
validate(need(ext == "csv", "Please upload a csv file"))
df = read.csv(inFile$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
colnames <- names(df)
df
})
output$contents <- renderTable( {
updateSelectInput(session,
inputId = 'var',
label = 'Select the first var',
choices = colnames)
} ) }
shinyApp(ui = ui, server = server)

Some of your reactive expression aren't right, lets split things out to make it easier to follow. In particular use observeEvent to watch the file input.
library(shiny)
ui <- fluidPage(
fileInput("myfileinput", "Please choose a csv File", multiple = FALSE, accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
selectInput('myselectinput','Select the first var', ""),
tableOutput('mytable')
)
server <- function(input, output, session) {
#Reactive to store loaded data
reactives <- reactiveValues(
mydata = NULL
)
#Observe file being selected
observeEvent(input$myfileinput, {
#Store loaded data in reactive
reactives$mydata <- read.csv(file = input$myfileinput$datapath)
#Update select input
updateSelectInput(session, inputId = 'myselectinput', label = 'Select the first var', choices = colnames(reactives$mydata))
})
#Data table
output$mytable <- renderTable({
reactives$mydata
})
}
shinyApp(ui = ui, server = server)

Related

How To Apply Regex in Shiny App Filter/Button?

I'm super new to Shiny Apps and to R. How would I add a button that allows me to filter the passed-in dataset using this regex? The uploaded dataset would all contain the same column names, and the column I want to apply the regex to is "close_notes". I want to first convert this column to a string, uppercase everything, then apply the regex. Thank you so much for your help in advance!
The Regular Expression:
"\\bMASTER DATA\\b|\\bSOURCE LIST\\b|\\bVALIDITY DATES\\b|\\bMRP CONTROLLER\\b|\\bPSV\\b|\\bELIGIBILITY\\b|\\bCOST\\b|\\bMARKETING EXCLUSION\\b|\\bEFFECTIVITY\\b|\\bMISSING\\b|\bbBLANK\\b"
The code below is for the Shiny App. Please let me know if anything looks wrong or like it should be modified. Thank you!
library(shiny)
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),
# Button
downloadButton("downloadData", "Download")
),
mainPanel(
dataTableOutput("contents")
)
)
)
server <- function(input, output) {
datasetInput <- reactive({
req(input$file1)
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
if (is.null(inFile))
return(NULL)
read.csv(inFile$datapath, header = input$header)
})
output$contents <- renderDataTable({
datasetInput()
})
output$downloadData <- downloadHandler(
filename = function() {
paste("myfile",Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(datasetInput(), file, row.names = FALSE)
}
)
}
shinyApp(ui, server)
You can do some changes to your current code.
Used reactiveValues to save the data uploaded, also changed reactive to observe.
Added an actionButton to apply filter after pressing the button and used observeEvent on the server side.
library(shiny)
library(dplyr)
#Define the regex to apply.
regex_to_apply <- "\\bMASTER DATA..."
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),
# Button
downloadButton("downloadData", "Download"),
actionButton('apply_regex', 'Apply Regex')
),
mainPanel(
dataTableOutput("contents")
)
)
)
server <- function(input, output) {
rv <- reactiveValues()
observe({
req(input$file1)
# input$file1 will be NULL initially. After the user selects
# and uploads a file, it will be a data frame with 'name',
# 'size', 'type', and 'datapath' columns. The 'datapath'
# column will contain the local filenames where the data can
# be found.
inFile <- input$file1
if (is.null(inFile))
return(NULL)
rv$data <- read.csv(inFile$datapath, header = input$header)
})
output$contents <- renderDataTable({
rv$data
})
output$downloadData <- downloadHandler(
filename = function() {
paste("myfile",Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(rv$data, file, row.names = FALSE)
}
)
observeEvent(input$apply_regex, {
rv$data <- rv$data %>% filter(grepl(regex_to_apply, toupper(close_notes)))
})
}
shinyApp(ui, server)
You should move the word boundaries to the outsides of the alternation, like this:
\b(MASTER DATA|SOURCE LIST|VALIDITY DATES|MRP CONTROLLER|PSV|ELIGIBILITY|COST|MARKETING EXCLUSION|EFFECTIVITY|MISSING|BLANK)\b

Uploading to Shiny and assigning it to environment for further use

I am trying to create a Shiny dashboard where the user can upload data sets, naming them, and then selecting one data set from a dropdown menu.
I dont fully understand how a user can upload a data, save it and further access it. I tried using assign(), but the dataset does not show up under ls(). My try:
library(data.table)
library(shinyWidgets)
library(shinydashboard)
if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
actionButton('show_ls', 'show_ls'),
# Name data
textInput('name_data', 'Store data as' , value = ''),
# Action button to upload
actionButton('upload_data', 'Upload and save data')
),
mainPanel(
tableOutput('ls')
# textOutput('ls'))
)
)
)
server <- function(input, output, session) {
# This part uploads one row from the file, so the user can selects columns and choose name of the file
data <- reactive({
file1 <- input$file1
if(is.null(file1)){return()}
data_input <- fread(file=file1$datapath, sep=",")
updateTextInput(
session,
'name_data',
value = file1$name
)
return(data_input)
})
#### ASSIGNING THE DATA
assign_data <- eventReactive(input$upload_data, {
assign(input$name_data, data(), envir = .GlobalEnv)
})
assign_the_data <- reactive(assign_data())
output$contents <- renderTable({
if(is.null(data())) return(NULL)
data()
})
outputOptions(output, 'contents', suspendWhenHidden = FALSE)
show_ls <- eventReactive(input$show_ls, {data.frame(a = ls(.GlobalEnv))})
output$ls <- renderTable({
show_ls()
})
}
shinyApp(ui, server)
}
Using assign() can be difficult because the search path through the namespace can be difficult to predict. A better solution would be to store the datasets in a reactive values list and access them from there. You can dynamically render the dataset picker UI based on the names of the datasets stored in the reactive values list.
if (interactive()) {
ui <- fluidPage(sidebarLayout(
sidebarPanel(
fileInput(
"file1",
"Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
# Name data
textInput('name_data', 'Store data as' , value = ''),
# Action button to upload
actionButton('upload_data', 'Upload and save data')
),
mainPanel(uiOutput("dataset_picker"),
tableOutput('selected_table')
# textOutput('ls')))
))
server <- function(input, output, session) {
# This part uploads one row from the file, so the user can selects columns and choose name of the file
dfs <- reactiveValues()
observeEvent(input$upload_data, {
req(input$file1, input$name_data)
dfs[[input$name_data]] <- read.csv(input$file1$datapath[1])
print(names(dfs))
})
output$dataset_picker <- renderUI({
req(length(dfs) > 0)
pickerInput(
"dataset_picker",
label = "Choose dataset",
choices = names(reactiveValuesToList(dfs)),
selected = NULL
)
})
output$selected_table <- renderTable({
req(input$dataset_picker)
dfs[[input$dataset_picker]]
})
}
shinyApp(ui, 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)

How to capture R Shiny text input of variable name for analysis

Newbie to R and working through simple R Shiny examples for learning purposes. The following program enables user to upload a delimited data file, at which point head() displays first few rows. I also want to allow use to input in a text input the name of a variable in the file to generate a frequency. How can i capture the text input and reference it in the server section? You can see i have commented out a line where i manually enter the field and it works fine.
I've sifted through quite a few examples using textinput, but all were facing different issues than i could find. I do apologize if a post already has the help i seek. Thanks in advance.
server <- function(input, output) {
splay <- reactive({
req(input$file1)
df.raw <- read.csv(input$file1$datapath, header = input$header, sep = input$sep, quote = input$quote)
info <- list(df.raw=df.raw)
return(info)
})
output$contents <- renderTable({
if(input$disp == "head") { return(head(splay()$df.raw)) }
else { return(splay()$df.raw) }
})
observe({
varname <- renderText({input$frqvar})
})
output$jason <- renderTable({
if (is.null(input$file1)) { return() }
#table(splay()$df.raw$tx)
table(splay()$df.raw$varname())
})
output$caption1 <- renderText({
if (is.null(input$file1)) { return() }
paste("Listing of Uploaded Data and Frequency of ",input$frqvar ,"Variable")
})
} #this ends the server function
#ui=user interface portion
#place elements in the fluid page section to layout the page
ui <- fluidPage(
# App title
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions
sidebarLayout(
# Sidebar panel for inputs
sidebarPanel(
# Input: Select a file
fileInput("file1", "Choose CSV File", multiple = FALSE, accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")),
# Horizontal line
tags$hr(),
# Input: Checkbox if file has header
checkboxInput("header", "Header", TRUE),
# Input: Select separator
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
# Input: Select quotes
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"'),
# Horizontal line
tags$hr(),
# Input: Select number of rows to display
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head"),
textInput("frqvar",
label = h1("Variable to run Freq"),
value = " " ),
actionButton("action", label="Submit")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
textOutput("caption1"),
tableOutput("contents"),
tableOutput("jason")
#tableOutput("")
)
)
)
shinyApp(ui = ui, server=server)
Below is an example using one of R's built-in dataset, with a twist. Having users type in the name of the variable will lead to a lot of errors and thus a lot of work on your end to catch those errors. Ideally, after users have uploaded their dataset, you generate a dropdown menu of the variable names that can be selected.
Before explaining the above, you can access any input in your server function with input$id.
library(shiny)
ui <- fluidPage(
textInput("id", "label"),
verbatimTextOutput("out")
)
server <- function(input, output){
output$out <- renderPrint({
input$id
})
}
shinyApp(ui, server)
Now, for generating executing what you are after but with a selectInput (drop down menu).
library(shiny)
ui <- fluidPage(
selectInput("dataset", "select a dataset", choices = c("cars", "mtcars")),
uiOutput("dropdown"),
verbatimTextOutput("head"),
plotOutput("hist")
)
server <- function(input, output) {
data <- reactive({
if(input$dataset == "cars")
cars
else
mtcars
})
output$dropdown <- renderUI({
selectInput("variables", "Select a variable", names(data()))
})
output$head <- renderPrint({
head(data())
})
output$hist <- renderPlot({
hist(data()[[input$variables]])
})
}
shinyApp(ui, server)
Below is the code with small modifications of your serverfunction with dependency of submit button reactive environment.
server <- function(input, output, session) {
session$onSessionEnded(stopApp)
splay <- reactive({
req(input$file1)
df <- read.csv(input$file1$datapath, header = input$header, sep = input$sep, quote = input$quote)
info <- list(df = df)
return(info)
})
output$contents <- renderTable({
if (input$disp == "head") { return(head(splay()$df)) }
else {return(splay()$df) }
})
freq <- eventReactive(input$action,{
return(splay()$df[[input$frqvar]])
})
observeEvent(input$action,{
output$jason <- renderTable({
if (is.null(input$file1)) { return() }
else {table(freq()) }
})
})
output$caption1 <- renderText({
if (is.null(input$file1)) { return() }
paste("Listing of Uploaded Data and Frequency of ",input$frqvar ," Variable")
})
}

passing on data from observe function to download

I got stuck on my first shiny app again. So far the App was runing fine, but now I wanted to download the plot I generated and I can not work out how to get the results out of the observe function.
As I can not generate the plot outside the observe function, I was thinking I would assign the necessary data to a global variable useing <<-, but if I run a reactive function e.g. df.selected.columns() this seem to cause errors.
Can someone give me a hint how to proceed?
Thank you so much for any suggestions! Aishe
Here is me code:
ui <- shinyServer(
fluidPage(
tabsetPanel(
tabPanel("Data upload",
titlePanel("Data upload"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",multiple = TRUE, accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
tags$hr(),
checkboxInput("header", "Header", TRUE), radioButtons("sep", "Separator", choices = c(Comma = ",", Semicolon = ";",Tab = "\t"), selected = ","),
tags$hr(),
checkboxInput("disp", "Display",TRUE),
tags$hr(),
uiOutput("choose_first_column"),
uiOutput("choose_second_column"),
br()
),
mainPanel(
tableOutput("contents"),
tags$hr(),
tableOutput("tab"),
tags$hr(),
uiOutput("download"),
plotOutput("headplot")
)
)
),
tabPanel("2","2"
)
)
)
)
server <- shinyServer(
function(input, output) {
observe({
req(input$file1)
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
output$contents <- renderTable({
(head(df))})
output$choose_first_column <- renderUI({
colnames <- names(df)
selectInput("column_1", "Choose Date column",
choices = colnames,
selected = colnames)})
output$choose_second_column <- renderUI({
colnames <- names(df)
selectInput("column_2", "Choose Variable column",
choices = colnames,
selected = colnames)})
df.selected.columns <- reactive({
df.columns <- df[,c(input$column_1,input$column_2)]
return(df.columns)
})
output$tab <- renderTable({
(head(df.selected.columns()))
})
Plot1 <- reactive({
plot(head(df.selected.columns()[,2]))
})
output$headplot <- renderPlot({
Plot1()
})
# This comes closest to what I wanted to do. However, now I can not select the columns anymore.
# try(result <<- head(df.selected.columns()[,2]),silent=T)
# With this line it crushes straight away
# result <<- head(df.selected.columns()[,2])
})
output$download <- renderUI({
if(!is.null(input$column_1) & !is.null(input$column_2)) {
downloadButton('OutputPlot', 'Download Plot')
}
})
output$OutputPlot <- downloadHandler(
filename = function() {
paste('plot', '.pdf', sep='')
},
content=function(file){
pdf(file)
plot(result)
dev.off()
})
})
runApp(list(ui = ui, server = server))
Input data example:
date time level
01.01.2000 00:00:00 0.3724
01.01.2000 01:00:00 0.192
01.01.2000 02:00:00 -0.0252
Remove the observe
Make the loaded file a reactive
Update all references to df to df() since it's now a reactive expression
Add appropriate req() functions to prevent error messages
In your downloadHandler you have plot(result), but there's no such thing as result. You want Plot() or plot(df.selected.columns())
You should be confirming that your selected delimiter is actually splitting the loaded table correctly before your return the loaded table. Without that, you'll get errors and strange results/
Here's the updated df and downloadHandler functions to get you started:
df <- reactive({
req(input$file1)
read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
})
output$OutputPlot <- downloadHandler(
filename = function() {
paste('plot', '.pdf', sep='')
},
content=function(file){
pdf(file)
plot(head(df.selected.columns()[,2]))
dev.off()
})

Resources