R/plotters.R

Defines functions dyBarChart dyStackedBarChart dyMultiColumn dyBarSeries dyStemSeries dyShadow dyFilledLine dyErrorFill dyMultiColumnGroup dyCandlestickGroup dyStackedBarGroup dyStackedLineGroup dyStackedRibbonGroup computeYaxisRange

Documented in dyBarChart dyBarSeries dyCandlestickGroup dyErrorFill dyFilledLine dyMultiColumn dyMultiColumnGroup dyShadow dyStackedBarChart dyStackedBarGroup dyStackedLineGroup dyStackedRibbonGroup dyStemSeries

#' Employ a dygraph plotter on a series, a group of series, or the whole dygraph
#' 
#' Plotters provide variuos ways to customize how your data appears
#' on the dygraph.  Series-based plotters allow users to mix-and-match different plotters on a 
#' per-series or (with dyGroup) a per-group basis.  See \code{\link{dyPlotter}} for additional detail.
#'
#'
#' @section Available plotters:
#'
#' 
#' Currently the dygraphs package provides the following plotters:
#' 
#' \describe{
#'    \item{dyBarChart()}{Draws a bar plot rather than a line plot. If the provided dygraph
#' features more than one series, dyBarChart will call dyMultiColumn instead.}
#' 
#'    \item{dyStackedBarChart()}{Draws a bar chart stacking all the underlying series.}
#'
#'    \item{dyMultiColumn()}{Draws multiple column bar chart.} 
# 
#'    \item{dyBarSeries()}{Draws a single set of bars for just the provided series.}
#' 
#'    \item{dyStemSeries()}{Draws a single set of stems for just the provided series.}
#' 
#'    \item{dyShadow()}{An extraction of the _fillplotter from dygraph-combined-dev.js, 
#'    drawing the filled area without the line.}
#' 
#'    \item{dyFilledLIne()}{An extraction of the _fillplotter and _lineplotter combo 
#'    from dygraph-combined-dev.js. dyFilledLine allows users to fill only a single series.}
#' 
#'    \item{dyMultiColumnGroup()}{The multicolumn plotter, but on a subset of the series, leaving 
#'    the others for other plotters.}
#' 
#'    \item{dyCandlestick()}{Draw a candlestick chart.}
#' 
#'    \item{dyCandleStickGroup()}{Employed on the provided series, 
#'    but still plotting the others.}
#'    
#'    \item{dyStackerBarGroup()}{Return the data group as stacked bars}
#' 
#'    \item{dyStackerRibbonGroup()}{Return the data group as stacked ribbons}
#' 
#' }
#' 
#' 
#' @param dygraph Dygraph to add plotter to
#' @param name name - or chrarcter vector of names - of (the) series within the data set
#' @param compress (For dyCandlestick) If true, compress data yearly, quarterly, monthly, weekly or daily
#' according to overall amount of bars and/or current zoom level.
#' @param ... additional options to pass to dySeries
#'
#'
#' @return A dygraph with the specified plotter(s) employed.
#' 
#' @name Plotters
#' @examples 
#' ## The following two examples will results in the same dygraph:
#' 
#' dygraph(mdeaths) %>% 
#'   dyBarChart()
#'  
#' lungDeaths <- cbind(mdeaths, fdeaths)
#' dygraph(lungDeaths) %>%
#'   dyMultiColumn()
#'   
# lungDeaths <- cbind(mdeaths, fdeaths)
# dygraph(lungDeaths) %>%
#   dyStackedBarChart()
#'
#' ## Per-series plotters:
#' 
#' lungDeaths <- cbind(mdeaths, fdeaths)
#' dygraph(lungDeaths) %>%
#'   dyBarSeries('fdeaths')
#' 
#' lungDeaths <- cbind(mdeaths, fdeaths)
#' dygraph(lungDeaths) %>%
#'   dyStemSeries('fdeaths')
#'   
#' lungDeaths <- cbind(mdeaths, fdeaths)
#' dygraph(lungDeaths) %>%
#'   dyShadow('fdeaths')
#' 
#' lungDeaths <- cbind(mdeaths, fdeaths)
#' dygraph(lungDeaths) %>%
#'   dyFilledLine('fdeaths')
#'
#' ## A bunch of different plotters together:
#' 
#' lungDeaths <- cbind(fdeaths, mdeaths, ldeaths, foo = fdeaths/2, bar = fdeaths/3)
#' dygraph(lungDeaths) %>%
#'   dyRangeSelector() %>%
#'   dyBarSeries('bar') %>% 
#'   dyStemSeries('mdeaths') %>% 
#'   dyShadow('foo') %>% 
#'   dyFilledLine('fdeaths')
#'
#' ## Group-based plotters:
#'   
# lungDeaths <- cbind(mdeaths, fdeaths, ldeaths)
# dygraph(lungDeaths) %>%
#   dyMultiColumnGroup(c('fdeaths', 'mdeaths'))
#'
#' ## Candlestick plotters:
#'   
#' library(xts)
#' data(sample_matrix)
#' library(dygraphs)
#' dygraph(sample_matrix) %>%
#'   dyCandlestick()
#'   
#' sample<-data.frame(sample_matrix)
#' sample_2<-sample*2
#' names(sample_2)<-c('O', 'H', 'L', 'C')
#' sample<-cbind(sample, sample_2)
#' dygraph(sample) %>% 
#'   dyOptions(stackedGraph = TRUE) %>% 
#'   dyCandlestickGroup(c('Open', 'High', 'Low', 'Close')) %>% 
#'   dyCandlestickGroup(c('O', 'H', 'L', 'C'))
#'
#' ## Stacked Bar and Ribbon Graphs:  
#' 
#' dygraph(lungDeaths) %>% 
#'   dySeries('mdeaths', axis = 'y2') %>%
#'   dyAxis('y', valueRange = c(-100, 1000)) %>% 
#'   dyStackedBarGroup(c('ldeaths', 'fdeaths'))
#'   
#' lungDeaths <- cbind(ldeaths, fdeaths, mdeaths, 
#'                     additive = rep.int(200, length(ldeaths)),
#'                     line = rep.int(3000, length(ldeaths)))
#' dygraph(lungDeaths) %>% 
#'   dySeries('line', strokePattern = 'dashed') %>% 
#'   dySeries('ldeaths', stepPlot = TRUE) %>% 
#'   dyStackedBarGroup(c('additive', 'mdeaths')) %>% 
#'   dyStackedRibbonGroup(c('fdeaths', 'ldeaths'))
NULL

#' @rdname Plotters
#' @export
dyBarChart <- function(dygraph) {
  if (length(dygraph$x$data)>2) {
    dygraph <- dyPlotter(dygraph = dygraph,
              name = "MultiColumn",
              path = system.file("plotters/multicolumn.js", package = "dygraphs"))
    
  } else {
    dygraph <- dyPlotter(dygraph = dygraph,
              name = "BarChart",
              path = system.file("plotters/barchart.js", package = "dygraphs"))
  }
  
  return (dygraph)
}


#' @rdname Plotters
#' @export
dyStackedBarChart <- function(dygraph) {
  dygraph <- dyPlotter(dygraph = dygraph,
              name = "StackedBarChart",
              path = system.file("plotters/stackedbarchart.js", package = "dygraphs"))
  
  names<-dygraph$x$attrs$labels[-1]
  
  dygraph <- computeYaxisRange(dygraph, names)
  dygraph 
  
}


#' @rdname Plotters
#' @export
dyMultiColumn <- function(dygraph) {
  dyPlotter(dygraph = dygraph,
            name = "MultiColumn",
            path = system.file("plotters/multicolumn.js", package = "dygraphs"))
}


#' @rdname Plotters
#' @export
dyBarSeries <- function(dygraph, name, ...) {
  file <- system.file("plotters/barseries.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
  
}


#' @rdname Plotters
#' @export
dyStemSeries <- function(dygraph, name, ...) {
  file <- system.file("plotters/stemplot.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyShadow <- function(dygraph, name, ...) {
  file <- system.file("plotters/fillplotter.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyFilledLine <- function(dygraph, name, ...) {
  file <- system.file("plotters/filledline.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyErrorFill <- function(dygraph, name, ...) {
  file <- system.file("plotters/errorplotter.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyMultiColumnGroup <- function(dygraph, name, ...) {
  file <- system.file("plotters/multicolumngroup.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dyGroup', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyCandlestickGroup <- function(dygraph, name, ...) {
  file <- system.file("plotters/candlestickgroup.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dots <- list(...)
  do.call('dyGroup', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))
}


#' @rdname Plotters
#' @export
dyStackedBarGroup <- function(dygraph, name, ...) {
  dots <- list(...)
  
  if(length(name) < 2) {
    dygraph <- do.call('dyBarSeries', c(list(dygraph = dygraph, name = unlist(name)), dots))
    return(dygraph)
  }
  
  file <- system.file("plotters/stackedbargroup.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dygraph <- do.call('dyGroup', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))

  dygraph <- computeYaxisRange(dygraph, name)
  dygraph 
}

#' @rdname Plotters
#' @export
dyStackedLineGroup <- function(dygraph, name, ...) {
  dots <- list(...)
  
  if(length(name) < 2) {
    # just rely on the base package
    return(dygraph)
  }
  
  file <- system.file("plotters/stackedlinegroup.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dygraph <- do.call('dyGroup', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))

  dygraph <- computeYaxisRange(dygraph, name)
  dygraph 
}
 
 
#' @rdname Plotters
#' @export
dyStackedRibbonGroup <- function(dygraph, name, ...) {
  dots <- list(...)
  
  if(length(name) < 2) {
    dygraph <- do.call('dyFilledLine', c(list(dygraph = dygraph, name = name), dots))
    return(dygraph)
  }
  
  file <- system.file("plotters/stackedribbongroup.js", package = "dygraphs")
  plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
  
  dygraph <- do.call('dyGroup', c(list(dygraph = dygraph, name = name, plotter = plotter_), dots))

  dygraph <- computeYaxisRange(dygraph, name)
  dygraph 
}

computeYaxisRange <- function(dygraph, name){ 
  # most of what happens from here on out is a simplified version of the 
  # stackPoints and computeYaxis functions in the underlying dygraph package.
  # Since we can't modify the Yaxis range from within the specialized plotter,
  # we need to calculate an appropriate valueRange for the group's axis here, then
  # reconcile that against user-provided ranges and then pass into the widget... this
  # way we ensure that the newly stacked data (but initially unstacked to the widget) 
  # doesn't get cutoff by an axis range - computed by the widget - that won't consider
  # the points stacked
  attrs <- dygraph$x$attrs

  data <- attr(dygraph$x, "data")
  cols <- which(names(data) %in% name)
  
  #get all the series, minus the x axis, that are not part of the group
  data_ <- data[-c(1, cols)]
  name_ <- names(data)[which(!names(data) %in% name)][-1]
  
  #grab the axis for the group, we'll calculate the new range only on this axis  
  series <- attrs$series[[name[1]]]
  axisNm <- series$axis
  if (!is.null(axisNm)) {
    axis <- attrs$axes[[axisNm]]
    valueRange <- axis$valueRange
  } else {
    axisNm<-"y"
    axis <- attrs$axes[[axisNm]] <- NULL
    valueRange <- NULL
  }
  
  if(is.null(valueRange)) {
    valueRange <- c(0, 0)
  }
 
  # get the group data fields
  data <- data[cols]
 
  for(i in 1:length(data)) {
      # get the data points
      points <- data[i][[1]]
      # fill NAs... we're not saving this data back into the graph, so this is OK
      is.na(points) <- 0
      
      # add to cumulativeList
      if(!exists('cumulativeYval')) cumulativeYval <- points
      else cumulativeYval <- cumulativeYval + points
      # calculate extremes
      extremes <- range(cumulativeYval)
  }
  
  for(i in 1:length(data_)) {
    if (length(data_)==0) break
    
    # ranges are calcuated separately, so skip those from other axes
    series_ <- attrs$series[[name_[i]]]
    if (!is.null(series_$axis) && series_$axis != axisNm) next
    
    points <- data_[i][[1]]
  
    # fill NAs
    is.na(points) <- 0
    
    # getExtremes
    extremes_ <- range(points)
    extremes[1] <- min(extremes[1], extremes_[1])  
    extremes[2] <- max(extremes[2], extremes_[2])  
  }
  
  valueRange[1] <- min(extremes[1], valueRange[1])
  valueRange[2] <- max(extremes[2], valueRange[2])
    
  # add a little padding since we're hard-setting the range
  valueRange[2] <- valueRange[2] + 0.05 * abs(valueRange[2] - valueRange[1])
  
  axis$options$valueRange <- valueRange
  attrs$axes[[axisNm]] <- axis$options  
  
  # return modified dygraph
  dygraph$x$attrs <- mergeLists(dygraph$x$attrs, attrs)
  return (dygraph)
}

Try the dygraphs package in your browser

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

dygraphs documentation built on May 2, 2019, 3:34 p.m.