Reactive Loading in R Shiny [duplicate] - r

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)

Related

Read and Use Several Objects in an .RData fileInput in Shiny

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:

Image Processing Operations inside R shiny server.R

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)

shiny fileinput r dataframe

Using R shiny, I am developing a simple app that allows user to input data from a file. With csv or txt files everything works fine, but I can not make R dataframes to load.
## SERVER.R
shinyServer(function(input, output) {
infile <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
infile<load(input$datafile$datapath)
})
myData <- reactive({
df<-infile()
if (is.null(df)) return(NULL)
})
output$value1 <- renderPrint({
names(iris)
})
output$value2 <- renderPrint({
names(myData())
})
load("iris.Rdata") ## data loaded for testing
})
## UI.R
shinyUI(fluidPage(
fileInput("datafile", label = h3("File input")),
fluidRow(column(4, verbatimTextOutput("value1"))),
fluidRow(column(4, verbatimTextOutput("value2")))
))
When I run this app I can see the names of the iris dataset loaded only for testing, but respect the names of the loaded file (which should be rendered as value2) only shows "NULL"
Any help?? thanks in advance!
I think this is what you want. You had a couple of typos, and you probably didn't quite understand what load actually does, it loads a set of objects into memory.
I did the following things:
added some initialization code to save a couple of .Rdata for testing, they both have exactly one object in them, a dataframe. The code needs this.
add a line to parse out the first object in that loaded datafile and return it
Here is the code:
server.r
## SERVER.R
#Initialization
library(datasets)
save(iris,file="iris.Rdata")
save(mtcars,file="m.Rdata")
shinyServer(function(input, output) {
infile <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
objectsLoaded <- load(input$datafile$name)
# the above returns a char vector with names of objects loaded
df <- eval(parse(text=objectsLoaded[1]))
# the above finds the first object and returns it
return(df)
})
myData <- reactive({
df<-infile()
if (is.null(df)) return(NULL)
return(df)
})
output$value1 <- renderPrint({
names(iris)
})
output$value2 <- renderPrint({
names(myData())
})
load("iris.Rdata") ## data loaded for testing
})
ui.r
## UI.R
shinyUI(fluidPage(
fileInput("datafile", label = h3("File input")),
fluidRow(column(4, verbatimTextOutput("value1"))),
fluidRow(column(4, verbatimTextOutput("value2")))
))
Here is the output:

Source in reactive content Shiny

I want to split my app into smaller peaces for better handling.
server.R
library(shiny)
source("onLoad.R", local = TRUE)
shinyServer(function(input, output, session) {
sourceRecursive("/.../")
})
sourceRecursive
#check folder and all subfolders for .R files
#source() them!
sourceRecursive <- function(path) {
dirs <- list.dirs()
files <- dir(pattern = "^.*[Rr]$", include.dirs = FALSE)
for (f in files)
source(f)
for (d in dirs)
sourceRecursive(d)
}
example file I try to source. file.R
output$myChoices <- renderUI({
selectInput(inputId = 'x',
label = 'y',
choices = levels(myDataSet$df$z),
multiple = T
)
})
Bounces back with:
Error in output$myChoices <- renderUI({ :
object 'output' not found
Obviously the problem is that within the file.R the variable output is not defined since this is a variable which is used in the shiny context. How would I tell R (or shiny) to treat all the variables as shiny defined variables (such as output$whatever, input$something, reactive etc). That seems crucial to me in order to break up the programme into smaller peaces.
I'm using both source(local=TRUE) and sys.source to load the file into the proper environment, it seems to work:
library(shiny)
shinyServer(function(input, output, session) {
# From http://shiny.rstudio.com/articles/scoping.html
output$text <- renderText({
source('each_call.R', local=TRUE)
})
# Source in the file.R from the example in the question
sys.source('file.R', envir=environment())
})
I didn't test it, but you might be able to use:
sourceRecursive <- function(path, env) {
files <- list.files(path = path, pattern = "^.*[Rr]$", recursive = TRUE)
for (f in files) sys.source(f, env)
}
shinyServer(function(input, output, session) {
session.env <- environment()
sourceRecursive(path = ".", env = session.env)
})
What if you use local=TRUE in your call to source provided that sourceRecursive is in the right scope (maybe put it in server.R). See this documentation here

Source R file in reactive context (Shiny)

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

Resources