R/plotBeta.R

Defines functions plotBeta

Documented in plotBeta

# @importFrom rgl open3d
# @importFrom rgl lines3d
# @importFrom rgl rgl.bringtotop
# @importFrom rgl persp3d
# @importFrom rgl title3d
# @importFrom rgl axis3d
#' @importFrom graphics axis
#' @importFrom graphics filled.contour
#' @importFrom graphics title
#' @importFrom grDevices rainbow

#' @name plotBeta
#' @rdname plotBeta
#'
#' @title Plots the varying beta coefficients of decomposition
#' @description \code{plotBeta} plots the varying beta coefficients of STR decomposition.
#' It plots coefficients only only for independent seasons (one less season than defined).
#' @seealso \code{\link{plot.STR}}
#' @param x Result of STR decomposition.
#' @param xTime Times for data to plot.
#' @param predictorN Predictor number in the decomposition to plot the corresponding beta coefficiets.
#' @param dim Dimensions to use to plot the beta coefficients.
#' When \code{1}, the standard charts are used.
#' When \code{2}, \code{graphics:::filled.contour} function is used.
#' When \code{3}, \code{rgl:::persp3d} is used. The default value is \code{1}.
#' @param type Type of the graph for one dimensional plots.
#' @param pch Symbol code to plot points in 1-dimensional charts. Default value is \code{20}.
#' @param palette Color palette for 2 - and 3 - dimentional plots.
#' @author Alexander Dokumentov
#' @examples
#' \donttest{
#'
#' fit <- AutoSTR(log(grocery))
#' for(i in 1:2) plotBeta(fit, predictorN = i, dim = 2)
#'
#' ########################################
#'
#' TrendSeasonalStructure <- list(segments = list(c(0,1)),
#' sKnots = list(c(1,0)))
#' DailySeasonalStructure <- list(segments = list(c(0,48)),
#'                                sKnots = c(as.list(1:47), list(c(48,0))))
#' WeeklySeasonalStructure <- list(segments = list(c(0,336)),
#'                                 sKnots = c(as.list(seq(4,332,4)), list(c(336,0))))
#' WDSeasonalStructure <- list(segments = list(c(0,48), c(100,148)),
#'                             sKnots = c(as.list(c(1:47,101:147)), list(c(0,48,100,148))))
#'
#' TrendSeasons <- rep(1, nrow(electricity))
#' DailySeasons <- as.vector(electricity[,"DailySeasonality"])
#' WeeklySeasons <- as.vector(electricity[,"WeeklySeasonality"])
#' WDSeasons <- as.vector(electricity[,"WorkingDaySeasonality"])
#'
#' Data <- as.vector(electricity[,"Consumption"])
#' Times <- as.vector(electricity[,"Time"])
#' TempM <- as.vector(electricity[,"Temperature"])
#' TempM2 <- TempM^2
#'
#' TrendTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 116)
#' SeasonTimeKnots <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 24)
#' SeasonTimeKnots2 <- seq(from = head(Times, 1), to = tail(Times, 1), length.out = 12)
#'
#' TrendData <- rep(1, length(Times))
#' SeasonData <- rep(1, length(Times))
#'
#' Trend <- list(name = "Trend",
#'               data = TrendData,
#'               times = Times,
#'               seasons = TrendSeasons,
#'               timeKnots = TrendTimeKnots,
#'               seasonalStructure = TrendSeasonalStructure,
#'               lambdas = c(1500,0,0))
#' WSeason <- list(name = "Weekly seas",
#'                 data = SeasonData,
#'                 times = Times,
#'                 seasons = WeeklySeasons,
#'                 timeKnots = SeasonTimeKnots2,
#'                 seasonalStructure = WeeklySeasonalStructure,
#'                 lambdas = c(0.8,0.6,100))
#' WDSeason <- list(name = "Dayly seas",
#'                  data = SeasonData,
#'                  times = Times,
#'                  seasons = WDSeasons,
#'                  timeKnots = SeasonTimeKnots,
#'                  seasonalStructure = WDSeasonalStructure,
#'                  lambdas = c(0.003,0,240))
#' TrendTempM <- list(name = "Trend temp Mel",
#'                    data = TempM,
#'                    times = Times,
#'                    seasons = TrendSeasons,
#'                    timeKnots = TrendTimeKnots,
#'                    seasonalStructure = TrendSeasonalStructure,
#'                    lambdas = c(1e7,0,0))
#' TrendTempM2 <- list(name = "Trend temp Mel^2",
#'                     data = TempM2,
#'                     times = Times,
#'                     seasons = TrendSeasons,
#'                     timeKnots = TrendTimeKnots,
#'                     seasonalStructure = TrendSeasonalStructure,
#'                     lambdas = c(0.01,0,0)) # Starting parameter is too far from the optimal value
#' Predictors <- list(Trend, WSeason, WDSeason, TrendTempM, TrendTempM2)
#'
#' elec.fit <- STR(data = Data,
#'                 predictors = Predictors,
#'                 gapCV = 48*7)
#'
#' plot(elec.fit,
#'      xTime = as.Date("2000-01-11")+((Times-1)/48-10),
#'      forecastPanels = NULL)
#'
#' plotBeta(elec.fit, predictorN = 4)
#' plotBeta(elec.fit, predictorN = 5) # Beta coefficients are too "wiggly"
#'
#' }
#' @export

plotBeta = function(x, xTime = NULL, predictorN = 1, dim = c(1, 2, 3), type = "o", pch = 20,
                    palette = function(n) rainbow(n, start=0.0, end=0.7))
{
  beta = x$output$predictors[[predictorN]]$beta
  timeKnots = x$input$predictors[[predictorN]]$timeKnots
  if(is.null(xTime)) {
    translatedTimes = timeKnots
  } else {
    times = x$input$predictors[[predictorN]]$times
    translatedTimes = xTime[1]
    for(i in seq_along(timeKnots)) {
      leftInd = max(which(times <= timeKnots[i]))
      rightInd = min(which(times >= timeKnots[i]))
      ratio = ifelse(leftInd == rightInd,
                     0,
                     (timeKnots[i] - times[leftInd]) / (times[rightInd] - times[leftInd]))
      translatedTimes[i] = xTime[leftInd] + ratio * (xTime[rightInd] - xTime[leftInd])
    }
  }
  if(length(beta) == length(translatedTimes)) {
    plot(translatedTimes, beta, type = type, pch = pch,
         xlab = "Time", ylab = "Beta",
         main = x$input$predictors[[predictorN]]$name)
  } else {
    m = matrix(beta, ncol = length(translatedTimes))
    if(dim[1] == 1) {
      plot(translatedTimes, m[1,], ylim = range(m), type = type, pch = pch,
           xlab = "Time", ylab = "Beta",
           main = x$input$predictors[[predictorN]]$name)
      for(i in tail(seq_len(nrow(m)), -1)) {
        lines(translatedTimes, m[i,], type = type, pch = pch, col = i)
      }
    } else if(dim[1] == 2) {
      ylabs = vapply(x$input$predictors[[predictorN]]$seasonalStructure$sKnots,
             FUN = function(x) do.call("paste", as.list(format(x))),
             FUN.VALUE = "")
      filled.contour(translatedTimes, seq_len(nrow(m)), t(m),
                     zlim = range(m), color.palette = palette,
                     plot.title = title(main = x$input$predictors[[predictorN]]$name, xlab = "Time", ylab = "Seasons"),
                     plot.axes = {
                       axis(side = 1, at = translatedTimes, labels = format(translatedTimes));
                       axis(side = 2, at = seq_len(nrow(m)), labels = head(ylabs, nrow(m)))
                     }
      )
    } else if(dim[1] == 3) {
      # "Soft" dependency on rgl. For more details:
      # https://stackoverflow.com/questions/53627676/how-to-make-a-dependency-optional-in-a-package/53627891#53627891
      if (!requireNamespace("rgl", quietly = TRUE)) {
        warning("The rgl package must be installed to use stR::plotBeta with parameter dim = 3")
        return()
      }
      rng = range(m)
      if(diff(rng) == 0) {
        col = "green"
      }
      else {
        col = (t(m) - rng[1])/diff(rng)
        r = palette(65536)
        col = r[round(col * 65535) + 1]
      }
      ylabs = vapply(x$input$predictors[[predictorN]]$seasonalStructure$sKnots,
                     FUN = function(x) do.call("paste", as.list(format(x))),
                     FUN.VALUE = "")
      rgl::open3d(windowRect=c(10, 35, 810, 835))
      rgl::persp3d(y = seq_len(nrow(m)), x = translatedTimes, z = t(m),
              aspect = c(1, 1, 1), ylab = "Seasons", xlab = "Time", zlab = "Beta", col = col, axes = FALSE)
      rgl::axis3d(edge = 'y', at = seq_len(nrow(m)), labels = head(ylabs, nrow(m)))
      rgl::axis3d(edge = 'x', at = translatedTimes, labels = format(translatedTimes))
      rgl::axis3d(edge = 'z')
      rgl::title3d(main = x$input$predictors[[predictorN]]$name)
      rgl::rgl.bringtotop()
    } else {
      stop("dim paramemetr is incorrect. Must be 1, 2, or 3.")
    }
  }
}

# for(i in 1:5)
#   plotBeta(elec.fit, xTime = as.Date("2000-01-11") + ((Times-1)/48-10), predictorN = i, dim = 2)

Try the stR package in your browser

Any scripts or data that you put into this service are public.

stR documentation built on Aug. 11, 2023, 1:10 a.m.