How to clean up CSV data after uploading to Shiny App - r

Please help!
I'm trying to build a Shiny App with the intent to classify data loaded from a CSV file. How do I successfully create a DataFrame from a CSV file (that is uploaded) so that I can move forward and clean/analyze it.
Please see code:
library(shiny)
library(lubridate)
library(utils)
library(dplyr)
library(tidytext)
ui <- (pageWithSidebar(
headerPanel("CSV File Upload Demo"),
sidebarPanel(
#Selector for file upload
fileInput('datafile', 'Choose CSV file',
accept=c('text/csv', 'text/comma-separated-values,text/plain')),
#These column selectors are dynamically created when the file is loaded
uiOutput("fromCol"),
uiOutput("toCol"),
uiOutput("amountflag"),
#The conditional panel is triggered by the preceding checkbox
conditionalPanel(
condition="input.amountflag==true",
uiOutput("amountCol")
)
),
mainPanel(
tableOutput("filetable")
)
))
Please advise whether to use Reactive
server <- (function(input, output) {
#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)
}
dataframe <- reactive({
readr::read_csv(infile()$datapath)
})
# Clean data by whole-case removal of missing cells (either NAs or "nan")
# Remove the rows which have NAs
myDataClean2 = dataframe[complete.cases(dataframe),]
# In order to turn it into a tidy text dataset, we first put the data into a data frame:
text_df <- data_frame(myDataClean2$text,myDataClean2$title,myDataClean2$author,myDataClean2$id,myDataClean2$label)
names(text_df) <- c("text","title","author","id","label")
# Within the tidy text framework, we break both the text into individual tokens and transform
# it to a tidy data structure. To do this, we use tidytextâs unnest_tokens() function.
tidy_text_df <- text_df %>%
unnest_tokens(word, text)
#This previews the CSV data file
output$filetable <- renderText({
tidy_text_df()
})
})
})
# Run the application
shinyApp(ui = ui, server = server)

You are mixing reactive blocks. Your filedata should end with something that outputs your data, likely the output from unnest_tokens(word, text). (It should put out all data you are interested in, I think that that line does.) From there, your output$filetable needs to be outside of filedata's reactive block, on its own. And it should be using filedata(), not tidy_text_df (which isn't available outside of the first reactive block).
Try this:
server <- (function(input, output) {
#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)
}
dataframe <- reactive({
readr::read_csv(infile()$datapath)
})
# Clean data by whole-case removal of missing cells (either NAs or "nan")
# Remove the rows which have NAs
myDataClean2 = dataframe[complete.cases(dataframe),]
# In order to turn it into a tidy text dataset, we first put the data into a data frame:
text_df <- data_frame(myDataClean2$text,myDataClean2$title,myDataClean2$author,myDataClean2$id,myDataClean2$label)
names(text_df) <- c("text","title","author","id","label")
# Within the tidy text framework, we break both the text into individual tokens and transform
# it to a tidy data structure. To do this, we use tidytextâs unnest_tokens() function.
text_df %>%
unnest_tokens(word, text)
})
#This previews the CSV data file
output$filetable <- renderText({
filedata()
})
})

Related

uploading multiple file input and accessing them through the shiny app to perfrom a loop

I'm pretty stuck here; I have created a simple shiny app with the possibility of uploading multiple files. However, I don't know how can I move on from here and access the files directly within the shiny app, for example, get all the uploaded data files into one data.frame to perform a loop later on.
for example we have
data_1 <- "data file 1"
data_2 <- "data file 2"
data_3 <- "data file 3"
data_4 <- "data file 4"
dataSet <- data.frame(DATA= c(1,2,3,4),
DATAFILE=c(data_1 ,data_2 ,data_3 ,data_4))
Is there any way to do that? I hope I have been able to explain myself thoroughly. I really appreciate any help you can provide.
library(shiny)
options(shiny.maxRequestSize = 30 * 1024^2)
ui <- fluidPage(
fileInput("upload", NULL, buttonLabel = "Upload...", multiple = TRUE),
tableOutput("files")
)
server <- function(input, output, session) {
output$files <- renderTable(input$upload)
}
shinyApp(ui, server)
input$upload is a data.frame containing four columns, to read the files we'll need datapath column that contains the temp path with the uploaded data, in this case they are csv's. From there we use a function like readr::read_csv() to transform the raw uploaded data into a df.
We can construct a reactive that consists in a list with all the uploaded files in it.
# read all the uploaded files
all_files <- reactive({
req(input$upload)
purrr::map(input$upload$datapath, read_csv) %>%
purrr::set_names(input$upload$name)
})
Full app:
library(shiny)
library(tidyverse)
library(DT)
# create some data to upload
write_csv(mtcars, "mtcars.csv")
write_csv(mpg, "mpg.csv")
write_csv(iris, "iris.csv")
options(shiny.maxRequestSize = 30 * 1024^2)
ui <- fluidPage(
fileInput("upload", NULL, buttonLabel = "Upload...", multiple = TRUE),
DT::DTOutput("files"),
tableOutput("selected_file_table")
)
server <- function(input, output, session) {
output$files <- DT::renderDT({
DT::datatable(input$upload, selection = c("single"))
})
# read all the uploaded files
all_files <- reactive({
req(input$upload)
purrr::map(input$upload$datapath, read_csv) %>%
purrr::set_names(input$upload$name)
})
#select a row in DT files and display the corresponding table
output$selected_file_table <- renderTable({
req(input$upload)
req(input$files_rows_selected)
all_files()[[
input$upload$name[[input$files_rows_selected]]
]]
})
}
shinyApp(ui, server)
There are two stages to this:
When you select a file what happens is that is gets copied into a temp directory. One of the values returned by the input is the location of the temp file, another is the original file name.
Once you have the file path you can use a function to read the data from that temp file.
The example at the bottom of this should be helpful (although your example needs a little bit more than this one because you have selected multiple files):
https://shiny.rstudio.com/reference/shiny/1.6.0/fileInput.html

How to use test.R to unmerge the column using R shiny

After I get the column name from the user, I want to unmerge the column 'alpha.'
I have the dataframe, and I have the same dataframe on my system as a csv file. (I'm highlighted the dataframe here for clarity) -> All of the following is occurring in the r script named test.R
What I'm looking for is a way to use test.R When I click the "Unmerge" button in R shiny, I should get the results (with unmerging columns) and the final dataset should render in the main panel.
Since I'm new to R Shiny, I'm not sure how to go about doing it.
Could someone please help me?
Note: The browse button should take the same data frame as csv and provide the unmerged results in the main panel.
test.R
library(dplyr)
library(tidyr)
library(stringr)
library(tidyverse)
library(stringr)
library(svDialogs)
column_name <- dlg_input("Enter a number", Sys.info()["user"])$res
before_merge<- data.frame(ID=21:23, alpha=c('a b', 'c d', 'e z'))
before_merge
library(reshape2)
newColNames <- c("type1", "type2")
#column_name <- readline(prompt="Enter the desired column name: ")
newCols <- colsplit(before[[column_name]], " ", newColNames)
after_merge <- cbind(before, newCols)
after[[column_name]] <- NULL
after_merge
Shiny App
## Only run examples in interactive R sessions
library(shiny)
if (interactive()) {
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File", accept = ".csv"),
checkboxInput("header", "Header", TRUE),
actionButton("dataset2", "Extract", class = "btn-primary"),
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output) {
output$contents <- renderTable({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
read.csv(file$datapath, header = input$header)
})
observeEvent(input$dataset2, {
source("test.R", local = TRUE)
})
}
shinyApp(ui, server)
}
So what you want to do is twofold:
First, remove the dialog input from test.R and put in a corresponding input in Shiny itself. This is to identify the column, right? You can make a selectInput with the options being the column names that the dataframe has.
Next, put all the relevant code into a function. This function should do the following: take in an input dataframe (you are creating this before_merge in test.R, instead, use the dataframe that you are getting from the upload), do whatever you need to do (the colsplit, etc.), and then return the final result.
Once you have that, then it's just a matter of putting a line at the top of your Shiny file where you source your test.R, and then you can call the function directly.
Alternatively, you don't even need a separate test.R file - just put your function above the output$contents section and use it directly. It's useful to have a separate helper file if you have a lot of functions (or the functions are used elsewhere), but in this case you don't need it.

Accessing data in different parts of server() in shiny

I am having a problem with accessing data in different parts of my server() function. The basic structure is something like this:
server <- shinyServer(function(input, output) {
# get the data from a file obtained from a textInput in the ui
data <- reactive({
req(input$file)
file <- input$file$datapath
# process the file and return a new dataframe
})
output$head <- renderTable({
mydf <- data()
head(mydf)
})
output$tail <- renderTable({
mydf <- data()
tail(mydf)
})
})
I would like to avoid having to call data() twice but I haven't found a way to do that.
Edit following the comment by #KentJohnson
What I am trying to achieve is for the user to select a file to open, using textInput, and after the file is opened, the app should do some processing and populate the two tables in the ui. After this, the user then chooses some other actions which also require the same data.
I wanted to avoid having to call data() twice but I haven't found a way to do that. I was assuming that each call would mean reading from the file each time. The file is very large so that is my motivation.
As #KentJohnson points out, reactive already achieves your goal. The expression that makes up data...
req(input$file)
file <- input$file$datapath
# process the file and return a new dataframe
...only runs when input$file$datapath changes. It does not rerun each time data() is called.
Putting your two tables into an observe environment makes it possible to call data() only twice, but I don't know if it will fit with what you want to do. Notice that here, I didn't put a textInput or things like that because my point was to show the observe environment. I'll let you adapt it to your situation (since you didn't put the ui part in your post):
library(shiny)
ui <- basicPage(
fileInput("file",
"Import a CSV file",
accept = ".csv"),
tableOutput("head"),
tableOutput("tail")
)
server <- shinyServer(function(input, output) {
# get the data from a file obtained from a textInput in the ui
data <- reactive({
req(input$file)
inFile <- input$file
read.csv(inFile$datapath, header = F, sep = ";")
# process the file and return a new dataframe
})
observe({
mydf <- data()
if (is.null(mydf)){
output$head <- renderTable({})
output$tail <- renderTable({})
}
else {
output$head <- renderTable({
head(mydf)
})
output$tail <- renderTable({
tail(mydf)
})
}
})
})
shinyApp(ui, server)
Edit: I misunderstood the OP's question, see #SmokeyShakers' answer for a more appropriate answer.

Shiny Server get number of records in a dataframe

Im trying to learn shiny and to read in an excel sheet and show both the contents of the excel sheet and the number of records in the UI
I'm a bit lost. when i read in the data set, how do i reference the dataframe that i have read in
# Server Code
server <- shinyServer(function(input, output) {
# Read the Data in
library(xlsx)
# Output the actual Table
output$contents <- renderTable({
test_df <- read.xlsx(inFile$datapath,1)
test_df
)})
# Output the number of records to check
output$text <- renderText({
paste("Number of records is:", nrow(test_df))
})
})
Best practice would be to have your library calls and any read_* functions in your global.R file (which should be in the same directory as server.R and ui.R. global.R will be parsed at the beginning of your web application and the file will be available in both the ui and the server (though you only need it in the server here).
So something like:
#in globar.R
library(xlsx)
test_df <- read.xlsx(inFile$datapath,1)
#and server
server <- shinyServer(function(input, output) {
# Output the actual Table
output$contents <- renderTable({
test_df
)})
# Output the number of records to check
output$text <- renderText({
paste("Number of records is:", nrow(test_df))
})
})
should work fine.

Calling the filename from a reactive dataset in shiny r

I am currently writing a shiny app which imports a dataset and displays a manipulated version. To work on the shiny methods I am currently working on a simplified version which displays the imported dataset. I currently assign the imported dataset to a reactive value, and then use the render table as follows:-
shinyServer(function(input, output) {
DATA<-reactive({
input$filein
})
output$Dataset <- renderTable({
DATA()
})
})
The interface then produces a table with the following columns:-
name, size, type, datapath.
What I had in mind was to call the datapath variable, and use read.csv to call it within the renderTable function. I tried using:-
DATA()$datapath
However that doesn't seem to produce any result. Are there any other ways to extract this data within Shiny? I contemplated using vector indices as you would using regular R code however I am unsure as to whether or not that'll work within Shiny.
Here is an example for files in the current working directory. The example file I used was a minimal csv file (see bottom). Please note however that this is indeed limited to files in your working directory. If you want other files to be loaded you will need to have a further component to specify the path (possibly in the selectInput).
library(shiny)
library(tools)
runApp(
list(
ui = pageWithSidebar(
headerPanel("File Info Test"),
sidebarPanel(
p("Demo Page."),
selectInput("filein", "Choose File", choices=c("test.csv"))
),
mainPanel(
tableOutput("myTableInfo"),
tableOutput("myTable")
)
),
server = function(input, output){
mydata <- reactive({
read.csv(input$filein)
})
file_info <- reactive({
validate(
need(!is.null(input$filein), "please select file"
)
)
name <- input$filein
size <- file.info(input$filein)[['size']]
type <- file_ext(input$filein)
datapath <- file_path_as_absolute(input$filein)
cbind(name, size, type, datapath)
})
output$myTableInfo <- renderTable({
file_info()
})
output$myTable <- renderTable({
mydata()
})
}
)
)
test.csv
X1,X2,X3
1,2,3
4,5,6

Resources