R Shiny: test existence of reactive value which is optional after req() - r

I have code like this
myfx <- reactive({
req(
isTruthy(input$value),
isTruthy(data1()) || isTruthy(data2())
)
...
if(exists(data2())) {
# do some stuff
}
## do this other stuff regardless
})
The if(exists()) piece is where I am stuck. Exists is not the right function here, nor does validate(need(data2())) work. How can I conditionally execute some code if one of the optional reactives (from a group where at least one is required) exists?
EDIT 1: To make explicit the problem, see the issue illustrated by the debug prints below:
myfx <- reactive({
req(
isTruthy(input$value),
isTruthy(data1()) || isTruthy(data2())
)
print("I am printed, and data2() has not been uploaded by user")
print(isTruthy(data2()))
print("I am never printed")
if(isTruthy(data2())) {
# do some stuff
}
## do this other stuff regardless
})
Edit 2: ok I see the reason. And I also see that I'm not observing the behavior in my first req() call because of short-circuiting (||). But now I'm stuck how to achieve the behavior I want. Bascially I don't calculate data2() until the user uploads something (use a req() here too). So that is where this is hanging. But if I remove the req() from the top of this, then I get errors due to trying to work on input that doesn't exist. See the definition for data2() below. How can I fix this?
data2 <- reactive({
req(input$data2)
read.csv(input$data2$datapath) %>%
as_tibble() %>%
return()
})

You can re-use isTruthy. Since it still returns true for 0 rows, you may want to add a check for non-zero row count:
myfx <- reactive({
req(
isTruthy(input$value),
isTruthy(data1()) || isTruthy(data2())
)
...
if (isTruthy(data2()) && nrow(data2()) > 0) {
# do some stuff
}
## do this other stuff regardless
})
Or you can capture the attempt in a try/tryCatch and react accordingly:
myfx <- reactive({
req(
isTruthy(input$value),
isTruthy(data1()) || isTruthy(data2())
)
...
res2 <- tryCatch({
# do some stuff with data2()
}, error = function(e) NULL)
## do this other stuff regardless
})

Ok, here is the final working solution.
myfx <- reactive({
req(
isTruthy(input$value),
isTruthy(data1()) || isTruthy(data2())
)
print("I am printed, and data2() has not been uploaded by user")
print(isTruthy(data2()))
print("I am never printed")
if(isTruthy(data2())) {
# do some stuff
}
## do this other stuff regardless
})
data2 <- reactive({
if(isTruthy(input$data2)) {
read.csv(input$data2$datapath) %>%
as_tibble() %>%
return()
}
})

raise an error if dat2 doesn't exit by checking number of rows
chk will become NULL if dat2 doens't exist
use chk in if statement to determine what to do
chk <- tryCatch({ nrow(dat2()) > 0}, error = function(e) NULL)
if(is.null(chk)){
dat1
} else{
cbind(dat1, dat2)
}

Related

renderText in RShiny with conditions If Else

I am in my server.r file and trying to create an output via renderText with a conditional statement. The below code is throwing me the error:
Error in .getReactiveEnvironment()$currentContext() :
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.)```
I have a feeling I have the architecture of this code wrong.
if (A > B)
{
output$sample <- renderText({ do some calculation)})
}
else if(A <= B)
{
output$sample <- renderText({do some other calculation)})
}
I have attempted to reformat to the below but get the same error. I feel I may be fundamentally wrong in my approach here. Any help welcomed.
output$sample <-
if (A > B)
{
renderText({ do some calculation)})
}
else if(A <= B)
{
renderText({do some other calculation)})
}
Server part where the issue was has been resolved here with some reactive objects. Please try this
ab <- reactive({req(input$account_value) - req(input$blocked_funds)})
# free funds
output$free_funds <- renderText({ab()})
# current margin
cm <- reactive({
req(input$account_value,input$blocked_funds)
if (input$account_value > input$blocked_funds){
curmargin <- round(input$account_value/(input$account_value+input$blocked_funds), digits = 2)
}else {
curmargin <- round((.5*(input$account_value))/input$blocked_funds, digits = 2)
}
})
output$current_margin <- renderText({cm()})
rm <- reactive({
req(input$account_value,input$blocked_funds)
round(input$account_value/(input$account_value + input$blocked_funds*2.5)*100,digits = 1)
})
# New margin
output$revised_margin <- renderText({
paste(rm(),"%",sep = "")
})

tryCatch error handling doesn't work in shiny app?

I'm doing some touch to my shiny app , the problem i'm encountering is that i can't handle the errors using tryCatch like :
tryCatch({
# expr
},
error = function(e) {
# handle the error
}
I'm using the Apriori algorithm within my application ,when the user choose a dataset ,he can also adjust the values of min-support and min-confidence, but sometimes with some values of these, apriori algorithm returns 0 rules , and the error occurs when trying to plot the graph of the association rules .
Here's a small spinet of my code so far :
Getting the file
...
...
...
Find the association rules :
rules <- reactive({
validate(
need(input$file, "Please choose a data set")
)
transactions = read.transactions(
file = file(input$file$datapath),
format = "basket",
sep = ","
)
minValue <- min(length(transactions),input$visualization)
rules <-
apriori(transactions[0:minValue],
parameter = list(
support = input$min_supp,
confidence = input$min_conf
))
print(length(transactions[0:minValue]))
return(rules)
})
Plot the obtained association rules :
output$graphChart <- renderPlot({
Sys.sleep(1)
validate(
need(input$file, "Please choose a data set")
)
set.seed(42)
# validate(
# need(length(rules()) == 0, "zero rules")
# )
tryCatch({
plot(rules(), method = "graph")
})
error = function(condition){
print('there was an error')
}
})
But nothing changed i still get the error and no message printed in the R studio's console
I tried this but it doesn't help me get rid of the error,
By the way i also get errors on other tabs when no rules found .
EDITED
As Pork mentioned in his comment ,i tried :
output$graphChart <- renderPlot({
Sys.sleep(1)
validate(
need(input$file, "Please choose a data set")
)
set.seed(42)
# validate(
# need(length(rules()) == 0, "zero rules")
# )
tryCatch({
plot(rules(), method = "graph",)
})
error=function(cond) {
message(cond)
return(NA)
}
warning=function(cond) {
message(cond)
# Choose a return value in case of warning
return(NULL)
}
})
And the error persist again,
Can someone help me please ?
Any suggestions or advice would be appreciated!
Thanks.
Here is a small example of how you may use tryCatch block. We shall use showNotification to notify the user of the error
library(shiny)
ui <- fluidPage(
sidebarPanel(width = 2,
selectInput("data","data",choices = c(1,2),selected = 1)
),
mainPanel(
plotOutput("graphChart")
)
)
server <- function(input, output, session) {
rules <- reactive({
if(input$data == 1){
return(mtcars$mpg)
}else{
"some error"
}
})
output$graphChart <- renderPlot({
tryCatch({
plot(rules())
}, warning = function(w) {
showNotification('there was a warning','',type = "error")
return()
}, error = function(e) {
showNotification('there was an error','',type = "error")
return()
}, silent=TRUE)
})
}
shinyApp(ui, server)

How do I make two observeEvent function for different options in selectinput

The result page in my program aims to respond differently to the different options the user enters. I feel observeEvent seems relevant but when I wrote this way it only displays the latest observeEvent (which is the female one).
Here is the simplified version of my code:
library(shiny)
ui <- fluidPage(
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Personal Information",
selectInput(
"gender",
"What is your biological gender?:",
c("--" = "null","male" = "gender1","female" = "gender2")
)
),
tabPanel("Result",
verbatimTextOutput("result")
)
)
)
)
server <- function(input, output) {
#Events
observeEvent(
{input$gender == "gender1"},
output$result <- renderPrint ("You are a male.")
)
observeEvent(
{input$gender == "gender2"},
output$result <- renderPrint ("You are a female.")
)
}
shinyApp(ui, server)
You should use one observeEvent that triggers whenever input$gender changes. Then have a conditional inside that which determines what value to return. You actually don't need the observeEvent at all, since any reactive expression (including a renderPrint) will update if any reactive values in it are invalidated. So the best way to do what you want is to replace bout observeEvent functions with the below:
output$result <- renderPrint({
if (input$gender == 'gender1') {
return("You are a male.")
} else if (input$gender == 'gender2') {
return("You are a female.")
}
})
The difference with using an event function vs a render* is that the code block is considered to be in an isolate block and only the change of the eventExpr will trigger the code to run. That's good if you want to make the code only run when an Update button is pressed, but if you want it to be reactive to changing values (like in your example) you shouldn't use an event function.
Also, you are strongly encouraged not to nest reactive expressions as you do above. If you must have an event function drive a renderPrint function (as in your example), the reccomended way of doing that is with an eventReactive:
gender_input <- eventReactive(input$update, {
if (input$gender == 'gender1') {
return("You are a male.")
} else if (input$gender == 'gender2') {
return("You are a female.")
}
})
output$result <- renderPrint({gender_input()})
Or you could place all in 1 observeEvent and depending on the condition, change the desired text and use it then in a renderPrint function like this:
server <- function(input, output) {
observeEvent(input$gender, {
if (input$gender == "gender1") {
txt <- "You are a male."
} else if (input$gender == "gender2") {
txt <- "You are a female."
} else {
txt <- NULL
}
output$result <- renderPrint(txt)
})
}
Allthough i would also favor the solution from #divibisan.
You could although use a reactiveValue, where the text is stored. In this way, you can access the text everywhere in your server function and you dont have to nest the rnderPrint function inside the observeEvent. This is what you would do with the server function:
server <- function(input, output) {
reactTXT <- reactiveValues(txt=NULL)
observeEvent(input$gender, {
if (input$gender == "gender1") {
txt <- "You are a male."
} else if (input$gender == "gender2") {
txt <- "You are a female."
} else {
txt <- NULL
}
reactTXT$txt <- txt
})
output$result <- renderPrint({
reactTXT$txt
})
}
First you create the reactiveValue reactTXT. In the observeEvent you assign the text to the reactiveValue with reactTXT$txt <- txt. And in the renderPrint function you just pass the reactiveValue reactTXT$txt to print it.

R shiny error with renderTable

I am building a shiny app for doing some network analyses. I want to calculate properties for the network using a function that is stored in global.R. However, I am not able to get the table output.
Here is the the part of my ui.R where I set the output for the table
# More ui.R above
mainPanel(
tabsetPanel(id = "conditionedPanels",
tabPanel("Network Properties",br(),value = 1,
actionButton('netproperty', label='Calculate Properties',class="btn btn-primary"),
h3(textOutput("Data Summary", container = span)),
tableOutput('prop_table')),
##... More ui.R code below
and here is my server.R:
shinyServer( function(input, output, session) {
## Get the properties
props <- reactive({
if (input$netproperty <= 0){
return(NULL)
}
result <- isolate({
input$netproperty
tryCatch ({
if(input$data_input_type=="example"){
if(input$datasets == "Network1"){
load("data/Network1.rda")
props <- graph_topology(g)
props
} else if (input$datasets == "Network2"){
load("data/Network1.rda")
props <- graph_topology(g)
props
} else if (input$datasets == "Network3"){
el <- read.delim("data/Network3.txt")
g <- graph.data.frame(el, directed = FALSE)
props <- graph_topology(g)
props
} else if (input$datasets == "Network4") {
el <- read.delim("data/Network4.txt")
g <- graph.data.frame(el, directed = FALSE)
props <- graph_topology(g)
props
}
} else if (input$data_input_type=="custom"){
if (is.null(input$dt_file))
return(NULL)
inFile <- input$dt_file
dataDT <- as.matrix(read.delim(inFile$datapah, sep="\t", header = FALSE, fill = TRUE))
g <- graph.data.frame(dataDT, directed = FALSE)
props <- graph_topology(g)
props
}
},
error = function(err) {
print(paste("Select Example or custom data set"))
})
})
result
})
## Output properties table
output$prop_table <- renderTable({
props()
})
}
When I press the button calculate properties, I get the error message always, telling me that I need to select example or custom data. I have tried with custom and example datasets, and the error remains. If I remove the tryCatch command in server.R I get the error of length equal zero. It seems that the function graph_topology in my global.R files is not working properly, but if I run it outside of the shiny app I get a matrix, that I thought it could be easily visualize with renderTable. I have also tried instead of using uiOutput in the ui.R using tableOutput but I have the same problem.

Dynamic Shiny Input

I am trying to render a Data table in R shiny on selected inputs but getting an error:-
output$reconOutput <- renderUI({
reconOutput <- sort(unique(as.vector(my_data$ReconIdName)), decreasing = FALSE)
reconOutput <- append(reconOutput, "All", after = 0)
selectizeInput("reconchoose", "Recon:", reconOutput)
})
output$statusOutput <- renderUI({
statusOutput <- sort(unique(as.vector(my_data$Status)), decreasing = FALSE)
statusOutput <- append(statusOutput, "All", 0)
selectizeInput("statuschoose", "Status:", statusOutput)
})
output$issuesbyReconName<- renderDataTable(
data <- reactive({
req(input$reconchoose)
req(input$statuschoose)
if(input$reconchoose == "All") {
filt1 <- quote(recon != "#?><")
} else {
filt1 <- quote(recon == input$reconchoose)
}
if (input$statuschoose == "All") {
filt2 <- quote(status != "#?><")
} else {
filt2 <- quote(status== input$statuschoose)
}
raw %>%
filter_(filt1) %>%
filter_(filt2)
})
)
Could you please guide me on this?
output$issuesbyReconName
1: shiny::runApp
Warning: Error in if: missing value where TRUE/FALSE needed
Is it related to any null value in columns that is creating a conflict in the code?
Can you share your input side code as well? It looks like it might be caused by there being no default value for some of the input objects, leading to the error.
Try either to set a default value for these objects or start the IF series with something like
if (is.na(input$reconchoose)) return("") else

Resources