How do I produce partial graphics in R-Shiny output? - r

I hope I can explain this succinctly. I have an R function that runs an ecological simulation and returns a list of output (time steps, population size, mortality history, number of offspring, stuff like that). I want to slow down the graphics output under certain circumstances so that students can see population dynamics as they happen. The plot axes and title should be displayed, then in 0.5 s the first line representing cumulative offspring should appear, then 0.5 s later the second line of cumulative offspring appears, then the third 0.5 s later, until the entire cohort of new offspring has been plotted at the end of the "simulation."
The problem is that the app waits until the whole image has been rendered before displaying it, so I can't show students "slowed down" population dynamics. The output plot is blank until all of those 0.5 s delays have finished, then it renders all at once. Even the graphics calls that precede the for() loop are suppressed until after the loop finishes. The code examples below are incomplete, work in progress versions.
Here is my server code-- if you uncomment the dev.new() call in the renderPlot command the app works exactly as desired, except that output is in a new graphics device, rather than in the Shiny app plot window:
shinyServer(function(input, output) {
observe({
if(input$runSim == 0) return()
isolate({
sim <- reactive({
switch(input$sim,
dorriefish = {
df.sim(input$S.df, input$p.df, show=FALSE)
} # end case dorriefish
) # end switch(input$sim)
}) # end reactive()
output$modl.plot <- renderPlot({
switch(input$sim,
dorriefish = {
if (input$reps.df == 1)
{
# dev.new()
opar <- par(no.readonly=TRUE)
len <- length(sim()$offspring.t)
par(fig=c(0,1,0.1,0.9), xpd=NA)
plot(sim()$offspring.t, type="n", xlab="Time steps", ylab="Cumulative Doriefish offspring",
xlim=c(1, max(len, length(sim()$mass))))
mtext("Dorriefish living per time step (green = alive, red = dead):", side=3, at=(max(len)/2)+0.5,
line=4.2)
for(i in 1:nrow(sim()$mhistory))
{
z <- rep("green", length(sim()$mass))
z[sim()$mhistory[i,]] <- "red"
points(seq(1,len, length=length(sim()$mass)), rep(max(1.18*sim()$offspring.t), length(sim()$mass)),
pch=21, col="black", bg=z, cex=2.5)
lines(sim()$offspring.t[1:i], type="h")
Sys.sleep(0.5)
}
txt <- paste("Total offspring:", sim()$offspring,
" Time to cohort extinction:", length(sim()$offspring.t), "time steps.")
mtext(txt, side=1, at=0, line=5, adj=0)
par(opar)
} # end if(input$reps.df == 1)
} # end case dorriefish
) # end switch(input$sim)
}) # end renderPlot()
}) # end isolate()
}) # end observe()
}) # end shinyServer()
Here is the UI code:
library(shiny)
shinyUI(
fluidPage(
titlePanel("BIOL 330 ecological simulations"),
sidebarLayout(
sidebarPanel("",
helpText(HTML("<h3 style='text-align:center;'>Control Panel</h3>"), align='center'),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
# choose a simulation from a drop down menu
selectInput("sim", HTML("<b>Select a simulation to explore:</b>"),
# list the simulations available
c("No simulation selected (Introduction)" = "none",
"Dorriefish growth/reproduction trade-offs" = "dorriefish",
"Optimal foraging" = "optfor")
),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
conditionalPanel(condition="input.sim=='dorriefish'",
helpText(HTML("<b>Simulation model parameters:</b>")),
sliderInput("S.df", label=div(HTML("Specify <em>S</em>, the switch point mass (g) for
transition from somatic growth to reproduction:")),
min = 1, max = 50, value = 10, step=5),
sliderInput("p.df", label=div(HTML("Specify <em>p</em>, the probability of mortality
by predation in any given time step:")),
min = 0, max = 1, value = 0.12, step=0.01),
sliderInput("reps.df", label=div(HTML("Specify the number of full simulations to
run:")), min = 1, max = 100, value = 1, step=1)
),
# bottom controls common to all panels
conditionalPanel(condition="input.sim!='none'",
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
fluidRow(column(4, actionButton("runSim", "Run simulation")),
column(4, actionButton("saveSim", "Save output file")),
column(4, actionButton("printSim", "Save/print plot"))),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray')
)
),
mainPanel("",
# no model selected-- show information page
conditionalPanel(condition="input.sim=='none'",
includeHTML("www/simNoneText.html")
),
tabsetPanel(id="outTabs", type="tabs",
tabPanel("Plot", plotOutput("modl.plot")
),
tabPanel("Summary"
),
tabPanel("R Code"
)
)
)
)
)
)
So to repeat my question, how can I get the server to display the cumulative number of offspring in each time step, pause 0.5 s, than show the next until all the simulation time steps have been displayed?
Thanks, and best regards,
--Mike C.

I've tried to read your code and this is what I saw:
I suggest you to use the uiOutput() function to display output, so that the ui.R gets clearer, while putting computation in server.R
To simulate the steps while the population is growing (or anything else) you could calculate all at once in server.R, and then displaying inside a for() loop only some data, like this inside the server.R
output$plot <- renderUI({
### here calculate the results all at once and save it to a variable
result <- calculations
for(i in 1:dim(result)[1]){
Sys.sleep(0.5) # time to wait to perform each plot
### here you put the code to only get some results of
### the calculation you've perfomed earlier
ggplot(results[i,...], ...)
}
})

Related

shiny plot doesn't show up

I'm trying to make my first shiny app, in which a number of values are taken in, a number of calculations are performed (which depend on both values in the input and those in the server function), and then the outputs plotted. However, I can either no plot at all in the output (as in the sample below), or can just get the 1:1 line and not my data to show up. I'm not entirely sure where to begin troubleshooting, but I think I have problems with both making the calculations and feeding them into the plot function here. If you have any pointers it would be greatly appreciated.
Here is a simplified version of my app:
library(shiny)
require(ggplot2)
ui<-fluidPage(
sidebarLayout(
sidebarPanel(
titlePanel("mytitle"),
sliderInput(inputId= "min", label="minratio", value=0, min=0, max=0.499),
sliderInput(inputId= "max", label="maxratio", value=1, min=0.5, max=1)
),
mainPanel(
textOutput("valoutput"),
plotOutput("distPlot",width="100%"))
)
)
server<-function(input, output){
BS = function(x) {
mini=x[1]; maxi=x[2]
ratio <-seq(from=mini,to=maxi, by=0.01)
total<-30*ratio+3
res = c(ratio,total)
}
data<-reactive({as.data.frame("mini"=as.numeric(input$min), "maxi"=as.numeric(input$max))})
output$valoutput <- renderText({BS(data())[1]})
output$distplot <- renderPlot({
d1=BS(data())[1]
d2=BS(data())[2]
ggplot()+geom_abline(intercept = 0, slope=1, colour="grey50")+geom_point(aes(x=d1, y=d2))
}, height = 350, width = 600)
}
shinyApp(ui=ui, server=server)
Thanks so much!
Your BS function is not correct. Change it with this one (with as.numeric). Otherwise x[1]/x[2] will be data.frames and will throw an error in seq(). Alternatively you could also use double brackets, like x[[1]].
BS = function(x) {
mini=x[1]; maxi=x[2]
ratio <-seq(from=as.numeric(mini),to=as.numeric(maxi), by=0.01)
total<-30*ratio+3
res = c(ratio,total)
}
and in your ui your plot output name is not correct. It should be distplot not distPlot.
And you dont need to call as.data.frame, just data.frame does the right job, as you want to create a data.frame and not convert an object.
data <- reactive({
data.frame("mini"=as.numeric(input$min),
"maxi"=as.numeric(input$max))
})

R shiny renderplot returns a blank plot with only x and y corrdinates

I am writing shiny program that is supposed to display a plot with x axis being the sample size and y being the corresponding power. Since the power needs to be calculated for each value of sample size ranging from n/2 to 2n, I used a for loop inside the reactive part.
here is the code:
I cannot figure out why the output gives me a blank plot which has only the coordinates without any points on it. I guess there is something wrong with the two vectors (samplesize1 and powervector1) that I want to be shown on the plot, but I didn't understand why they are not showing up in the picture.
Could someone help me figure this out?
library('shiny')
ui<-fluidPage(
titlePanel("Sample Size Calculation"),
numericInput("num1",
h3("Power to be reached"),
value = 0.85, min=0, max=1,step=0.01),
numericInput("num2",
h3("Scale parameter"),value=25,step=0.1),
numericInput("num3",
h3("delta"),
value = 2,step=0.01),
numericInput("num4",
h3("allocation ratio"),
value = 1,min=0, step=0.01),
numericInput("num5",
h3("Beta"),
value = 0.1062, min=0, step=0.01),
numericInput("num6",
h3("event probability"),
value = 1,min=0, max=1,step=0.01),
numericInput("num7",
h3("Significant level"),
value = 0.05, min=0, max=1,step=0.01),
plotOutput("picture"),
textOutput("k_gamma"),
submitButton("Submit")
)
server<-function(input,output){
n=2
power1=rep(NA,2*n)
ndf=rep(NA,2*n)
ddf=rep(NA,2*n)
f_crit1=rep(NA,2*n)
f_crit2=rep(NA,2*n)
criticalvalue1=rep(NA,2*n)
criticalvalue2=rep(NA,2*n)
x=rep(NA,2*n)
my_func<-reactive({
k_gamma<-input$num2
delta_pt<-input$num3
r<-input$num4
beta<-input$num5
eventprob<-input$num4
alpha<-input$num7
for (i in 1:(2*n)) {
ndf[i]=2*ceiling(eventprob*i)*k_gamma
ddf[i]=2*ceiling(eventprob*i)*r*k_gamma
f_crit1[i]= qf(1-alpha,ndf[i],ddf[i])
f_crit2[i] = qf(alpha,ndf[i],ddf[i])
criticalvalue1[i]=(f_crit1[i]*r)/((delta_pt**(beta)))
criticalvalue2[i]=(f_crit2[i]*r)/((delta_pt**(beta)))
power1[i]=1-pf(criticalvalue1[i],ndf[i],ddf[i])+pf(criticalvalue2[i],ndf[i],ddf[i])
samplesize1=c(ceiling(n/2):(2*n))
powervector1=power1[ceiling(n/2):(2*n)]
}
})
output$picture<-renderPlot({plot(my_func()$samplesize1, my_func()$powervector1 ,xlim=c(0,200),ylim=c(0,1))})
}
shinyApp(ui, server)

Plot the Plotly Graph Dynamically in the Shiny App in R

I want to draw a Plotly graph in the Shiny App in R. I want the the functionality in such a way that I want to plot a certain number of points (say 20) in a loop.
This is my code for the Server.R :-
xAxis = vector("numeric", as.numeric(input$Generations))
yAxis = vector("numeric", as.numeric(input$Generations))
graphDF = data.frame(cbind(xAxis, yAxis))
for(i in 1 : 5)
{ output$GA = renderPlotly({
print(graphDF) # Testing
graphDF$yAxis[i] = i
graphDF$xAxis[i] = i
print(graphDF) # Testing
# Plotly functionality
p <- plot_ly(graphDF, x = graphDF$xAxis, y = graphDF$yAxis)
})
}
Any help would be most appreciated.
Kind Regards
This was more complicated than it looked. It looks like you want to iterate and create a series of plotly graphs, changing the data values as you go along.
Because the Generations slider re-initializes the vector to a new length,
and each iteration changes the state of the data being plotted, you can't just cascade reactive functions. Storing the state in a reactiveValues is a good way to handle this.
The major changes were as follows:
Added a reactiveValues to store xAxis and yAxis
Added an observeEvent to reinitialize those values when its value change
Added an "Iteration range" slider to drive the iteration (easier than a reactive timer). Note that it has an animate parameter that (probably) creates a reactive timer on its own.
Modified the plotly call to make it more conventional and avoid warnings.
The code:
library(shiny)
library(plotly)
u <- fluidPage(
titlePanel("Iterations of a plotly graph"),
sidebarLayout(
sidebarPanel(
sliderInput("Generations","Number of Generations:",
min = 1, max = 50, value = 20),
sliderInput("iter", "Iteration range:",
value = 1, min = 1, max = 1000, step = 1,
animate=animationOptions(interval=800, loop=T)),
p("To start click on the blue arrowhead")
),
mainPanel(
plotlyOutput("GA")
)
))
s <- shinyServer(function(input,output){
rv <- reactiveValues(xAxis=NULL,yAxis=NULL)
observeEvent(input$Generations,{
rv$xAxis=vector("numeric", as.numeric(input$Generations))
rv$yAxis=vector("numeric", as.numeric(input$Generations))
})
output$GA = renderPlotly({
rv$yAxis[input$iter] <- input$iter
rv$xAxis[input$iter] <- input$iter
gdf <- data.frame(xAxis=rv$xAxis, yAxis=rv$yAxis)
plot_ly(gdf, x = ~xAxis, y = ~yAxis, type="scatter",mode="markers")
})
})
shinyApp(u,s)
Because it is dynamic, you have to run it to see how it really works, but here is a screen shot after several iterations:

having problems implementing a "Run" button with Shiny

I know this question has been addressed multiple times and I've researched those instances that I've found, but have not found a solution that works.
I'm using an actionButton() as a Run button-- the intent is to not re-run the simulation unless the actionButton is clicked. I've used observe({ }) and isolate({ }) as I've seen discussed here, but still have several problems. I'll discuss the problems, then include the code below. The app is in early stages presently, and ONLY the second simulation on the drop down menu is partly implemented, so after starting the app select "Dorriefish growth/reproduction tradeoffs" from the selectInput() menu. Don't be concerned by any other rough spots at this time.
When the app begins, the run button behaves as expected in the sense that moving the top two sliders (S and p) does not cause the simulation to run or display output in a separate graphics device (reps.df == 1 is a special case requiring a dev.new()). At this point, input$runSim (the run button) == 0 because it has not been clicked yet.
First problem: when the run button is clicked, the graphics device opens and the simulation runs as expected, then ANOTHER graphics device opens and the same simulation displays again. Be patient while the first simulation display finishes-- a second will open on top of it. When those are closed (by clicking on their window controls), the next time the run button is pressed the same simulation is displayed a third time, then another graphics device opens and displays a new simulation run. If those graphics devices are closed, subsequent clicks on the run button behave as expected, opening one graphics device and displaying one, unique simulation run each time. Why do the first two clicks on the run button produce TWO graphics devices and repeat the first simulation run three times? (Pounds head on desk.)
Second problem: after the first time the run button is pushed, input$runSim increments and thereafter any movement of the S and p sliders causes a new graphics device to open and display a new simulation run. I don't want this behavior-- I need the simulation to display ONLY when the run button is clicked, not automatically when other input parameters are changed. I want the nominal behavior of the submitButton(), but I've read online that an actionButton with observe and isolate is the better practice. For the life of me I just cannot get it to isolate the run button function from the other sliders changing when input$runSim is greater than zero, i.e. after the first time it is clicked. There does not appear to be any obvious way to reset the value of that actionButton variable back to zero after a simulation run has been displayed, so after that first click the button no longer prevents new simulations whenever any other input variable is updated. (Pounds head some more.)
In summary: 1) why do the first two clicks on the run button each cause two graphics device windows to open, and why do they display the first simulation run three times? 2) How can I make the simulation run and display ONLY when the run button is clicked after the first time it is clicked?
Here is my (very preliminary) code:
ui.r
# filename: ui.r
# Michael Camann, Humboldt State University, 2014
################################################################################
#
# Define the user interface
#
################################################################################
library(shiny)
shinyUI(
fluidPage(
titlePanel("BIOL 330 ecological simulations"),
sidebarLayout(
sidebarPanel("",
helpText(HTML("<h3 style='text-align:center;'>Control Panel</h3>"), align='center'),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
# choose a simulation from a drop down menu
selectInput("sim", HTML("<b>Select a simulation to explore:</b>"),
# list the simulations available
c("No simulation selected (Introduction)" = "none",
"Dorriefish growth/reproduction trade-offs" = "dorriefish",
"Optimal foraging" = "optfor")
),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
conditionalPanel(condition="input.sim=='dorriefish'",
helpText(HTML("<b>Simulation model parameters:</b>")),
sliderInput("S.df", label=div(HTML("Specify <em>S</em>, the switch point mass (g) for
transition from somatic growth to reproduction:")),
min = 1, max = 50, value = 10, step=5),
sliderInput("p.df", label=div(HTML("Specify <em>p</em>, the probability of mortality
by predation in any given time step:")),
min = 0, max = 1, value = 0.12, step=0.01),
sliderInput("reps.df", label=div(HTML("Specify the number of full simulations to
run:")), min = 1, max = 100, value = 1, step=1)
),
# bottom controls common to all panels
conditionalPanel(condition="input.sim!='none'",
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray'),
fluidRow(column(4, actionButton("runSim", "Run simulation")),
column(4, actionButton("saveSim", "Save output file")),
column(4, actionButton("printSim", "Save/print plot"))),
tags$hr(style='height:2px; border-width:0; color:gray; background-color:gray')
)
),
mainPanel("",
# no model selected-- show information page
conditionalPanel(condition="input.sim=='none'",
includeHTML("www/simNoneText.html")
),
tabsetPanel(id="outTabs", type="tabs",
tabPanel("Plot", plotOutput("modl.plot")
),
tabPanel("Summary"
),
tabPanel("R Code"
)
)
)
)
)
)
server.r
# filename: server.r
# Michael Camann, Humboldt State University, 2014
library(shiny)
################################################################################
#
# Dorrie fish reproduction/growth trade-offs
#
################################################################################
# This function implements the Doriefish simulation exercise distributed in Java
# with Cain et al Ecology, 2nd ed.
# Arguments:
#
# S The switch point in grams for transitioning from growth to reproduction.
# Default = 10 g.
#
# p Probability of predation. Default = 0.12.
#
# show Logical. If TRUE (default), print and plot single simulation output. Set
# to FALSE when running multiple simulations in order to average the number
# of offspring across multiple simulations, in which case viewing the
# results of individual simulations isn't necessary.
df.sim <- function(S=10, p=0.12, show=TRUE)
{
if (S < 10 | S > 50) stop("S must be between 10 and 50 grams.")
doriefish <- 10 # cohort size
imass <- 5 # initial mass
mass <- rep(imass, doriefish) # init vector of dorrie fish mass
dead <- rep(FALSE, doriefish) # init vector of mortality status
mhistory <- matrix(dead, nrow=1, byrow=TRUE) # init a matrix of mortality history
offspring.t <- 0 # init offspring count
total.offspring <- vector() # storage vector
while(any(dead==FALSE)) # continue until all are dead
{
repro.t <- mass >= S & !dead # who reproduces during this time step?
offspring.t <- offspring.t + sum(mass[repro.t==TRUE]/5) # one offspring per 5 g body mass
total.offspring <- c(total.offspring, offspring.t) # keep track of offspring each time step
mass[!dead & !repro.t] <- mass[!dead & !repro.t] + 5 # incr mass by 5 g if not reproducing
die.t <- sapply(1:length(dead), function(x) runif(1) <= p) # stochastic selection of some for predation
dead <- dead | die.t # update the mortality vector
mhistory <- rbind(mhistory, dead) # update the mortality history matrix
}
rownames(mhistory) <- c(1:nrow(mhistory))
rval <- list(S=S, p=p, mass=mass, mhistory=mhistory, offspring.t=total.offspring,
offspring=total.offspring[length(total.offspring)], show=show)
class(rval) <- "df.sim"
return(rval)
}
print.df.sim <- function(sim) # print function for df.sim()
{
if(sim$show)
{
cat("\n\tDoriefish simulation\n\n")
cat("Switch point from growth to reproduction:", sim$S, "g.\n\n")
cat("Probability of predation:", sim$p, "per time step.\n\n")
cat("Time to cohort extinction:", length(sim$offspring.t), "time steps.\n\n")
cat("Total adult Doriefish biomass:", sum(sim$mass), "g.\n\n")
cat("Total offspring produced:", sim$offspring, "\n\n")
plot(sim)
}
}
plot.df.sim <- function(sim, sstep=FALSE, s=0.75, ...) # plot function for df.sim()
{
opar <- par(no.readonly=TRUE) # save graphics parameters
txt <- paste("Total offspring:", sim$offspring,
" Time to cohort extinction:", length(sim$offspring.t), "time steps.")
step.through <- function(sim, s=0.5, txt=txt)
{
len <- length(sim$offspring.t)
par(fig=c(0,1,0.1,0.9), xpd=NA)
plot(sim$offspring.t, type="n", xlab="Time steps", ylab="Cumulative Doriefish offspring",
xlim=c(1, max(len, length(sim$mass))))
mtext("Dorriefish living per time step (green = alive, red = dead):", side=3, at=(max(len)/2)+0.5,
line=4.2)
for(i in 1:nrow(sim$mhistory))
{
z <- rep("green", length(sim$mass))
z[sim$mhistory[i,]] <- "red"
points(seq(1,len, length=length(sim$mass)), rep(max(1.18*sim$offspring.t), length(sim$mass)),
pch=21, col="black", bg=z, cex=2.5)
lines(sim$offspring.t[1:i], type="h")
Sys.sleep(s)
}
mtext(txt, side=1, at=0, line=5, adj=0)
}
if(sstep) step.through(sim, s, txt)
else
{
par(fig=c(0,1,0.1,1), xpd=NA)
plot(sim$offspring.t, type="h", xlab="Time steps",
ylab="Cumulative Doriefish offspring", ...)
mtext(txt, side=1, at=0, line=5, adj=0)
}
par(opar)
}
################################################################################
#
# Define the shiny server
#
################################################################################
shinyServer(function(input, output) {
observe({
if(input$runSim == 0) return()
isolate({
sim <- reactive({
switch(input$sim,
dorriefish = {
df.sim(input$S.df, input$p.df, show=FALSE)
} # end case dorriefish
) # end switch(input$sim)
}) # end reactive()
output$modl.plot <- renderPlot({
switch(input$sim,
dorriefish = {
if (input$reps.df == 1)
{
dev.new()
plot(sim(), sstep=TRUE)
}
}, # end case dorriefish
) # end switch(input$sim)
}) # end renderPlot()
}) # end isolate()
}) # end observe()
}) # end shinyServer()
Thanks in advance for any advice you can offer. I'm rather new to Shiny and obviously need more time with it.
I had a look at your code and tried it myself.
I think the main problem is within your ShinyServer method. A "renderPlot" within a "reactive" within an "Isolate" within an "observe" seems like a bad idea. Surely "renderPlot" and "observe" shouldn't be encapsulated within other reactive expressions, they are reactive endpoints. Here you have a really clear overview of how to use the reactive expressions which helped me a lot: http://rstudio.github.io/shiny/tutorial/#reactivity-overview
I tried to rewrite your ShinyServer code to follow that philosophy:
shinyServer(function(input, output) {
sim <- reactive({
switch(input$sim,
dorriefish = {
df.sim(input$S.df, input$p.df, show=FALSE)
} # end case dorriefish
) # end switch(input$sim)
}) # end reactive()
output$modl.plot <- renderPlot({
if(input$runSim == 0) return()
isolate({
switch(input$sim,
dorriefish = {
if (input$reps.df == 1)
{
plot(sim(), sstep=TRUE)
}
}, # end case dorriefish
) # end switch(input$sim)
}) # end isolate
}) # end renderPlot()
}) # end shinyServer()
This seems to work fine.
Notice I also removed the
dev.new()
I don't think there's a need to open a plotting device within shiny, that's what the renderPlot function takes care of.
And as a final tip I suggest you have a look at a visual debugger for shiny (and R in general) so you can trace every bit of code: there's one within RStudio or you could install the StatET plugin for eclipse. It helps a bunch to see what gets called when, to see the reactive expressions at work.
I would recommend using actionButton with observeEvent. The minimal example would be as follow:
In your server.R file you would need the following:
shinyServer(
function(input, output) {
observeEvent(input$run, {
# simulation code
})
})
The observeEvent is then triggered by actionButton in ui.R:
actionButton("run", label = "Run Simulation")
The button is decorated with the id run. After it's hit the input$run on the server side is registered with observeEvent. Once it's triggered the function in the observeEvent is performed (# simulation code in the example).
The above is, I hope, a solution to your problem 2). It doesn't explain the problem 1) but it should solve it.

Automating Interaction with RShiny App

I am trying to automate the interaction of a Shiny app so it displays a series of results while incrementing through a predetermined range of inputs, without having to repetitiously count and change input values. This automation will provide a systematic view of a set of inputs, such as displays of refreshed price charts for selected stocks, or plots of current performance indicators for real-time processes that are being monitored.
This is similar to question [Update graph/plot with fixed interval of time] (Update graph/plot with fixed interval of time) which runs a loop with a timer. Extending that approach, my objective is to:
a) Automatically set the invalidateLater pause high (1 hour) to effectively stop the cycle after a fixed (5) set of displays, pending new user input to restart it.
b) [When I can do that, I will add a counter-based control to cycle through a set of input$obs before it stops. For simplicity, that step, which has the same error and presumably same solution, is omitted here.]
Using the above referenced toy example, the following script does repeatedly cycle through its 5 displays, but it yields this error rather than changing the pause interval.
Listening on port 8100
Error in hist.default(dist, main = paste("Last Histogram count =", as.numeric(updater()), :
'x' must be numeric
as.numeric(autoControl())
Error: could not find function "autoControl"
I can not find the reactive conductor, reactiveValues or other methods that this task requires. Thank you for your help.
library(shiny)
updates <- 0
updater <- function(){ updates + 1 }
runApp(list(
ui = pageWithSidebar(
headerPanel("Hello Shiny!"),
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 50)
,
selectInput(inputId = "secPause",
label = "Seconds between displays:",
choices = c(1, 2, 3, 60*60),
selected = 2)
),
mainPanel(
plotOutput("distPlot")
)
),
server =function(input, output, session) {
updateTracker <- reactive( {
invalidateLater(as.numeric(input$secPause) * 1000, session)
updates <<- as.numeric(updater())
})
autoControl <- reactive( {
if(updateTracker() <= 5)
secPause <<- input$secPause
else
secPause <<- 60*60
return(secPause)
})
output$distPlot <- renderPlot( {
if(updateTracker() <= 5) {
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist, main = paste("Histogram count =" , updateTracker()))
}
else {
updates <<- 0
hist(dist, main = paste("Last Histogram count =",
as.numeric(updater()), "with secPause =",
as.numeric(autoControl())))
}
})
}
))
You are getting the error because the hist distribution is defined inside the if clause, but you are using it (after 5 intervals) inside the else clause, where it is not defined. That's why it works for the first 5 intervals.
if(updateTracker() <= 5) {
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist, main = paste("Histogram count =" , updateTracker()))
}
else {
updates <<- 0
hist(dist, main = paste("Last Histogram count =",
as.numeric(updater()), "with secPause =",
as.numeric(autoControl())))
}
After I moved the dist to before the if condition, I got your cycling to work. (I also split your code into UI.R and server.R to make it more manageable.) Not pasting here since it is essentially the same code, but you can find the working version of code in this gist.

Resources