How to use local .txt files in a Shiny App - r

Hi all this is my first question, so I hope the format is correct.
I'm looking to create a R shiny app that calls on all the .txt files that that are within the parameters set by the user, merges those .txt files, and produces a word cloud.
The app located here https://lukaszsowinski.shinyapps.io/WC-app/ crashes once it is opened, although it works on my local computer. I'm almost sure it has to do with the way I'm writing in my wd(), data files, and .txt files as they were giving me problems before I was able to finally published. This is the error I'm getting
2017-08-12T01:17:22.742107+00:00 shinyapps[204302]: Error in loadWorkbook(file) :
2017-08-12T01:17:22.742109+00:00 shinyapps[204302]: Cannot find /home/shiny/WC-app/WordMappingInfo.xlsx
Here is the ines of code that I'm not sure where my error is.
library(rsconnect)
rsconnect::deployApp('C:/Users/Lukasz Sowinski/Desktop/WC-app')
server <- function(input, output, server)
{
textframe <- read.xlsx("C:/Users/Lukasz Sowinski/Desktop/WC-app/WordMappingInfo.xlsx", 1)
schooldata <- list (
"Num" = textframe$Num[!is.na(textframe$Num)],
"SchoolName" = C(textframe$SchoolName),
"Path" = c(
"C:/Users/Lukasz Sowinski/Desktop/WC-app/texts/Queens College.txt",
"C:/Users/Lukasz Sowinski/Desktop/WC-app/texts/Lehman College.txt",
"C:/Users/Lukasz Sowinski/Desktop/WC-app/texts/Denison University.txt",
"C:/Users/Lukasz Sowinski/Desktop/WC-app/texts/St Johns University.txt",
"C:/Users/Lukasz Sowinski/Desktop/WC-app/texts/Rutgers University.txt"
),
"Students" = textframe$Students[!is.na(textframe$Students)],
"Tuition" = textframe$Tuition[!is.na(textframe$Tuition)],
"Program" = textframe$Program[!is.na(textframe$Program)]
)
Here is the some of the cod where I call up the data as needed based on user input.
if (schooldata$Program[i] == input$selection)
{
if (temptext == 0)
{
temptext <- schooldata$Path[i]
temptext.1 <- readLines(temptext)
mastertext.1 = temptext.1
}
temptext <- schooldata$Path[i]
temptext.1 <- readLines(temptext)
mastertext.1 <- rbind(mastertext.1, temptext.1)
}
I've also tried using pathways
"./WC-app/WordMappingInfo.xlsx"
"~/WC-app/WordMappingInfo.xlsx"
That I found in similar questions but neither work.
Any help would be tremendously appreciated. Thank you

Have you tried with shinyFiles CRAN packages extension?
In the ui.R file
shinyUI(bootstrapPage(
shinyFilesButton('files', label='File select', title='Please select a file', multiple=FALSE)
))
In the server.R file
shinyServer(function(input, output) {
shinyFileChoose(input, 'files', root=c(root='.'), filetypes=c('', 'txt'))
})

Related

How to check to see if a function is an object in the R workspace and if not, run a source file to invoke it?

In the below example code, the function testFunction() is defined in the separate source file functionsLibrary.R saved on the desktop. This example code works as intended.
How would I modify the code to first test if testFunction() is an object in the R workspace, and source it (running the line source("C:/Users/laran/OneDrive/Desktop/functionsLibrary.R")) only if the function is not in the workspace?
In the full code this is intended for, the function takes a very long time to run (reading a large data file into memory) and I only want it sourced if it is not currently a workspace object.
Example code:
library(shiny)
source("C:/Users/laran/OneDrive/Desktop/functionsLibrary.R")
ui <- fluidPage(
br(),
numericInput('selectValue','Select number of values to square:',value=1,step=1,min=1),
br(),
tableOutput('table')
)
server <- function(input,output,session)({
output$table <- renderTable(testFunction(input$selectValue))
})
shinyApp(ui, server)
Source file contents (filename functionsLibrary.R):
testFunction <- function(a) {
b <- data.frame(Value=seq(1:a),Square_Value = seq(1:a)^2)
return(b)
}
An easy way to go about this would be to use exist(). This should work for your problem.
library(shiny)
if (!exists("testFunction")) {
source("C:/Users/laran/OneDrive/Desktop/functionsLibrary.R")
}
ui <- fluidPage(
br(),
numericInput('selectValue','Select number of values to square:',value=1,step=1,min=1),
br(),
tableOutput('table')
)
server <- function(input,output,session)({
output$table <- renderTable(testFunction(input$selectValue))
})
shinyApp(ui, server)
We could extend the if clause to check if testFunction is really a function in case it exists and if not source the file.
if (!exists("testFunction") || (exists("testFunction") && !is.function(testFunction)))

Uploading multiple files from shiny app to google drive

Using the advice from this previous post I was able to figure out how to upload a single file from my shiny app to a specific folder on my google drive. This worked perfectly. Unfortunately, I get the following error when I try to select and upload multiple files though. Any help is appreciated!
"Warning in if (!file.exists(media)) { :
the condition has length > 1 and only the first element will be used
Warning: Error in rationalize_path_name: is_string(name) is not TRUE
[No stack trace available]"
Here is minimally reproducible example below
library(googledrive)
ui <- fluidPage(
fileInput(inputId = "file",
label = "Choose file to upload",
accept = NULL,
multiple = TRUE)
)
server <- function(input, output) {
observeEvent(input$file, {
drive_upload(media = input$file$datapath,
name = input$file$name,
path = "my_folder")
})
}
shinyApp(ui, server)
To upload several files you need to iterate on each input$file$datapath, input$file$name pair:
observeEvent(input$file, {
mapply( function(datapath, name){
drive_upload(media = datapath,
name = name,
path = "my_folder")},
input$file$datapath,
input$file$name)
})

Excel data distribution with Shiny

I am not good at English, so sentences may be wrong.
I want to distribute excel files prepared in advance to users. Is it possible to realize such a system with shiny? No problem with .zip.
Thank you
ui.R
shinyUI(
fluidPage(
downloadButton('downloadData', 'Excel Download')
)
)
server.R
shinyServer(function(input, output) {
output$downloadData <- downloadHandler(
filename = "distribution.xlsx",
content = "distribution_excel"
)
})
Yes, it is possible and you were nearly there. Below is a minimal working example. I assume that your .xlsx file is located in the same folder as your app.R. Notice that I have created the app in a single R file as opposed to two separate files.
The trick to getting the file to download is to use a function for the content inside of downloadHandler(). Specifically we are using the base function file.copy(). Clicking the button should now download the file: distribution.xlsx. This file can obviously be exchanged with a zip file.
If you want different users to access different Excel files, you can write an additional function inside of your server function that passes the file argument to the downloadHandler().
# Load packages ----
pkgs <- c("shiny")
invisible(lapply(pkgs, require, character.only = TRUE))
# Set up the UI ----
ui <- fluidPage(
# Define your download button
downloadButton(
outputId = "downloadData",
label = "Excel Download"
)
)
# Set up the server side ----
server <- function(input, output, session) {
# Define the download handler with function() for content.
output$downloadData <- downloadHandler(
filename = "distribution.xlsx",
content = function(file) {
file.copy("distribution.xlsx", file)
}
)
}
# Combine into an app ----
shinyApp(ui = ui, server = server)

Get original names of files with a function like fileInput (R shiny)

I want to select some files in the browser like with fileInput in Shiny but I only need their paths as a character and nothing else. I do not want to upload them (but it's no problem if it is done anyway). When I use fileInput the result is a data.frame containing the paths of the files in a temporary folder with the names i.e. 0.csv, 1.txt, 2.pdf ... But I need the original filenames (with or without the full path). Is there any way to achieve this in a fast and 'non-hacky' way?
There is a very important reason why this is not possible: Security
JavaScript has no accress to the file System, so you will not to able to get the full paths of the user. One option is your force your user to use a path, but well... he can lie there of course. Maybe do it like this
You could only use it like this:
library(shiny)
ui <- fluidPage(
tags$h1("Test"),
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
textInput("path", "Please enter the full path of your file"),
tableOutput("pathtable")
)
server <- function(input, output, session) {
testdf <- reactive({
data.frame(
ID = 1,
file = input$path
)
})
output$pathtable <- renderTable({
if(input$path == "") {
return(NULL)
} else {
testdf()
}
})
}
shinyApp(ui = ui, server = server)
The original names are saved in the variable
input$file1$name
However the "real" data (which is renamed as OP correctly pointed out) can be accessed via
input$file1$datapath
where file1 is the InputId of the function fileInput()

Interactive directory input in Shiny app (R)

I am building a shiny app that requires a user to select a folder on the local machine, which contains the files to be processed by the app.
I am using a solution proposed here. This works fine on a local machine, but does not work if the app is deployed to a shinyapps server.
The author of this solution confirmed that it was only designed to work with local Shiny apps, since it makes OS shell calls to display a directory dialog.
I am wondering if there is a different solution for directory dialog, which will work on the deployed Shiny apps (I am deploying to shinyapps.io).
Edited: Notice that I cannot use fileInput interface for two reasons:
The users of the app are not technical people and they do not know which files inside the folder are used by the app.
The selected folder may contain other folders within which the needed files reside, such that it is impossible to select all files at once, even if the fileInput interface has the multiple option enabled.
The folder/files structure is not something I can change, it is downloaded AS IS from a medical device and therefore the only thing I can expect from the users is to specify the parent folder and the rest should be done inside the R code.
This is a working example based on using the "webkitdirectory" attribute. At the moment the attribute is supported by Chrome, Opera and Safari (mobile and desktop) and it should be supported in Firefox 49 to be released in September.
More about this here. It work with subdirectories also.
It requires using the tags keyword in ui.R. I have tested it by uploading three csv files each contaning three numbers separeted by a coma. Tested locally and on shinyapps.io with Chrome and Opera. This is the code:
ui.R
library(shiny)
library(DT)
shinyUI(tagList(fluidPage(theme = "bootstrap.css",
includeScript("./www/text.js"),
titlePanel("Folder content upload"),
fluidRow(
column(4,
wellPanel(
tags$div(class="form-group shiny-input-container",
tags$div(tags$label("File input")),
tags$div(tags$label("Choose folder", class="btn btn-primary",
tags$input(id = "fileIn", webkitdirectory = TRUE, type = "file", style="display: none;", onchange="pressed()"))),
tags$label("No folder choosen", id = "noFile"),
tags$div(id="fileIn_progress", class="progress progress-striped active shiny-file-input-progress",
tags$div(class="progress-bar")
)
),
verbatimTextOutput("results")
)
),
column(8,
tabsetPanel(
tabPanel("Files table", dataTableOutput("tbl")),
tabPanel("Files list", dataTableOutput("tbl2"))
)
)
)
),
HTML("<script type='text/javascript' src='getFolders.js'></script>")
)
)
server.R
library(shiny)
library(ggplot2)
library(DT)
shinyServer(function(input, output, session) {
df <- reactive({
inFiles <- input$fileIn
df <- data.frame()
if (is.null(inFiles))
return(NULL)
for (i in seq_along(inFiles$datapath)) {
tmp <- read.csv(inFiles$datapath[i], header = FALSE)
df <- rbind(df, tmp)
}
df
})
output$tbl <- DT::renderDataTable(
df()
)
output$tbl2 <- DT::renderDataTable(
input$fileIn
)
output$results = renderPrint({
input$mydata
})
})
text.js
window.pressed = function(){
var a = document.getElementById('fileIn');
if(a.value === "")
{
noFile.innerHTML = "No folder choosen";
}
else
{
noFile.innerHTML = "";
}
};
getFolders.js
document.getElementById("fileIn").addEventListener("change", function(e) {
let files = e.target.files;
var arr = new Array(files.length*2);
for (let i=0; i<files.length; i++) {
//console.log(files[i].webkitRelativePath);
//console.log(files[i].name);
arr[i] = files[i].webkitRelativePath;
arr[i+files.length] = files[i].name;
}
Shiny.onInputChange("mydata", arr);
});
Let me know if this helps.
Have you tried around with the shinyFiles package?
There is a widget which lets you chose a directory.
As output you get the path of that directory which you can in turn use to access the files.
Here is an example how it works.
server
library(shiny)
library(shinyFiles)
shinyServer(function(input, output, session) {
# dir
shinyDirChoose(input, 'dir', roots = c(home = '~'), filetypes = c('', 'txt'))
dir <- reactive(input$dir)
output$dir <- renderPrint(dir())
# path
path <- reactive({
home <- normalizePath("~")
file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
})
# files
output$files <- renderPrint(list.files(path()))
})
ui
library(shiny)
library(shinyFiles)
shinyUI(fluidPage(sidebarLayout(
sidebarPanel(
shinyDirButton("dir", "Chose directory", "Upload")
),
mainPanel(
h4("output$dir"),
verbatimTextOutput("dir"), br(),
h4("Files in that dir"),
verbatimTextOutput("files")
)
)))
Hope this helps.

Resources