R - `reactive` after `observeEvent` in shiny - r

I have a shiny app that takes a .csvfile as input and do some calculations and plot graphs.
the problem is, since the data input is reactive, places where i show my plots shows error till i upload a csv, as shown in image below.
Here's the part of the code in my server, that shows error:
patient_type_data <- reactive({
--my code that subsets the data based on other
})
wait_data is a reactive variable containing data from .csv uploaded.
I've tried to solve it like:
patient_type_data <- reactive({
observeEvent(wait_data(), --my code--)
})
and
patient_type_data <- observeEvent(wait_data(),
reactive({--my code--})
)
both always returned some error at some point.
So, how do i not let the functions execute, as long as the .csv is not uploaded or solve this errors?

Related

Manipulating a user-uploaded file/data in R shiny

I've been working on an R shiny app that is supposed to take a user-uploaded .csv file, do a bunch of manipulations/calculations to that data, and then spit out some graphs. I am completely new to shiny, however, and am very lost. I've tried to look this up, but most results I found take the data and directly show it in a graph. So far I've tried this (code is taken from here):
UI:
ui <- fluidPage(
fileInput("userfile", "Choose CSV File", multiple = TRUE,
accept=c("text/csv","text/comma-separated-values,text/plain",".csv")),
# etc.
Server:
server <- function(input,output){
df <- read.csv(input$userfile$datapath)
# some manipulation, such as adding a new column, for example:
df$timestwo <- 2 * df$column1
}
Is df in the Server code supposed to be the dataframe that was read in from the user-uploaded file? If not, how can I create a dataframe that is able to go through several changes, before making a graph? When I try to run my code I get "Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer." Thanks!
Edit to add: all the data manipulation I wanted to do worked with my sample dataset, but not the user-input one I tried out (which was the exact same data).

R Shiny - dataset load in a first chunk doesn't exist in a second chunk ...?

I have a strange error in a shiny app I built with the library learnr. An error "Object not found" about an object I just loaded and just visualized (meaning the object exists no ?)
Although I don't have a reproducible example, some of you will maybe understand what is creating the error :
I have a first chunk {r load} that loads a dataset. There is no error here, I can even visualize the dataset (screenshot below)
Then I have a second chunk, where I would like to manipulate the dataset. But it tells me dataset doesn't exist ! How it could be possible, I just visualized it one chunk before ?! ...
I don't understand how a dataset could be exists in a chunk, and not in another. Does it mean the dataset isn't loaded in the global environment ? Is it a problem with the learnr library ?
Maybe someone will have an idea, or something I could test. Thank you in advance.
EDIT:
The problem is about the environment/workspace. In the first chunk, even if I load the dataset, it is not store in the environment. I tested the function ls() in a second chunk, and it tells me there is no object in the workspace. The loaded dataset is not here, I don't know why ...
In my opinion, shiny doesn't store any data. You have to pass it manually from one chunk to other as follow (only adding the code snippet from server):
server <- function(input, output, session) {
output$heat <- renderPlotly({
Name<-c("John","Bob","Jack")
Number<-c(3,3,5)
Count<-c(2,2,1)
NN<-data.frame(Name,Number,Count)
render_value(NN) # You need function otherwise data.frame NN is not visible
# You can consider this as chunk 1
})
render_value=function(NN){
# Here your loaded data is available
head(NN)
# You can consider this as chunk 2
})
}
}
shinyApp(ui, server)
You can find full code here: Subset a dataframe based on plotly click event
OR
Create global.R file as suggested here and follow this URL: R Shiny - create global data frame at start of app

ShinyApp reactive error while trying to select variables from imported data set

I am very new to Shiny and R in general and I am building an app that allows users to import data, select their variables, number of trees.. ect and then run that through a random forest script and have it display the outputs. Right now I am just working on the inputs, however, I am running into a problem. The user can import a CSV but then they cannot select their variables (headers from csv). I am trying to make it reactive so the user first must import their csv before the option of selecting their variables pops up (seems simple).
Here is my code right now:
ui.R
server.R
Error in Console
I am probably just making a silly mistake because I am unfamiliar with Shiny but your help would be much appreciated.
A little background info
First off, I recommend you read this through to get a good understanding of reactivity in Shiny: Shiny Reactivity Overview. This helps a lot with variable scoping in a Shiny context too: Scoping Rules in Shiny Apps.
The issue
I believe this issue is due to you defining the variable file_to_read within the scope of shiny output: output$input_file in your server.R file. When the function read.table() looks for the variable file_to_read, it doesn't exist since it is only defined within the scope of the shiny output.
Try making a reactive value and then assigning the input$file value to it once it is uploaded by the user. You'll also have to convert your dat1 variable to a shiny reactive since you can only read reactive values in the context of other reactive sources (e.g. observe(), reactive(), observeEvent(), etc.)
file_to_read <- reactiveVal(NULL) # Set the value to NULL to initialize
output$input_file <- renderTable({
if (is.null(input$file)) return () # Check there is an input file
file_to_read(input$file) # Set the reactiveVal to the input file
})
# Make dat1 a reactive so it can be read within a shiny reactive
dat1 <- reactive({
if(is.null(file_to_read()) return (NULL) # Check for input file in reactiveVal
read.table(file_to_read()$datapath, sep = input$sep, header = input$header)
})
# Make an eventReactive to capture when there is read.table() data from dat1
reactive1 <- eventReactive(dat1, {
if (is.null(dat1)) return ()
D <- colnames(dat1)
return (list(D, D[1]))
})
I didn't test this code since you posted your data in image format and I don't have an input file, but hope this helps your error.

Shiny App - passing the string to variable

I am trying to build Shiny App that does sentiment analysis. I have the code that works fine when i execute the script normally where Rstudio is importing the data from email.csv file. This file contains only 2 columns ( SentTo and RawText) and the text i am analyzing is located in B2 cell.
Once i run the code below i get nice chart that measure the sentiment.
library(readr)
library("ggplot2")
library('syuzhet')
Emails <- read_csv("C:/email.csv")
d<-get_nrc_sentiment(Emails$RawText)
td<-data.frame(t(d))
td_new <- data.frame(rowSums(td[1:14]))
names(td_new)[1] <- "count"
td_new <- cbind("sentiment" = rownames(td_new), td_new)
rownames(td_new) <- NULL
td_new2<-td_new[1:8,]
qplot(sentiment, data=td_new2, weight=count,
geom="bar",fill=sentiment)+ggtitle("Email sentiments")
Now what i am trying to do is to modify this code a bit and build the Shiny application by doing next:
ui.R
# Adding the Imput text field to the app
shinyUI(fluidPage(
textAreaInput("UserInput", "Caption", "Please Enter Your Text", width =
"500px", height = "300px"),
mainPanel(
plotOutput("distPlot"))
))
Server.R
library(shiny)
library(syuzhet)
library(ggplot2)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
Emails <- input$UserInput
d<-get_nrc_sentiment(Emails)
td<-data.frame(t(d))
td_new <- data.frame(rowSums(td[1:14]))
names(td_new)[1] <- "count"
td_new <- cbind("sentiment" = rownames(td_new), td_new)
rownames(td_new) <- NULL
td_new2<-td_new[1:8,]
qplot(sentiment, data=td_new2, weight=count,
geom="bar",fill=sentiment)+ggtitle("Email sentiments")
})
})
After i run the app i get this error:
So ti builds the app but even when i paste some text in to the field it seems that the code i am using in server.R part is not doing what it needs to do.
If i replace the line in server.R part (Emails <- input$UserInput) with (Emails <- read_csv("C:/email.csv"))
than it works fine. This tells me that the issue is within the way i am passing the text to the Emails. Through the input form its text through the csv file it is a second row and second column that contains the data. The code that follows i think its looking that specific format.
Anybody has suggestion on how to modify this to make it work?
Thank you in advance.
I believe the issue is in line:
td_new <- data.frame(rowSums(td[1:14]))
If I change it to the following, it works for me:
td_new <- data.frame(rowSums(td))
I'm not sure why you had the 1:14 index in there, but I don't see what it does.
Before plotting in shiny, first have it output the user input so that you understand what is being passed to the next step. verbatimTextOutput('input$UserInput') and verbatimTextOutput('dput(input$UserInput)'). I'm guessing this will be a character vector of length 1.
Now, go back to your code outside of shiny and pass it this same input, formatted exactly the same. Right now your code that works is getting a data.frame from a csv file and passed a column, which would be a character vector.
Once you get it working outside of shiny, using the input as parsed by shiny, the fixes to make your shiny app work should be clear.

Reading an RData file into Shiny Application

I am working on a shiny app that will read a few RData files in and show tables with the contents. These files are generated by scripts that eventually turns the data into a data frame. They are then saved using the save() function.
Within the shiny application I have three files:
ui.R, server.R, and global.R
I want the files to be read on an interval so they are updated when the files are updated, thus I am using:
reactiveFileReader()
I have followed a few of the instructions I have found online, but I keep getting an error "Error: missing value where TRUE/FALSE is needed". I have tried to simplify this so I am not using:
reactiveFileReader()
functionality and simply loading the file in the server.R (also tried in the global.R file). Again, the
load()
statement is reading in a data frame. I had this working at one point by loading in the file, then assigning the file to a variable and doing an "as.data.table", but that shouldn't matter, this should read in a data frame format just fine. I think this is a scoping issue, but I am not sure. Any help? My code is at:
http://pastebin.com/V01Uw0se
Thanks so much!
Here is a possible solution inspired by this post http://www.r-bloggers.com/safe-loading-of-rdata-files/. The Rdata file is loaded into a new environment which ensures that it will not have unexpected side effect (overwriting existing variables etc). When you click the button, a new random data frame will be generated and then saved to a file. The reactiveFileReader then read the file into a new environment. Lastly we access the first item in the new environment (assuming that the Rdata file contains only one variable which is a data frame) and print it to a table.
library(shiny)
# This function, borrowed from http://www.r-bloggers.com/safe-loading-of-rdata-files/, load the Rdata into a new environment to avoid side effects
LoadToEnvironment <- function(RData, env=new.env()) {
load(RData, env)
return(env)
}
ui <- shinyUI(fluidPage(
titlePanel("Example"),
sidebarLayout(
sidebarPanel(
actionButton("generate", "Click to generate an Rdata file")
),
mainPanel(
tableOutput("table")
)
)
))
server <- shinyServer(function(input, output, session) {
# Click the button to generate a new random data frame and write to file
observeEvent(input$generate, {
sample_dataframe <- data.frame(a=runif(10), b=rnorm(10))
save(sample_dataframe, file="test.Rdata")
rm(sample_dataframe)
})
output$table <- renderTable({
# Use a reactiveFileReader to read the file on change, and load the content into a new environment
env <- reactiveFileReader(1000, session, "test.Rdata", LoadToEnvironment)
# Access the first item in the new environment, assuming that the Rdata contains only 1 item which is a data frame
env()[[names(env())[1]]]
})
})
shinyApp(ui = ui, server = server)
Ok - I figured out how to do what I need to. For my first issue, I wanted the look and feel of 'renderDataTable', but I wanted to pull in a data frame (renderDataTable / dataTableOutput does not allow this, it must be in a table format). In order to do this, I found a handy usage of ReportingTools (from Bioconductor) and how they do it. This allows you to use a data frame directly and still have the HTML table with the sorts, search, pagination, etc.. The info can be found here:
https://bioconductor.org/packages/release/bioc/html/ReportingTools.html
Now, for my second issue - updating the data and table regularly without restarting the app. This turned out to be simple, it just took me some time to figure it out, being new to Shiny. One thing to point out, to keep this example simple, I used renderTable rather than the solution above with the ReportingTools package. I just wanted to keep this example simple. The first thing I did was wrap all of my server.R code (within the shinyServer() function) in an observe({}). Then I used invalidateLater() to tell it to refresh every 5 seconds. Here is the code:
## server.R ##
library(shiny)
library(shinydashboard)
library(DT)
shinyServer(function(input, output, session) {
observe({
invalidateLater(5000,session)
output$PRI1LastPeriodTable <- renderTable({
prioirtyOneIncidentsLastPeriod <- updateILP()
})
})
})
Now, original for the renderTable() portion, I was just calling the object name of the loaded .Rdata file, but I wanted it to be read each time, so I created a function in my global.R file (this could have been in server.R) to load the file. That code is here:
updateILP <- function() {
load(file = "W:/Projects/R/Scripts/ITPOD/itpod/data/prioirtyOneIncidentsLastPeriod.RData", envir = .GlobalEnv)
return(prioirtyOneIncidentsLastPeriod)
}
That's it, nothing else goes in the global.R file. Your ui.R would be however you have it setup, call tableOutout, dataTableOutput, or whatever your rendering method is in the UI. So, what happens is every 5 seconds the renderTable() code is read every 5 seconds, which in turns invokes the function that actually reads the file. I tested this by making changes to the data file, and the shiny app updated without any interaction from me. Works like a charm.
If this is inelegant or is not efficient, please let me know if it can be improved, this was the most straight-forward way I could figure this out. Thanks to everyone for the help and comments!

Resources