When I run the below code without observeEvent working, it works fine. Those observeEvents are shown separately, below the last question and above the body of code below. They should be placed in the server section, under the 2 reactive inputs and above the output graph. When I uncomment them and run the app, user-corrected input errors can cause the app to crash despite the use of the validate function. (Validate that inputs into the "Y" column of the input matrix are in increasing sequential order, and that the max period in input column "Y" does not exceed the limit set in slider "X"). My questions are:
- How do I trigger observeEvent only when the Action Button is clicked? (That way all validations "should" have passed, the user has had time to fix any input errors without crashing the app). observeEvent is used to save inputs and outputs into objects for further use in other R functions, not shown here.
- A secondary question, more important is the above, I'll repost this 2nd question once I figure out the above: [If a user tries entering a number in column Y > than the value in slider X, is there a way to override and input into the matrix (input$yield_inputs) the lesser of those 2 numbers? And vice versa, if someone tries moving the slider X value to an amount < than the max in column Y of the input grid, is there a way to override and use the lower of those 2 values in $input$X? With observeEvent operating, these moves crash the app; I´d rather simply override user inputs and not deal with warnings and instructions for the user to fix the inputs.]
The observeEvents in question:
#observeEvent(yield_data(), {yield.inputs <<- unique(yield_data())})
#observeEvent({vector(periods(),yield_data()[,1],yield_data()[,2])},{yield.outputs <<- unique({vector(periods(),yield_data()[,1],yield_data()[,2])})})
And the code:
library(shiny)
library(shinyMatrix)
m <- function(x) {matrix(c(1,1), 1, 2, dimnames = list(NULL, c("Y", "Z")))}
matrix.input <- function(x) {
matrixInput(
x,
value = {m()},
rows = list(extend = TRUE, names = TRUE, editableNames = TRUE),
cols = list(extend = FALSE, names = TRUE, editableNames = FALSE),
class = "numeric")
}
input.validate <- function(x,y) {
suppressWarnings(
validate(
need(x() >= max(y()[,1]), 'Modeled periods (X) must be >= max vector period (Y).'),
need(min(diff(y()[,1])) > 0, 'Vector input periods (column Y) must be in increasing order.')
)
)
}
vector <- function(X,Y,Z){ # X = nbr periods to model (complete time horizon);Y = period for variable Z to change; Z = variable effective in period Y
a <- rep(NA, X)
a[Y] <- Z
a[seq_len(min(Y)-1)] <- a[min(Y)]
if(max(Y) < X){a[seq(max(Y)+1, X, 1)] <- 0}
a <- approx(seq_along(a)[!is.na(a)],a[!is.na(a)], seq_along(a))$y
b <- seq(1:X)
c <- data.frame(X = b, Z = a)
return(c)
}
ui <- fluidPage(
titlePanel("Vector Generator"),
sidebarPanel(
# Input: specify in a slider the number of periods to model ----
sliderInput("X", "Modeled periods (X):", min = 1, max = 120, value = 60),
# Input: matrix grid ----
width = 6, tags$h5(strong("Yield vector inputs:")),
matrix.input("yield_inputs"),
),
mainPanel(
h5(strong("Plot of yield inputs:")),
width = 6,plotOutput("graph")
)
)
server <- function(input, output, session) {
periods <- reactive({input$X}) # Periods to model (X) data capture
yield_data <- reactive({input$yield_inputs}) # Matrix input grid capture (columns Y and Z)
output$graph <- renderPlot({
input.validate(periods,yield_data)
plot({vector(periods(),yield_data()[,1],yield_data()[,2])},
type="b",
main = 'X (vector periods) and Z (interpolated variables)')
})
}
shinyApp(ui, server)
See code below, now including that troublesome observeEvent that causes app crash when user inputs a value in column Y > slider input X:
library(shiny)
library(shinyMatrix)
m <- function(x) {matrix(c(1,1), 1, 2, dimnames = list(NULL, c("Y", "Z")))}
matrix.input <- function(x) {
matrixInput(
x,
value = {m()},
rows = list(extend = TRUE, names = TRUE, editableNames = TRUE),
cols = list(extend = FALSE, names = TRUE, editableNames = FALSE),
class = "numeric")
}
input.validate <- function(x,y) {
suppressWarnings(
validate(
need(x() >= max(y()[,1]), 'Modeled periods (X) must be >= max vector period (Y).'),
need(min(diff(y()[,1])) > 0, 'Vector input periods (column Y) must be in increasing order.')
)
)
}
vector <- function(X,Y,Z){ # X = nbr periods to model (complete time horizon);Y = period for variable Z to change; Z = variable effective in period Y
a <- rep(NA, X)
a[Y] <- Z
a[seq_len(min(Y)-1)] <- a[min(Y)]
if(max(Y) < X){a[seq(max(Y)+1, X, 1)] <- 0}
a <- approx(seq_along(a)[!is.na(a)],a[!is.na(a)], seq_along(a))$y
b <- seq(1:X)
c <- data.frame(X = b, Z = a)
return(c)
}
ui <- fluidPage(
titlePanel("Vector Generator"),
sidebarPanel(
# Input: specify in a slider the number of periods to model ----
sliderInput("X", "Modeled periods (X):", min = 1, max = 120, value = 60),
# Input: matrix grid ----
width = 6, tags$h5(strong("Yield vector inputs:")),
matrix.input("yield_inputs"),
),
actionButton(inputId = "go",label = "Save inputs and vector"),
mainPanel(
h5(strong("Plot of yield inputs:")),
width = 6,plotOutput("graph")
)
)
server <- function(input, output, session) {
periods <- reactive({input$X}) # Periods to model (X) data capture
yield_data <- reactive({input$yield_inputs}) # Matrix input grid capture (columns Y and Z)
observeEvent({vector(periods(),yield_data()[,1],yield_data()[,2])},
{yield.outputs <<- unique({vector(periods(),yield_data()[,1],yield_data()[,2])})})
output$graph <- renderPlot({
input.validate(periods,yield_data)
plot({vector(periods(),yield_data()[,1],yield_data()[,2])},
type="b",
main = 'X (vector periods) and Z (interpolated variables)')
})
}
shinyApp(ui, server)
observeEvent(input$go, {...})will only execute when theactionButton("go",...)is clicked.envmust be an environment" or "Error in normalizePath(path.expand(path), winslash, mustWork) : path[1]="Test1.R": The system cannot find the file specified". I tried adding input$go only to this: observeEvent(input$go,yield_data(),{yield.inputs <<- unique(yield_data())})input$go. I think your title and/or question are confusing. Further, those errors suggest a lot more is going on. (Not sure if it's related, but ... I've rarely found the use of<<-to be good/right, usually it's a sign that the design/architecture needs to be improved. Its use can make several things a bit more difficult.)