SHINY R reading different versions of excel files based on user selections - r

I have a shiny app, that reads in files that are uploaded by a user
Different people have different versions of excel. So if a user is using excel 2007 or excel 2010 we use one section of code. If they upload it in excel 2003 we use a different library to read the file. The user specifies in the form which version of excel they have
The function to do this is below
get_data <- function(strFilePath, storageType) {
if (is.null(strFilePath))
return(NULL)
if (storagetType == 'xls2010' || storagetType == 'xls2007'){
df <- openxlsx:read.xlsx(strFilePath,sheet = 1)
}
else if (storagetType == 'xls2003'){
df <- XLConnect:readWorksheetFromFile(strFilePath)
}
return(df)
}
To implement this in shiny, i have two widgets. A fileInput and a selectInput. The user selects which version of excel they are running and then selects the file which then is read in by the function get_data. I suspect its because I'm not utilizing the reactivity correctly. When i run the app and upload the file i get the error message
Error: object 'storagetType' not found
# Global.R
storage_types <- c(
"Excel 2010" = "xls2010",
"Excel 2007" = "xls2007",
"Excel 2003" = "xls2003"
)
# UI.R
ui <- shinyUI(fluidPage(
navbarPage("Navbar!",
# Tab contains all the information to upload a file
tabPanel("Upload Data",
# Side Panel with Options
fluidRow(
column(4, wellPanel(
id = "leftPanel",
div(
id = "Header",
h3("Options", align = "center"),
tags$hr()
),
div(
selectInput("xlsversion", "2. Select your Excel version", storage_types),
fileInput(inputId = 'file1',label = '3. Choose An Excel File'),
)
)))))))
# Server.R
server <- shinyServer(
function(input, output) {
# When the Browser to the file location gets updated
upload_data <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
get_data(inFile$datapath, input$xlsversion)
})
})

You not need selectInput simply parse name of file.
Also some typo fixed
library(shiny)
get_data <- function(strFilePath, storageType) {
if (is.null(strFilePath))
return(NULL)
file_ext=substring(storageType,nchar(storageType)-3)
if (file_ext == 'xlsx' ){
df <- openxlsx::read.xlsx(strFilePath,sheet = 1)
}
else if (file_ext == '.xls'){
df <- XLConnect::readWorksheetFromFile(strFilePath,sheet=1)
} else{
return(data.frame("Bad file format"))
}
return(df)
}
# UI.R
ui <- shinyUI(fluidPage(
navbarPage("Navbar!",
# Tab contains all the information to upload a file
tabPanel("Upload Data",
# Side Panel with Options
fluidRow(
column(4, wellPanel(
id = "leftPanel",
div(
id = "Header",
h3("Options", align = "center"),
tags$hr()
),
div(
fileInput(inputId = 'file1',label = '3. Choose An Excel File')
)
))),
dataTableOutput("result")))))
# Server.R
server <- function(input, output) {
# When the Browser to the file location gets updated
upload_data <- reactive({
if (is.null(input$file1))
return(NULL)
get_data(input$file1$datapath, input$file1$name)
})
output$result=renderDataTable({
upload_data()
})
}
shinyApp(ui,server)

Related

How to read csv file and render UI?

I have a simple shiny app and when I press a button a .csv file is saved in the directory where the file app.R is.
I want to be able to read this csv file and render the information in a table on my shiny app.
This is a similiar example about what I would like to do
df <- data.frame(no =c(1:3),money=c(9999:10001),penalty=c(999:1001))
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),actionButton("sort","Do Sorting")
),
mainPanel(
tableOutput("contents"),tableOutput("sortedcontents")
)
)
)
server <- function(input, output) {
rawInputData = reactive({
rawData = input$file1
if(!is.null(rawData)) {
data = read.csv(rawData$datapath);
} else {
return(NULL);
}
});
output$contents <- renderTable({
newData = rawInputData()
if(is.null(newData))
return();
newData;
})
sorting = reactive({
if(input$sort){
newData = rawInputData()
newData$moneysort <- ifelse(newData$money >=10000, 1, 0)
newData$penaltysort <- ifelse(newData$penalty >=1000, 1, 0)
}
newData
})
output$sortedcontents <- renderTable({
newData = sorting()
if(is.null(newData))
return();
newData;
})
}
}
shinyApp(ui, server)
Instead to have the opportunity to choose the file with a fileInpunt() I would like to avoid this step and automatically check a specific directory to look for the csv called "myData.csv" and render this csv in a table.
Here is an example of just reading data from local directory and rendering in shiny.
library(shiny)
write.csv(iris, 'iris.csv')
df = read.csv('iris.csv')
shinyApp(
ui = fluidPage(
fluidRow(
column(12,
tableOutput('iris_table')
)
)
),
server = function(input, output) {
output$iris_table <- renderTable(df)
}
)
This example uses a slight modification from this shiny TableOutput reference.

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)
}

Display a selected image from upload in Shiny UI

I want to be able to upload multiple images with file input and display the single image selected in the UI
ui.R
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file","Upload the file", multiple = TRUE), # fileinput() function is used to get the file upload contorl option
uiOutput("selectfile")
),
mainPanel(
uiOutput('images')
)
)
)
server.R
server <- function(input,output) {
## Side bar select input widget coming through renderUI()
# Following code displays the select input widget with the list of file loaded by the user
output$selectfile <- renderUI({
if(is.null(input$file)) {return()}
list(hr(),
helpText("Select the files for which you need to see data and summary stats"),
selectInput("Select", "Select", choices=input$file$name)
)
})
output$images <- renderImage({
if(is.null(input$file)) {return(NULL)}
for (i in 1:nrow(input$file))
{
if(input$file$name[i] == input$Select){
list(src=input$file$datapath[i],
alt= "error")
print(input$file$name[i])
print(input$file$datapath[i])
}
}
})
}
With this solution, the prints of the datapath and the name shows me the right answer but i keep getting the same error after trying to render the image: "Warning: Error in basename: a character vector argument expected".
Here is a solution using base64 encoding.
library(shiny)
library(base64enc)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file", "Upload the file", multiple = TRUE),
uiOutput("selectfile")
),
mainPanel(
uiOutput('image')
)
)
)
server <- function(input,output) {
output$selectfile <- renderUI({
req(input$file)
list(hr(),
helpText("Select the files for which you need to see data and summary stats"),
selectInput("Select", "Select", choices=input$file$name)
)
})
output$image <- renderUI({
req(input$Select)
i <- which(input$file$name == input$Select)
if(length(i)){
base64 <- dataURI(file = input$file$datapath[i], mime = input$file$type[i])
tags$img(src = base64, alt= "error")
}
})
}
shinyApp(ui, server)

Warning in summary(as.numeric(paste(input$to, "input$to"))) : NAs introduced by coercion in Shiny with R

I am very new to Shiny web app with R. I want to generate summary according to choice from checkboxGroupInput which i generated dynamically when browsing the CSV file. My problem is that when i want to convert from String to numeric that time it prints NA.
I am uploading my two files which are ui.r and server.r. I am trying since two days. If anyone help me then it will be very beneficial for me.
If i did anything wrong in my code then please suggest me right way.
ui.r
library(shiny)
library(shinythemes)
shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
# Application title
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
#checkboxInput("header", "Header?")
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
# tableOutput("disp")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
plotOutput("p")
)
)
))
server.r
library(shiny)
shinyServer(function(input, output,session) {
#This function is repsonsible for reading a csv file
output$input_file <- renderTable({
file_to_read = input$datafile
if(is.null(file_to_read))
{
return()
}
read.csv(file_to_read$datapath, sep = input$sep, nrows = input$obs))
})
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs)
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
observe({
# db <- gsub(",","",input$to)
# print(db)
# paste( intToUtf8(160), input$to, intToUtf8(160))
# print(summary(as.numeric(as.character( paste( " ", input$to, "
#"))))) })
print(summary(as.numeric( input$to) ))})
# output$sum <- renderPrint({
# summary(input$data.frame[,as.numeric(input$var)])
# })
# output$disp <- renderTable({
# input$to
# })
# output$summary1 <- renderPrint({
# sum <- as.numeric(as.character(input$to))
# summary(sum)
#})
})
This could be a starting point, although I dont recommend using this for a productive app, as the login-process is not really safe nor encrypted. It is based solely on text-data.
But you will have to put the ui in the server and render the page depending on the login status. So there are 2 renderUI but just 1 server-function. I dont know if you can have 2 different server-functions and redirect them. I think it all has to be in 1 server-function.
library(shiny)
username = "joe"
password = "joe123"
ui <- fluidPage(
uiOutput("ui")
)
server <- function(input, output, session) {
LOGGED <- reactiveValues(user = FALSE)
observeEvent(input$action, {
if ((input$name == username ) & (input$pass == password)) {
LOGGED$user = TRUE
} else {
LOGGED$user = FALSE
}
})
observe({
if (LOGGED$user == FALSE) {
output$ui <- renderUI({
tagList(
p(HTML("User is joe <br> and password is joe123")),
textInput("name", "Enter your username"),
passwordInput("pass", "Enter your password"),
actionButton("action", label = "Action")
)
})
} else if (LOGGED$user == TRUE) {
output$ui <- renderUI({
tagList(
h1("You are logged in.")
)
})
}
})
}
shinyApp(ui, server)
Like #Codeer said, there is no line in your code like this one summary(as.numeric(paste(input$to, “input$to”))). I edited your code, so all the uncommented lines dont appear, as its not necessary to show them.
In your example, your loading the csv file twice, which you can definitly avoid.
I moved the csv-loading into the reactive only. Then you can access the loaded file everywhere in your shiny-app. And i think in your print(summary()) statement, you're missing the data, as your only printing out the summary of the input$tovariable, which is only text and if you convert it to numeric you create NA-values.
So i rearranged your code a bit, and I think its behaving the way you intend it to.
library(shiny)
library(shinythemes)
ui <- {shinyUI(fluidPage(
theme = shinytheme("cyborg"),
themeSelector(),
titlePanel("Data Analytics and Visualization Dashboard"),
sidebarLayout(
sidebarPanel(
fileInput('datafile', 'Choose CSV file',accept=c('text/csv', 'text/comma-
separated-values,text/plain')),
h5("Max file size to upload is 5 MB."),
radioButtons("sep", "Seperator", choices = c(Comma = ',', semicolon = ';',
tab = "\t", space = " " )),
br(),
h4("Select columns from CSV"),
uiOutput("toCol"),
br(),
h4("Summary"),
textOutput("sum")
),
mainPanel(
numericInput("obs", "Enter the number of rows to display:", 5),
tableOutput("input_file"),
verbatimTextOutput("summary"),
plotOutput("p")
)
)
))}
server <- shinyServer(function(input, output,session) {
#This function is repsonsible for loading and reading a csv file
filedata <- reactive({
req(input$datafile)
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath,nrows = input$obs, sep = input$sep)
})
output$input_file <- renderTable({
filedata()
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <- filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
checkboxGroupInput("to", "Columns",items)
})
output$summary <- renderPrint({
req(input$to)
data <- filedata()
print(summary(data[,input$to]))
})
})
shinyApp(ui, server)
The csv file is loaded in the reactive (filedata). In the renderTable, you just enter the reactive variable - filedata(). And in the observe, you call again the reactive variable and only print out the summary of the data in the clicked column (input$to).

Get the name of uploaded file as a variable in Shiny

I am creating a Shiny App where one of the sections of a Venn Diagram will be named after the uploaded file(done by user). For example, if someone uploads a file ClientXYZ.csv, one section of the Venn diagram will be named "ClientXYZ"
Is it possible to do this in Shiny?
Its not clear without a reproducible example, but you can grab the name of the file with input and name.
library(shiny)
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")
)
)
)
server <- function(input, output) {
file_name <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
return (stringi::stri_extract_first(str = inFile$name, regex = ".*(?=\\.)"))
})
output$myFileName <- renderText({ file_name() })
}
# Run the application
shinyApp(ui = ui, server = server)

Resources