Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Trade) Arrows with Optional Annotations #157

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export("%>%")
export(as.yearmon)
export(as.yearqtr)
export(dyAnnotation)
export(dyArrow)
export(dyAxis)
export(dyCSS)
export(dyCallbacks)
Expand All @@ -12,6 +13,8 @@ export(dyCrosshair)
export(dyDataHandler)
export(dyDependency)
export(dyEvent)
export(dyGetPluginOptions)
export(dyHasPlugin)
export(dyHighlight)
export(dyLegend)
export(dyLimit)
Expand All @@ -24,6 +27,7 @@ export(dyRibbon)
export(dyRoller)
export(dySeries)
export(dySeriesData)
export(dySetPluginOptions)
export(dyShading)
export(dyUnzoom)
export(dygraph)
Expand Down
101 changes: 101 additions & 0 deletions R/arrow.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#' dygraph trade arrow
#'
#' Add an arrow to a dygraph
#'
#' @param dygraph Dygraph to add arrow to
#' @param seriesName Name of series within data set.
#' @param x Either numeric or date/time for the event, depending on the format of the
#' x-axis of the dygraph. (For date/time must be a \code{POSIXct} object or another
#' object convertible to \code{POSIXct} via \code{as.POSIXct})
#' @param label Label for event. Defaults to blank
#' @param direction Direction of arrow (up or down)
#' @param fillColor Fill color of arrow. This can be of the form "#AABBCC" or
#' "rgb(255,100,200)" or "yellow". Defaults to white.
#' @param strokeColor Stroke color of arrow. This can be of the form "#AABBCC" or
#' "rgb(255,100,200)" or "yellow". Defaults to black.
#'
#' @return A dygraph with the specified trade arrow.
#'
#' @examples
#' library(dygraphs)
#' dygraph(presidents, main = "Quarterly Presidential Approval Ratings") %>%
#' dyArrow("1950-6-30", "Korea", direction = "down", fillColor = "red") %>%
#' dyArrow("1965-2-09", "Vietnam", direction = "down", fillColor = "red")
#'
#' dygraph(presidents, main = "Quarterly Presidential Approval Ratings") %>%
#' dyArrow(c("1950-6-30", "1965-2-09"),
#' c("Korea", "Vietnam"),
#' direction = "down",
#' fillColor = "red")
#'
#' @export
dyArrow <- function(dygraph,
x,
text = NULL,
tooltip = NULL,
direction = c("up", "down", "left", "right", "ne", "se", "sw", "nw"),
fillColor = "white",
strokeColor = "black",
series = NULL) {

# create arrows
if (!is.null(text) && length(x) != length(text)) {
stop("Length of 'x' and 'text' does not match")
}
if (!is.null(tooltip) && length(x) != length(tooltip)) {
stop("Length of 'x' and 'tooltip' does not match")
}

# validate series if specified
if (!is.null(series) && ! series %in% dygraph$x$attrs$labels) {
stop("The specified series was not found. Valid series names are: ",
paste(dygraph$x$attrs$labels[-1], collapse = ", "))
}

# default the series if necessary
if (is.null(series))
series <- dygraph$x$attrs$labels[length(dygraph$x$attrs$labels)]

fixedtz <- ifelse(is.null(dygraph$x$fixedtz), FALSE, dygraph$x$fixedtz)
scale <- dygraph$x$scale

direction <- match.arg(direction)
arrows <- lapply(seq_along(x),
function(i) {
if (is.null(text))
arrowText <- NULL
else
arrowText <- text[i]
if (is.null(tooltip))
arrowTooltip <- NULL
else
arrowTooltip <- tooltip[i]
list(xval = ifelse(dygraph$x$format == "date",
asISO8601Time(x[i]), x[i]),
text = arrowText,
tooltip = arrowTooltip,
direction = direction,
fillColor = fillColor,
strokeColor = strokeColor,
series = series,
fixedtz = fixedtz,
scale = scale)
})

pluginName <- "Arrow"
if (dyHasPlugin(dygraph, pluginName)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior could just be made part of dyPlugin (i.e. if an a plugin name that already exists in the dygraph is added then we append rather than overwrite options). Would there be any downsides to this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I'm going to make a separate pull request introducing changes in dyPlugin.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR added #158

dygraph <- dySetPluginOptions(dygraph,
pluginName,
append(dyGetPluginOptions(dygraph, pluginName),
arrows))
} else {
dygraph <- dyPlugin(dygraph = dygraph,
name = pluginName,
path = system.file("plugins/arrow.js",
package = "dygraphs"),
options = arrows)
}

# return dygraph
dygraph
}
52 changes: 52 additions & 0 deletions R/dependency.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,58 @@ dyPlugin <- function(dygraph, name, path, options = list(), version = "1.0") {
dygraph
}

#' Check if plugin was included
#'
#' @param dygraph Dygraph to check plugin existance in
#' @param name Name of plugin
#'
#' @return TRUE if plugin was included in dygraph, FALSE otherwise.
#'
#' @export
dyHasPlugin <- function(dygraph, name) {
name %in% names(dygraph$x$plugins)
}

#' Get options of included plugin
#'
#' @param dygraph Dygraph with plugin to get options of
#' @param name Name of plugin
#'
#' @return A list with plugin options.
#'
#' @export
dyGetPluginOptions <- function(dygraph, name) {
if (!dyHasPlugin(dygraph, name)) {
stop(paste0("Can't get options of not loaded plugin: ", name))
}

# return options list
dygraph$x$plugins[[name]]
}

#' Set options to included plugin
#'
#' @param dygraph Dygraph with plugin to set options to
#' @param name Name of plugin
#' @param options New options to set
#'
#' @return A dygraph with plugin with updated options.
#'
#' @export
dySetPluginOptions <- function(dygraph, name, options = list()) {
if (!dyHasPlugin(dygraph, name)) {
stop(paste0("Can't set options for not loaded plugin: ", name))
}

if (length(options) == 0) {
options <- JS("{}")
}
dygraph$x$plugins[[name]] <- options

# return dygraph
dygraph
}

#' Include a dygraph plotter
#'
#' @param dygraph Dygraph to add plotter to
Expand Down
41 changes: 41 additions & 0 deletions docs/gallery-arrow.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: (Trade) Arrows with Optional Annotations
---

```{r setup, include=FALSE}
library(dygraphs)
```

```{r}
dygraph(presidents, main = "Quarterly Presidential Approval Ratings") %>%
dyArrow("1950-7-1",
"Korea",
direction = "se",
fillColor = "#d9534f") %>%
dyArrow("1965-1-1",
"Vietnam",
direction = "sw",
fillColor = "#5cb85c")
```

```{r}
library(quantmod)

getSymbols("SPY", from = "2016-12-01", auto.assign=TRUE)

difference <- SPY[, "SPY.Open"] - SPY[, "SPY.Close"]
decreasing <- which(difference < 0)
increasing <- which(difference > 0)

dyData <- SPY[, "SPY.Close"]

dygraph(dyData) %>%
dyArrow(index(dyData[increasing]),
as.vector(dyData[increasing]),
direction = "up",
fillColor = "green") %>%
dyArrow(index(dyData[decreasing]),
as.vector(dyData[decreasing]),
direction = "down",
fillColor = "red")
```
Loading