I want to access and use several objects from an uploaded .Rdata file by a Shiny App user.
It is possible by a simple call a load() in the global.R to access several objects stored in a .Rdata but I can't figure out how to access and use these when the .Rdata file is uploaded.
A reproducible example that mimics this related question where the .Rdata file contains only one object.
library(shiny)
# Define several objects and store them to disk
x <- rnorm(100)
y <- rnorm(200)
z <- "some text for the title of the plot"
save(x, file = "x.RData")
save(x, y, z, file = "xyz.RData")
rm(x, y, z)
# Define UI
ui <- shinyUI(fluidPage(
titlePanel(".RData File Upload Test"),
mainPanel(
fileInput("file", label = ""),
actionButton(inputId="plot","Plot"),
plotOutput("hist"))
)
)
# Define server logic
server <- shinyServer(function(input, output) {
observeEvent(input$plot,{
if ( is.null(input$file)) return(NULL)
inFile <- isolate({input$file })
file <- inFile$datapath
# load the file into new environment and get it from there
e = new.env()
name <- load(file, envir = e)
data <- e[[name]]
# Plot the data
output$hist <- renderPlot({
hist(data)
})
})
})
# Run the application
shinyApp(ui = ui, server = server)
This works when uploading x.RData but not with xyz.RData that gives the following error message:
Warning: Error in [[: wrong arguments for subsetting an environment
Stack trace (innermost first):
65: observeEventHandler [/Users/.../Desktop/app.R#31]
1: runApp
Ideally, since the three different objects in the .RData will be reused, I am looking for a solution that would create reactive elements x(), y(), z() that could be reused across several renderXXX().
This code works:
library(shiny)
# Define several objects and store them to disk
x <- rnorm(100)
y <- rnorm(200)
z <- "some text for the title of the plot"
save(x, file = "x.RData")
save(x, y, z, file = "xyz.RData")
rm(x, y, z)
# Define UI
ui <- shinyUI(fluidPage(
titlePanel(".RData File Upload Test"),
mainPanel(
fileInput("file", label = ""),
actionButton(inputId="plot","Plot"),
tableOutput("contents"),
plotOutput("hist"))
)
)
# Define server logic
server <- shinyServer(function(input, output) {
observeEvent(input$plot,{
if ( is.null(input$file)) return(NULL)
inFile <- isolate({input$file })
file <- inFile$datapath
load(file, envir = .GlobalEnv)
# Plot the data
output$hist <- renderPlot({
plot(x,y[1:100],main=z)
})
})
})
# Run the application
shinyApp(ui = ui, server = server)
Produces the plot like:
Related
I'm having an issue which I thought would have been very simple to solve, but I cannot figure it out.
I simply want to pass an uploaded csv file to a custom function in Shiny and output the result which is a ggplot graph. Here is my code for doing so
# Getting the file names
rdsfiles <- list.files(pattern = "\\.Rds$")
# --- Front End ---
ui <- shinyUI(fluidPage(theme = shinytheme("cerulean"), pageWithSidebar(
# Title
headerPanel("Title"),
# Sidebar to select a dataset
sidebarPanel(
selectInput("obj", "Choose a dataset:",
choices = rdsfiles),
fileInput("tissue_csv",
"Load tissue positions .csv file",
accept = c("text/csv", "text/comma-separated-values,text/plain",".csv")
),
textInput("feature", label = "Gene"),
),
# Different analyses available
mainPanel(
tabsetPanel(
tabPanel('UMAP', plotOutput("umap")),
tabPanel('Tissue', plotOutput("tissue")),
tabPanel('Gene Expression', plotOutput("genex")),
))
)))
# --- Back end ---
server <- shinyServer(function(input, output) {
# Return the requested datasets
datasetInput <- reactive({
df <- readRDS(input$obj, input$obj)
return(df)
})
tissueInput <- reactive({
inFile <- req(input$tissue_csv)
read.csv(inFile$datapath)
})
### HERE IS WHERE THE ERROR LIES ###
output$tissue <- renderPlot({
obj <- datasetInput()
tiss <- tissueInput()
custom_function(obj, tiss)
})
# Retrieve the UMAP projection
output$umap <- renderPlot({
obj <- datasetInput()
DimPlot(obj, reduction = "umap")
})
})
shinyApp(ui, server)
Whenever I use the app and upload my .csv file, it always gives me an error message that says 'file' must be a character string or connection. Why is this? Any suggestions?
I have an R shiny app that gets a .csv import from a user and searches the imported data across a built-in data frame, then gives the % match in the output. The UI is very simple, with a few different inputs (import .csv, a slider, and some radio buttons). What I want is to be able to take the reactive table output and print this to a .csv that the user can download to their machine. The server side of the app looks something like this:
server <- function(input, output){
rvals <- reactiveValues()
observeEvent(input$file_1,{
req(input$file_1)
rvals$csv <<- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
if(input$select == 1){
x <- function
}else if(input$select == 2){
x <- function
}else if(input$select == 3){x <- function}
#some more data processing and formatting here
return(x)
},digits = 4)
}
I would like to have the data table x be able to become a .csv that can be downloaded by clicking a download button. In the server, I added the following code, but when I try to download the data it just downloads a blank file and says "SERVER ERROR" in my downloads manager on my machine.
output$downloadData <- downloadHandler(
filename = "thename.csv",
content = function(file){
write.csv(x, file)
}
In the console I also get the error message:
Warning: Error in is.data.frame: object 'x' not found [No stack trace available]
The object you create inside the expression of renderTable is not available outside of it. Instead you could assign it to the reactive values you set up. Below is a working example (note that I have tried to replicate your code so the data will not be available until you click on "Upload CSV", which here just calls mtcars).
library(shiny)
ui = fluidPage(
sidebarPanel(
actionButton(inputId = "uploadCsv", label = "Upload CSV:", icon = icon("upload")),
selectInput(inputId = "preProc", label = "Pre-processing", choices = c("Mean"=1,"Sum"=2)),
downloadButton("downloadData", label = "Download table")
),
mainPanel(
h4("My table:"),
tableOutput("contents")
)
)
server <- function(input, output) {
rvals <- reactiveValues(
csv=NULL,
x=NULL
)
observeEvent(input$uploadCsv,{
rvals$csv <- mtcars # using example data since I don't have your .csv
# rvals$csv <- read.csv(input$file_1$datapath, header = TRUE)
#some data processing here
})
output$contents <- renderTable({
# Assuing the below are functions applied to your data
req(
input$preProc,
!is.null(rvals$csv)
)
if(input$preProc == 1){
rvals$x <- data.frame(t(colMeans(mtcars)))
}else {
rvals$x <- data.frame(t(colSums(mtcars)))
}
return(rvals$x)
},digits = 4)
output$downloadData <- downloadHandler(
filename = "myFile.csv",
content = function(file){
write.csv(rvals$x, file)
}
)
}
shinyApp(ui,server)
EventReactive already outputs a reactive value, you don't need to create an extra reactiveVal, see example below :
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Test"),
mainPanel(
actionButton("show", "Download"),
textOutput("result")
)
)
server <- function(input, output) {
csvfile <- eventReactive(req(input$show), ignoreNULL = T, {
"Content of file"
})
output$result <- reactive(
paste("result : ",csvfile()))
}
# Run the application
shinyApp(ui = ui, server = server)
I would also avoid to use <<-operator in a reactive expression.
I want to import a .RData file with fileInput but It doesn't work, I have this error message :
Error in my.data$TYPE_DE_TERMINAL : $ operator is invalid for
atomic vectors
dt <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
load(inFile$datapath)
})
GetData <- reactive({
my.data <- dt()
When I try my application with a .RData imported manually it works well (I remplaced dt() directly with a dataframe in my directory) ...
The following example solves the problem. It allows you to upload all .RData files.
Thanks to #Spacedman for pointing me to a better approach of loading the data:
Load the file into a new environment and get it from there.
For the matter of the example being "standalone" I inserted the top section that stores two vectors to your disk in order to load and plot them later.
library(shiny)
# Define two datasets and store them to disk
x <- rnorm(100)
save(x, file = "x.RData")
rm(x)
y <- rnorm(100, mean = 2)
save(y, file = "y.RData")
rm(y)
# Define UI
ui <- shinyUI(fluidPage(
titlePanel(".RData File Upload Test"),
mainPanel(
fileInput("file", label = ""),
actionButton(inputId="plot","Plot"),
plotOutput("hist"))
)
)
# Define server logic
server <- shinyServer(function(input, output) {
observeEvent(input$plot,{
if ( is.null(input$file)) return(NULL)
inFile <- isolate({input$file })
file <- inFile$datapath
# load the file into new environment and get it from there
e = new.env()
name <- load(file, envir = e)
data <- e[[name]]
# Plot the data
output$hist <- renderPlot({
hist(data)
})
})
})
# Run the application
shinyApp(ui = ui, server = server)
I'm currently working on image processing application using R Shiny It uploads an image using file upload and then I need to read the image to do the image processing operations. server.R file is as follows.
library(shiny)
library(EBImage)
library(imager)
library(jpeg)
function(input, output) {
observe({
file_path <- input$files
if (is.null(file_path))
return(NULL)
file_path$datapath <- gsub("\\\\", "/", file_path$datapath)
img <- readImage(file_path$datapath)
equalized <- equalize(img,range = c(0, 1), levels = 256)
output$text <- renderText({
file_path$datapath
})
output$img <- renderImage({
list(src = file_path$datapath,
contentType = "image/jpg",
width = "50%",
height = "auto",
alt = "This is alternate text")
})
})
}
But this gives me the following error.
Warning: Error in readImage: Please supply at least one filename.
Stack trace (innermost first):
57: readImage
56: observerFunc
I managed to plot an equalized image using raster method. Here are some tips/tricks:
You put everything inside an observer which is a pretty bad idea, so I got rid of that.
Use req() when checking whether a file is uploaded, UI is rendered, etc instead of an if statement. `
if (is.null(file_path)) return(NULL)
There is no need to assign input$files to a variable, you can call input$files$datapath. Also gsub() is not needed in this case.
file_path <- input$files
file_path$datapath <- gsub("\\\\", "/", file_path$datapath)
equalized is calculated, but you don't use it anywhere.
Solution
Checking with req() whether a file is uploaded.
Get the extension of the file (splitting by ., getting the last element)
Plot the equalized image using the display() function with method = "raster".
Print datapath which points to a temp dir/file
See:
library(shiny)
library(EBImage)
library(imager)
library(jpeg)
ui <- fluidPage(
fileInput("files", "Upload a file"),
plotOutput("img"),
textOutput("txt")
)
server <- function(input, output) {
output$img <- renderPlot({
req(input$files)
st <- strsplit(input$files$name, split = "[.]")[[1]]
extension <- st[length(st)]
display(equalize(readImage(input$files$datapath, type = extension), range = c(0, 1), levels = 256), method = "raster")
})
output$txt <- renderText({
input$files$datapath
})
}
shinyApp(ui, server)
Using EBImage we can load an image into Rshiny and use it for further processing. Below code allows the user to upload an image and then same is displayed on shiny screen back.
library(shiny)
library(EBImage)
upload_image <- list()
ui <- fluidPage(
fileInput("file1", "Upload an Image"),
plotOutput("img")
)
server <- function(input, output) {
output$img <- renderPlot({
req(input$file1)
upload_image[[1]] <- readImage(input$file1$datapath)
plot(upload_image[[1]])
})
}
shinyApp(ui , server)
Beginner Shiny question.
I have two models living in different folders, A and B, both called inputs.R, and want to load one or the other using selectInput to choose the folder (in reality, there is more than one file in each folder, so I don't want to load the file directly).
Currently, I have
ui <- fluidPage(selectInput("model_folder", "Select folder", c("A", "B")))
server <- function(input, output){
reactive({
inpts <- paste0("models/",input$model_folder, "/inputs.R")
source(inpts, local = T)
})
}
This does not work. Any thoughts would be greatly appreciated.
This will depend where you have your 'models' folder stored. So, pretend it is in the same directory as your shiny app. Here is some code that should recreate this situation, along with some models and data in the two separate folders. Just change the variable appDir to wherever you don't have a folder.
## Create the models/folders in a temporary location
## define it in appDir
appDir <- 'c:/path/to/temp/app'
dir.create(appDir)
dir.create(file.path(appDir, "models"))
for (i in 1:2) {
dir.create((folder = file.path(appDir, "models/", LETTERS[i])))
code <- bquote({
dat <- data.frame((x=rnorm(100)), y=rnorm(100, mean=.(i)*x))
mod <- lm(y ~ x, data=dat)
})
writeLines(deparse(code), file.path(folder, 'input.R'))
}
Then, in the new folder appDir, create a file app.R, which will be the example application. There are problems with how you are trying to use reactive, illustrated below. I capture all the variables from the sourced input.R files using mget() in this example.
library(shiny)
app <- shinyApp(
ui = fluidPage(
selectInput("model_folder", "Select folder", c("A", "B")),
uiOutput('info'),
tableOutput('summ')
),
server = function(input, output) {
output$info <- renderUI({
inp <- inpts()
list(
helpText(sprintf("Now looking at variables from %s", inp$name)),
radioButtons('vars', 'Variables', choices=names(inp), inline=TRUE)
)
})
output$summ <- renderTable({
inp <- inpts()
if (input$vars == 'mod') summary(inp$mod)
})
inpts <- reactive({
name <- file.path("models", input$model_folder, "input.R")
source(name, local=TRUE)
mget(ls())
})
}
)
Now, to run it you can just do
library(shiny)
runApp(appDir = normalizePath(appDir))