Edited to add reproducible code
I am building a Shiny app and encountered a problem with a while loop inside an observe function. The program does not display the reactive values after while loop. Here is the relevant code snippets from ui.r and server.r
ui.r
library(shiny)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
textAreaInput("inText", label = "Enter text", rows = 3),
submitButton("Predict")
),
mainPanel(
textOutput("outText"),
textOutput("outCount"),
textOutput("outPred")
)
)
))
Server.r
library(shiny)
library(stringr)
predict <- function(term)
{
if(term == 3)
table <- list()
else
if(term == 0)
table <- c("input","text","empty")
else
table <- c("words","were","found")
return(table)
}
shinyServer(
function(input, output) {
state <- reactiveValues()
observe({
state$inText <- input$inText
state$wcount <- sapply(gregexpr("[[:alpha:]]+", state$inText), function(x) sum(x > 0))
if( state$wcount > 2)
term.c <- 3
else
if( state$wcount == 2)
term.c <- 2
else
if( state$wcount == 1)
term.c <- 1
else
term.c <- 0
cont <- TRUE
while(cont == TRUE) {
if(term.c == 3) {
state$predList <- predict(term.c)
if(length(state$predList) > 0) break
else term.c <- 2
}
if(term.c == 2) {
state$predList <- predict(term.c)
if(length(state$predList) > 0) break
else term.c <- 1
}
if(term.c == 1) {
state$predList <- predict(term.c)
if(length(state$predList) > 0) break
else term.c <- 0
}
if(term.c == 0) {
state$predList <- c("Did", "not", "find", "term")
break
}
}
})
output$outText <- renderPrint({ input$inText })
output$outCount <- renderPrint({ sapply(gregexpr("[[:alpha:]]+", input$inText), function(x) sum(x > 0)) })
output$outPred <- renderPrint({ state$predList })
}
)
Enter two words and the values are displayed properly. Enter three words and an empty list is returned to state$predList which will give it a 0 length. the program should then execute the second if statement and populate state$predList with a non-zero length list. this happens but the display is never refreshed and the program goes into an infinite loop. It jumps to the first line of the observe function and continues in an infinite loop. I see this when I add browser().
Am I not using the reactive values correctly? Thanks for any assistance.
Related
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 = "")
})
I am trying to build a shiny app that reads a data frame and at every press of an actionButton returns the value of a specific column, one row at a time until all rows of the data frame have been read. The structure of the dataset is 3 columns, one for IDs, one for a characteristic and an indicator variable for the already read IDs (0/1). Every time the user presses the actionButton, the app reads one row of the dataset, starting from row 1, returns the value of a second variable in that row and changes the value of the third variable to 1. The tricky part for me is that I want to save the "used" ids, in order to continue the reading from the last used id after restarting the app. I have tried loading and saving the data at every step and using reactiveValues, but this does not seem to work well for me - probably I don't know how to use them correctly. I am very new in shiny, so any feedback is more than welcome.
An example of the code I have been using:
project.path <- getwd()
dat <- data.frame(id = c(1:20), gender = sample(c("male", "female"), 20, replace = TRUE), used = 0)
write.csv2(dat, file.path(project.path, "data.csv"), row.names = F)
saveData <- function(x) {
write.csv2(x, file = file.path(project.path, "data.csv"),
row.names = FALSE)
}
loadData <- function() {
dat <- read.csv2(file.path(project.path, "data.csv"))
return(dat)
}
# UI
ui <- fluidPage(
# Application title
titlePanel("Tittle"),
sidebarLayout(
sidebarPanel(
actionButton("counter", "Start")
),
mainPanel(
textOutput("result")
)
)
)
# SERVER
server <- function(input, output, session) {
last <- reactive({
d <- loadData()
last <- min(d$id[d$used == 0]) -1
})
cur <- reactive({
if(last() == 0){
cur <- input$counter
}else{
cur <- last() + input$counter
}
})
# Calculate Result
ResultText <- reactive({
d <-loadData()
if (input$counter == 0 & last() == 0){
paste0("No IDs have been used. Press button to start.")
}else{
if(input$counter > 0 & last() == 0){
d$used[cur()] <- 1
paste0("ID ", cur(), " is a ", as.character(d$gender[cur()]))
}else{
if(input$counter == 0 & last() > 0){
paste0("The last ID was ", d$id[last()], " (", as.character(d$gender[last()]), ") Press the button to continue reading the list.")
}else{
d$used[cur()] <- 1
paste0("ID ", cur(), " is a ", as.character(d$gender[cur()]))
}
}
}
})
output$result <- renderText({
ResultText()
})
observe({
d <- loadData()
if (input$counter > 0 & last() == 0){
cur <- input$counter
d$used[cur] <- 1
saveData(d)
}else{
if(input$counter > 0 & last() > 0){
d$used[cur()] <- 1
saveData(d)
}
}
})
}
# Run
shinyApp(ui = ui, server = server)
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
I've been stuck on this problem for hours. I tried to create a simpler version of my actual use case to see if I can debug the problem but still having trouble.
My shiny app is below. It takes an input from user, runs it through some calculations until it meets a threshold, then collects the value in a list. It does this for several iterations (10 here in the example), then plots a histogram of these values.
The specific error I'm getting says
Warning: Error in : evaluation nested too deeply: infinite recursion / options(expressions=)?
I think that my error is related to the way I'm using x.new, but I can't figure out how to code it differently.
# install.packages('shiny')
library(shiny)
ui <- fluidPage(
headerPanel('Title Here'),
sidebarPanel(
numericInput('x.qty', 'Pick a number', 3, 1, 10)),
mainPanel(plotOutput('valueplot'))
)
server <- function(input, output, session) {
results <- reactive({
x.list <- list()
for (i in 1:10){
x.new <- reactive({input$x.qty * sample(1:10, 1)})
repeat{
if (x.new() > 20){
x.list <- c(x.list, x.new())
results <- x.list
break
} # end if loop
x.new <- reactive({x.new() * sample(1:10, 1)})
} # end repeat
} # end for loop
results
})
output$valueplot <- renderPlot({hist(as.numeric(results()))})
}
shinyApp(ui = ui, server = server)
I would suggest to modify your server function in the following way:
server <- function(input, output, session) {
results <- reactive({
x.list <- list()
for (i in 1:10){
x.new <- input$x.qty * sample(1:10, 1)
repeat{
if (x.new > 20){
x.list <- c(x.list, x.new)
results <- x.list
break
} # end if loop
x.new <- x.new * sample(1:10, 1)
} # end repeat
} # end for loop
results
})
output$valueplot <- renderPlot({hist(as.numeric(results()))})
}
This way you avoid the infinite recursion provoked by
x.new <- reactive({x.new() * sample(1:10, 1)})
Does this work as you want? Each for loop iteration, x.new is calculated using x.qty then in the repeat loop x.new recursively multiplies itself by a random number until it is greater than 20.
library(shiny)
ui <- fluidPage(headerPanel('Title Here'),
sidebarPanel(numericInput('x.qty', 'Pick a number', 3, 1, 10)),
mainPanel(plotOutput('valueplot')))
server <- function(input, output, session) {
x.new <- function(x) {
x * sample(1:10, 1)
}
results <- reactive({
x.list <- list()
for (i in 1:10) {
x.new_draw <- x.new(input$x.qty)
repeat {
if (x.new_draw > 20) {
x.list <- c(x.list, x.new_draw)
break
} # end if loop
x.new_draw <- x.new(x.new_draw)
} # end repeat
} # end for loop
x.list
})
output$valueplot <- renderPlot({
hist(as.numeric(results()))
})
}
shinyApp(ui = ui, server = server)
I'm trying to populate a data.frame/matrix based on some user-defined rules. I managed to create a function in R, but am stuck trying to replicate this as a Shiny app [it's my first time using Shiny, and I'm an idiot to start with this one]
This is the crux of the code in regular r-script -
user-inputs are: size (1~3), changes (1~2) and iterations (10~1000)
school_choice_function<- function(changes, size, iterations )
{
######## 1509
##### List of schools
p<-1
j<-1
k<-1
l<-1
s_list<- rep(0,80)
for (i in 1:80) {
if (i <= 26) {
schl<- paste(LETTERS[p],LETTERS[i],sep = "")
s_list[i]<- schl }
if (i>26 & i<=52) {p<- 2
schl<- paste(LETTERS[p],LETTERS[j],sep = "")
s_list[i]<- schl
j=j+1}
if (i>52 & i<=78) {p<- 3
schl<- paste(LETTERS[p],LETTERS[k],sep = "")
s_list[i]<- schl
k=k+1}
if (i>78 ) {p<- 4
schl<- paste(LETTERS[p],LETTERS[l],sep = "")
s_list[i]<- schl
l=l+1}
}
rm(p,i,j,k,l)
########## Applicant Data
a<- c(2011:2015)
c<- 1:size
d<- 1:changes
y<-0
v<-1
w<-10
mat <- matrix(ncol=5, nrow=(iterations*10))
for(pop in 1:iterations){
for (z in v:w)
{
b<- s_list[(1+y):(8+y)]
e<- rep(0,5)
e[1]<- b[1]
g<- sample(d,1)
h<- sample(2:5,g, replace = FALSE)
f1<- rep(0,length(h))
for(j in 1:g){
for(i in 1:length(h))
{
f<- sample(c, 1)
f1[i]<- paste(sample(b,f,replace = FALSE),collapse = ",")
e[h[i]]<- f1[i]
}
}
for(i in c(which(e %in% 0))){
e[i]<- e[i-1]
}
mat[z,]<- e
y<-y+8
}
v<- w+1
w<- w+10
y<-0
}
df<- data.frame(mat,stringsAsFactors = FALSE)
colnames(df)<- c("2011","2012","2013","2014","2015")
return(df)
}
Ignoring the use of worst-practices in coding (I've just learnt to think in terms of loops), I'm using this is a shiny app like this. "s_list/schools" is a character matrix with 80 elements, created before this code.
Just so you get an intuition of what on earth is this - basically it is applicant data over 5 years, who may or many not get assigned to alternatives over time, (based on the rules which comes through in the loops).
The code works in the current form - except the output table is full of NAs.... Any kind of help would be a step up from where I'm at!
ui<- fluidPage(
numericInput(inputId="Changes", label="Changes", value=1, min = 1, max = 3, step = 1),
numericInput(inputId="Size", label="Size", value=2, min = 1, max = 3, step = 1),
numericInput(inputId="Iterations", label="Iterations", value=10, min = 10, max = 1000, step = 10),
tableOutput("dframe")
)
server<- function(input,output) {
Changes<- reactive({input$Changes})
Size<- reactive({input$Size})
Iterations<- reactive({input$Iterations})
schools<- s_list
########## Applicant Data
a<- c(2011:2015)
cc<- reactive(1:(Size()))
d<- reactive(1:(Changes()))
y<-0
v<-1
w<-10
mat <- reactive(matrix(ncol=5, nrow=((input$Iterations)*10)))
pop<- 0
z<- 0
i<- 0
j<- 0
this<- reactive({
for(pop in 1:(Iterations())){
for (z in v:w)
{
b<- schools[(1+y):(8+y)]
e<- rep(0,5)
e[1]<- b[1]
g<- reactive(sample(d(),1))
h<- reactive(sample(2:5,g(), replace = FALSE))
f1<- reactive(rep(0,length(h())))
for(j in 1:g()){
for(i in 1:length(h()))
{
f<- reactive(sample(cc(), 1))
f1()[i]<- reactive(paste(sample(b,f(),replace = FALSE),collapse = ","))
e[h()[i]]<- f1()[i]
}
}
for(i in cc()(which(e %in% 0))){
e[i]<- e[i-1]
}
mat()[z,]<- e
y<-y+8
}
v<- w+1
w<- w+10
y<-0
}
})
df<- reactive(data.frame(mat(),stringsAsFactors = FALSE))
output$dframe <- renderTable({ df() })
}
shinyApp(ui= ui, server = server)
Instead of writing the whole code of the function school_choice_function inside your server why don't you define the function outside your server and just call it from inside your server. Something like this:
server<- function(input,output) {
Changes<- reactive({input$Changes})
Size<- reactive({input$Size})
Iterations<- reactive({input$Iterations})
df<- reactive({
df <- school_choice_function(Changes(), Size(), Iterations())
return(data.frame(df, stringsAsFactors = FALSE))
})
output$dframe <- renderTable({ df() })
}