Nothing
shinyServer(function(input, output, session) {
# --- initialisazion -----------------------------------------------------------
# if (exists("ser", envir = globalenv())) rm("ser", envir = globalenv())
senv <- environment() # the session environment
# probably due to bad programming
rUplMsg <- reactiveValues(upd = 0)
rFOpts <- list()
gFiveBestMdl <- structure(list(arima = c("(0 1 0)(0 1 1)", "(1 1 1)(0 1 1)", "(0 1 1)(0 1 1)", "(1 1 0)(0 1 1)", "(0 1 2)(0 1 1)"), bic = c(-4.007, -3.986, -3.979, -3.977, -3.97)), .Names = c("arima", "bic"), row.names = c(NA, -5L), class = "data.frame")
rModel <- reactiveValues(seas = init.model, senv = senv)
rError <- reactiveValues(msg = "")
rStory <- reactiveValues(story = init.story, view.no = 1)
rStoryFeedback <- reactiveValues(click = NULL, timestamp = Sys.time())
# a function with reactive consequences. Must be inside shinyServer()
upd_or_fail <- function(z){
if (inherits(z, "try-error")){
rError$msg <- z
} else {
rModel$seas <- z
rError$msg <- ""
}
}
# --- URL ----------------------------------------------------------------------
if (on.website){
qstr <- shiny::isolate(session$clientData$url_search)
ql <- shiny::parseQueryString(qstr)
if (!is.null(ql$call)){
txt <- ql$call
call <- try(as.call(parse(text = txt)[[1]]), silent = TRUE)
if (inherits(call, "try-error")){
z <- call
} else {
z <- seasonalview:::upd_seas(init.model, call = call, senv = senv)
}
upd_or_fail(z)
}
}
# --- call updater -------------------------------------------------------------
# triggered by view
shiny::observe({
series <- input$iSeries
m <- shiny::isolate(rModel$seas)
z <- seasonalview:::upd_seas(m, series = series, senv = senv)
upd_or_fail(z)
})
# triggered by r or x13 terminal
shiny::observe({
if (input$iEvalCall > 0){
at <- shiny::isolate(input$iActiveTerminal)
m <- shiny::isolate(rModel$seas)
if (at == "R"){
txt <- shiny::isolate(input$iTerminal)
call <- try(as.call(parse(text = txt)[[1]]), silent = TRUE)
if (inherits(call, "try-error")){
z <- call
} else {
z <- seasonalview:::upd_seas(m, call = call, senv = senv)
}
} else if (at == "X-13"){
txt <- shiny::isolate(input$iTerminalX13)
call <- seasonal::import.spc(text = txt)$seas
if (inherits(call, "try-error")){
z <- call
} else {
call$x <- m$call$x
call$xreg <- m$call$xreg
call$xtrans <- m$call$xtrans
z <- seasonalview:::upd_seas(m, call = call, senv = senv)
}
} else {
stop("wrong at value")
}
upd_or_fail(z)
}
})
# triggered by selectors
shiny::observe({
FOpts <- list()
FOpts$method <- input$iMethod
FOpts$transform <- input$iTransform
FOpts$arima <- input$iArima
FOpts$outlier <- input$iOutlier
FOpts$easter <- input$iEaster
FOpts$td <- input$iTd
m <- shiny::isolate(rModel$seas)
if (length(FOpts) > 0 && !is.null(m)){
call <- seasonalview:::add_fopts(m, FOpts)
z <- seasonalview:::upd_seas(m, call = call, senv = senv)
upd_or_fail(z)
}
})
# --- consequences of rModel update --------------------------------------------
# plot
output$oMainPlot <- dygraphs::renderDygraph({
m <- rModel$seas
# could even get view from m
p <- seasonalview:::plot_dygraph(m, series = m$series.view)
shiny::validate(shiny::need(!is.null(p),
"This view is not available for the model. Change view or model."))
p <- dygraphs::dyOptions(p, gridLineColor = "#E1E5EA", axisLineColor = "#303030")
p
})
# view selector (depends on adjustment method (x11/seats))
output$oViewSelect <- shiny::renderUI({
m <- rModel$seas
cc <- lSeries
a <- shiny::selectInput("iSeries", NULL, choices = cc, selected = m$series.view, width = "240px")
return(a)
})
# selectors updated by rModel
output$oFOpts <- shiny::renderUI({
m <- rModel$seas
fopts <- seasonalview:::get_fopts(m)
# update if new fivebestmdl are available, otherwise, use last fivebestmdl
if (is.null(m$spc$automdl$print)){
fbm <- gFiveBestMdl
} else {
fbm <- fivebestmdl(m)
assign("gFiveBestMdl", fbm, envir = senv)
}
if (!fopts$arima %in% c("auto", fbm$arima)){
fopts$arima <- "user"
}
lFOpts2 <- lFOpts
is.user <- sapply(fopts, identical, "user")
lFOpts2[is.user] <- lFOpts.user[is.user]
ll <- as.list(fbm$arima)
names(ll) <- ll
lFOpts2$arima$MANUAL <- c(ll, lFOpts2$arima$MANUAL)
list(
shiny::selectInput("iMethod", "Adjustment Method", choices = lFOpts2$method, selected = fopts$method, width = '100%'),
shiny::selectInput("iTransform", "Pre-Transformation", choices = lFOpts2$transform, selected = fopts$transform, width = '100%'),
shiny::selectInput("iArima", "Arima Model", choices = lFOpts2$arima, selected = fopts$arima, width = '100%'),
shiny::selectInput("iOutlier", "Outlier", choices = lFOpts2$outlier, selected = fopts$outlier, width = '100%'),
shiny::selectInput("iEaster", "Holiday", choices = lFOpts2$easter, selected = fopts$easter, width = '100%'),
shiny::selectInput("iTd", "Trading Days", choices = lFOpts2$td, selected = fopts$td, width = '100%') )
})
# summary
output$oSummaryCoefs <- shiny::renderUI({
shiny::HTML(seasonalview:::html_coefs(rModel$seas))
})
output$oSummaryStats <- shiny::renderUI({
shiny::HTML(seasonalview:::html_stats(rModel$seas))
})
output$oSummaryTests <- shiny::renderUI({
shiny::HTML(seasonalview:::html_tests(rModel$seas))
})
# terminal
output$oTerminal <- shiny::renderUI({
m <- rModel$seas
cstr <- seasonalview:::format_seascall(m$call)
shiny::tagList(
shiny::tags$textarea(id="iTerminal", class="form-control", cstr)
)
})
# x13terminal
output$oTerminalX13 <- shiny::renderUI({
m <- rModel$seas
cstr <- seasonal:::deparse_spclist(m$spc)
shiny::tagList(
shiny::tags$textarea(id="iTerminalX13", class="form-control", cstr)
)
})
# --- stories ------------------------------------------------------------------
# show dom only if code is present
output$oStory <- shiny::renderUI({
story <- rStory$story
view.no <- rStory$view.no
if (is.null(story)){
return(NULL)
} else {
title <- attr(story, "yaml")$title
return(withMathJax(seasonalview:::html_storyview(story[[view.no]], title = title)))
}
})
# to avoid infinite loop cause by repeated clicks on 'next'
shiny::observe({
iStoryFeedback <- input$iStoryFeedback[1]
# message((Sys.time() - shiny::isolate(rStoryFeedback$timestamp)) > 1)
# wait 0.5 sec to accept new input
if ((Sys.time() - shiny::isolate(rStoryFeedback$timestamp)) > 0.5){
rStoryFeedback$click <- c(iStoryFeedback, rnorm(1))
rStoryFeedback$timestamp <- Sys.time()
}
})
# remove story DOM on close
shiny::observe({
sfb <- rStoryFeedback$click[1]
if (!is.null(sfb)){
if (sfb == "close"){
rStory$story <- NULL
rStory$view.no <- 1
}
}
})
# update rStory by iSelectorFeedback
shiny::observe({
sf <- input$iSelectorFeedback[1]
if (!is.null(sf)){
if (!sf %in% names(STORIES)){
stop("ID not in names(STORY): ", sf)
}
rStory$story <- STORIES[[sf]]
rStory$view.no <- 1
}
})
# update rStory by Next and Prev
shiny::observe({
sfb <- rStoryFeedback$click[1]
p <- shiny::isolate(rStory$view.no)
pp <- length(shiny::isolate(rStory$story))
if (!is.null(sfb)){
if (sfb == "next"){
p <- min(p + 1, pp)
} else if (sfb == "prev"){
p <- max(1, p - 1)
} else {
return(NULL)
}
rStory$view.no <- p
}
})
# update rModel by rStory
shiny::observe({
# message("STORY UPD")
story <- rStory$story
view.no <- rStory$view.no
if (is.null(story)){
return(NULL)
}
# message(view.no)
view <- story[[view.no]]
# message(m$series.view)
m <- view$m
z <- seasonalview:::upd_seas(m, series = m$series.view, senv = senv)
rModel$seas <- z
})
# --- errrors -----------------------------------------------------------------
# show error msg on error
shiny::observe({
if (rError$msg == "") return(NULL)
rawerr <- seasonalview:::err_to_html(rError$msg)
irev <- shiny::HTML('<button id="iRevert" type="button" class="btn action-button btn-danger" style = "margin-right: 4px; margin-top: 10px;">Revert</button>')
error.id <<- shiny::showNotification(shiny::HTML(rawerr), action = irev, duration = NULL, type = "error")
})
# remove error msg if error is gone
shiny::observe({
if (rError$msg != "") return(NULL)
if (exists("error.id"))
removeNotification(error.id)
})
# click on iRevert does a pseudo-manipulation of the last working model and thus
# triggers an update (but no run of X-13)
shiny::observe({
if (!is.null(input$iRevert)){
if (input$iRevert > 0){
m <- shiny::isolate(rModel$seas)
z <- seasonalview:::upd_seas(m, senv = senv)
z$msg <- ""
upd_or_fail(z)
}
}
})
# --- close and return ---------------------------------------------------------
if (run.mode == "seasonal"){
shiny::observe({
# if (input$iCancel > 0){
# shiny::stopApp()
# }
if (input$iReturn > 0){
shiny::stopApp(returnValue = shiny::isolate(rModel$seas))
}
})
}
if (run.mode %in% c("seasonal", "x13story")){
shiny::observe({
if (input$iOutput > 0){
out(shiny::isolate(rModel$seas))
}
})
}
shiny::observe({
if (input$iStatic > 0){
m <- shiny::isolate(rModel$seas)
scl <- static(m, test = FALSE)
# fix to avoid reevalation after sorting by add_fopts
if (!is.null(scl$regression.variables)){
rv <- scl$regression.variables
eav <- c("easter[1]", "easter[8]", "easter[15]")
tdv <- c("td", "td1coef")
rv <- c(rv[!rv %in% eav], rv[rv %in% eav])
rv <- c(rv[!rv %in% tdv], rv[rv %in% tdv])
scl$regression.variables <- rv
}
z <- seasonalview:::upd_seas(m, call = scl, senv = senv)
upd_or_fail(z)
}
})
# --- upload and download ------------------------------------------------------
output$oDownloadCsv <- downloadHandler(
filename = "download.csv",
content = function(file) {
m <- shiny::isolate(rModel$seas)
view <- m$series.view
dta <- seasonalview:::series0(m, view, reeval = FALSE, data.frame = TRUE)
write.csv(dta, file, row.names = FALSE)
},
contentType = "text/csv"
)
output$oDownloadXlsx <- downloadHandler(
filename = "download.xlsx",
content = function(file) {
m <- shiny::isolate(rModel$seas)
view <- m$series.view
dta <- seasonalview:::series0(m, view, reeval = FALSE, data.frame = TRUE)
openxlsx::write.xlsx(dta, file)
},
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
shiny::observe({
upl <- input$iFile
m <- shiny::isolate(rModel$seas)
if (!is.null(upl)){
uplMsg <- function(x, type = "error", duration = 15){
error.id <- shiny::showNotification(shiny::HTML(x),
action = NULL, duration = duration,
type = type, closeButton = TRUE)
}
if (upl$size == 0){
uplMsg("<h4>Upload error</h4><p>Uploaded file is of size 0.<p>")
}
type <- tools::file_ext(upl$name)
if (!type %in% c("xlsx", "csv")){
uplMsg("<h4>Upload error</h4>File type must be either <strong>xlsx</strong> or <strong>csv</strong>.")
return(NULL)
}
ser <- try(seasonalview:::read_anything(file.path(upl$datapath), type))
if (inherits(ser, "try-error")){
uplMsg("<h4>Reading error</h4> <p>The file should have the <strong>time in the first</strong>, the <strong>data in the second</strong> column.<p><p> Several time formats are supported, including Excel time formats.</p> <p>If you need an <strong>example file</strong>, download one of the demo series; the file is also uploadable.</p>")
} else {
uplMsg("<h4>Upload successful</h4> <p>Time dimension has been successfully recognized.<p>", "default", duration = 4)
call <- m$call
call$x <- as.name("ser")
assign("ser", ser, envir = senv)
# also update if the call look the same; data has changed.
z <- seasonalview:::upd_seas(init.model, call, force = TRUE, senv = senv)
upd_or_fail(z)
}
}
})
shiny::observe({
series.name <- input$iExample[1]
m <- shiny::isolate(rModel$seas)
if (!is.null(series.name)){
call <- m$call
# exception for chines imports
if (series.name == "imp"){
call$x <- as.call(parse(text = "window(imp, start = 2000)")[[1]])
} else {
call$x <- as.name(series.name)
}
z <- seasonalview:::upd_seas(m, call = call, senv = senv)
upd_or_fail(z)
}
})
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.