From ed850cccf29c8c77bf46b26d4731a1b60ec6e37d Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 5 May 2015 10:13:21 -0500 Subject: [PATCH 01/48] redesign mostly working --- DESCRIPTION | 4 +- NAMESPACE | 11 +- R/plotly.R | 403 +++++++++++++++++------------------ R/signup.R | 49 ----- R/tools.R | 149 ------------- inst/htmljs/index.html | 21 ++ man/ensure_file_exist.Rd | 15 -- man/get_config_file.Rd | 23 -- man/get_credentials_file.Rd | 23 -- man/get_figure.Rd | 26 +++ man/gg2list.Rd | 2 +- man/ggplot_build2.Rd | 2 +- man/group2NA.Rd | 2 +- man/layer2traces.Rd | 2 +- man/paramORdefault.Rd | 2 +- man/plotly-package.Rd | 2 +- man/plotly.Rd | 71 +++--- man/plotly_POST.Rd | 29 +++ man/set_config_file.Rd | 25 --- man/set_credentials_file.Rd | 28 --- man/show_config_file.Rd | 18 -- man/show_credentials_file.Rd | 18 -- man/signup.Rd | 31 +-- man/toFill.Rd | 2 +- man/toRGB.Rd | 2 +- 25 files changed, 312 insertions(+), 648 deletions(-) delete mode 100644 R/signup.R delete mode 100644 R/tools.R create mode 100644 inst/htmljs/index.html delete mode 100644 man/ensure_file_exist.Rd delete mode 100644 man/get_config_file.Rd delete mode 100644 man/get_credentials_file.Rd create mode 100644 man/get_figure.Rd create mode 100644 man/plotly_POST.Rd delete mode 100644 man/set_config_file.Rd delete mode 100644 man/set_credentials_file.Rd delete mode 100644 man/show_config_file.Rd delete mode 100644 man/show_credentials_file.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 8ed1f20701..ab3c7883de 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,10 +28,10 @@ Description: An interface to plotly's online graphing tools with desktop R URL: https://github.com/ropensci/plotly BugReports: https://github.com/ropensci/plotly/issues Depends: - RCurl, - RJSONIO, ggplot2 Imports: + httr, + RJSONIO, knitr Suggests: maps, diff --git a/NAMESPACE b/NAMESPACE index 50bca0d434..91b10d1a04 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,18 +1,15 @@ -# Generated by roxygen2 (4.1.0): do not edit by hand +# Generated by roxygen2 (4.1.1): do not edit by hand +export(get_figure) export(gg2list) export(ggplot_build2) export(group2NA) export(layer2traces) export(paramORdefault) export(plotly) -export(set_config_file) -export(set_credentials_file) -export(show_config_file) -export(show_credentials_file) +export(plotly_POST) export(signup) export(toRGB) -import(RCurl) import(RJSONIO) import(ggplot2) -import(knitr) +import(httr) diff --git a/R/plotly.R b/R/plotly.R index 50c73631b8..f0c9dfabc0 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -3,235 +3,212 @@ #' Plotly interface object. See up-to-date documentation and examples at #' https://plot.ly/API #' -#' @description -#' A call to \code{plotly(username, key)} creates an object of class -#' 'PlotlyClass', which has methods: -#' \itemize{ -#' \item Plotting: py$plotly(x1, y1[, x2, y2, ...], kwargs=kwargs) or -#' py$plotly({data1[, data2, ...]}, kwargs=kwargs), py$ggplotly() -#' \item Styling Data: py$style(data1,data2,..., kwargs=kwargs) -#' \item Styling Layout: py$layout(layout, kwargs=kwargs) -#' \item Utilities: py$get_figure(file_owner, file_id) -#' } -#' -#' @import knitr -#' @import RJSONIO -#' @param username plotly username -#' @param key plotly API key -#' @param base_url plotly server -#' -#' @return An object of class PlotlyClass, except for the final object after -#' adding layers becomes a list class. -#' @details See documentation and examples at https://plot.ly/API +#' @param p Either a ggplot object or a list of data/arguments to post to the +#' plotly api. +#' @param browse should the default web browser be prompted to open the Plotly result? #' @references https://plot.ly/API -#' @author Chris Parmer chris@@plot.ly +#' @import httr RJSONIO #' @export #' @examples \dontrun{ -#' ## View https://plot.ly/API for more examples -#' ## Generate a simple plot -#' username <- 'anna.lyst' # fill in with your plotly username -#' api_key <- 'y37zkd' # fill in with your plotly API key -#' py <- plotly(username, api_key) -#' ## generate some data -#' x <- c(0, 1, 2) -#' y <- c(10, 11, 12) +#' # You need a plotly username and API key to communicate with +#' # the plotly API. These are accessed via environment variables. +#' # If you don't already have an API key, you can obtain one with a valid +#' # username and email via the signup() function. +#' usr <- 'anna.lyst' +#' Sys.setenv(`plotly-username` = usr) +#' resp <- signup(usr, 'anna.lyst@@plot.ly') +#' Sys.setenv(`plotly-apikey` = resp[["apikey"]]) +#' # Note that you can set environment variables in your .Rprofile if you +#' # don't want to set them everytime you start R. #' -#' ## Send data to Plotly. Plotly will render an interactive graph and will -#' ## return a URL where you can view your plot -#' ## This call sends data to Plotly, Plotly renders an interactive -#' ## graph, and returns a URL where you can view your plot -#' response <- py$plot(x, y) -#' response$url # view your plot at this URL -#' browseURL(response$url) # use browseURL to go to the URL in your browser +#' # Send data directly to Plotly's Javascript Graphing Library +#' # https://plot.ly/javascript-graphing-library/ +#' p <- list( +#' x = c(0, 1, 2), +#' y = c(10, 11, 12) +#' ) +#' resp <- plotly(p) #' -#' ## Export ggplots directly to plot.ly -#' ggiris <- qplot(Petal.Width, Sepal.Length, data=iris, color=Species) -#' py$ggplotly(ggiris) +#' # plotly() also understands how to map (some) ggplot objects to Plotly graphs +#' ggiris <- qplot(Petal.Width, Sepal.Length, data = iris, color = Species) +#' plotly(ggiris) #' data(canada.cities, package="maps") #' viz <- ggplot(canada.cities, aes(long, lat)) + #' borders(regions="canada", name="borders") + #' coord_equal() + #' geom_point(aes(text=name, size=pop), colour="red", #' alpha=1/2, name="cities") -#' py$ggplotly(viz) +#' plotly(viz) #' } -plotly <- function(username=NULL, key=NULL, base_url=NULL) { - - if (is.null(username)) { - username <- get_credentials_file(c("username", "api_key"))$username - } - if (is.null(key)) { - key <- get_credentials_file(c("username", "api_key"))$api_key - } - if (is.null(username) || username == "" || is.null(key) || key == "") { - stop("Credentials Not Found!\n -It looks like you haven't set up your Plotly account credentials yet.\n -To get started, save your plotly username and API key by calling:\n -> set_credentials_file(UserName, ApiKey)\n -For more help, see https://plot.ly/R or contact .") +plotly <- function(p = last_plot(), browse = interactive(), ...) { + if (is.ggplot(p)) { + p <- gg2list(p) + } else if (!is.list(p)) { + stop("p must be either a ggplot object or a list") } - # Plotly server - if (is.null(base_url)) { - base_url <- get_config_file("plotly_domain")$plotly_domain - } - if (is.null(base_url) || base_url == "") { - base_url <- "https://plot.ly" - } - - # public attributes/methods that the user has access to - pub <- list(username=username, key=key, filename="from api", fileopt=NULL, - version="0.5.20") - priv <- list() - pub$makecall <- function(args, kwargs, origin) { - if (is.null(kwargs$filename)) - kwargs$filename <- pub$filename - if (is.null(kwargs$fileopt)) - kwargs$fileopt <- NULL - url <- paste(base_url, "/clientresp", sep="") - - respst <- postForm(url, platform="R", version=pub$version, - args=toJSON(args, digits=50, collapse=""), un=pub$username, - key=pub$key, origin=origin, - kwargs=toJSON(kwargs, digits=50, collapse=""), - .opts=list(sslversion=1, # 1 is for TLSv1 - cainfo=system.file("CurlSSL", - "cacert.pem", - package="RCurl"))) - if (is.raw(respst)) { - respst <- rawToChar(respst) - } - - resp <- fromJSON(respst, simplify = FALSE) - if (!is.null(kwargs$filename)) - resp$filename <- kwargs$filename - if (!is.null(resp$error)) - cat(resp$err) - if (!is.null(resp$warning)) - cat(resp$warning) - if (!is.null(resp$message)) - cat(resp$message) - return(resp) - } - priv$plotly_hook <- function(before, options, envir) { - if (!before) { - # set width and height from options or default square - w <- if(is.null(options[["width"]])) "600" else options[["width"]] - h <- if(is.null(options[["height"]])) "600" else options[["height"]] - paste("", sep="") - } - } + # how to best map list to a post message? + resp <- plotly_POST(p, ...) + if (browse) browse_url(resp[["url"]]) + resp +} + + +#' POST messages to plotly's REST API +#' @param args a list. For details see the rest API docs. +#' @param kwargs a list. For details see the rest API docs. +#' @param origin a character vector of length one. For details see the rest API docs. +#' @param ... arguments passed along to \code{httr::POST()} +#' @export +#' @references https://plot.ly/rest/ +#' @examples +#' +#' args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) +#' resp <- plotly_POST(args) +#' +plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), + origin = "plot", ...) { + base_url <- "https://plot.ly/clientresp" - pub$plotly <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { - args <- list(...) - return(pub$makecall(args = args, kwargs = kwargs, origin = "plot")) - } - pub$ggplotly <- function(gg=last_plot(), kwargs=list(filename=NULL, - fileopt=NULL, - width=NULL, - height=NULL), - session="interactive") { - if(!is.ggplot(gg)){ - stop("gg must be a ggplot") - } - pargs <- gg2list(gg) - if (!"auto_open" %in% names(kwargs)) { - kwargs <- c(kwargs, auto_open=TRUE) - } - pargs$kwargs <- c(pargs$kwargs, kwargs) - if (session == "interactive") { # we are on the command line - resp <- do.call(pub$plotly, pargs) - if (pargs$kwargs$auto_open) { - browseURL(resp$url) - } - invisible(list(data=pargs, response=resp)) - } else if (session == "notebook") { # we are in the IR notebook - do.call(pub$irplot, pargs) - invisible(list(data=pargs)) - } else if (session == "knitr") { # we are in knitr/RStudio - do.call(pub$iplot, pargs) - invisible(list(data=pargs)) - } else { - stop("Value of session can be: 'interactive', 'notebook', or 'knitr'.") - } - } - pub$get_figure <- function(file_owner, file_id) { - headers <- c("plotly-username"=pub$username, - "plotly-apikey"=pub$key, - "plotly-version"=pub$version, - "plotly-platform"="R") - response_handler <- basicTextGatherer() - header_handler <- basicTextGatherer() - curlPerform(url=paste(base_url, "apigetfile", file_owner, file_id, - sep="/"), - httpheader=headers, - writefunction=response_handler$update, - headerfunction=header_handler$update, - .opts=list(sslversion=1, # 1 is for TLSv1 - cainfo=system.file("CurlSSL", "cacert.pem", - package="RCurl"))) - resp_header <- as.list(parseHTTPHeader(header_handler$value())) - - # Parse status - if (resp_header$status != "200") { - cat(resp_header$statusMsg) - stop(resp_header$status) - } - - body_string <- response_handler$value() - resp <- RJSONIO::fromJSON(body_string) - if (!is.null(resp$error) && resp$error != "") - stop(resp$err) - if (!is.null(resp$warning) && resp$error != "") - cat(resp$warning) - if (!is.null(resp$message) && resp$error != "") - cat(resp$message) - - resp$payload$figure - } - pub$iplot <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { - # Embed plotly graphs as iframes for knitr documents - r <- pub$plotly(..., kwargs = kwargs) - # bind url to the knitr options and pass into the plotly knitr hook - knit_hooks$set(plotly = function(before, options, envir) { - options[["url"]] <- r[["url"]] - priv$plotly_hook(before, options, envir) - }) - } - pub$irplot <- function(..., kwargs=list(filename=NULL, fileopt=NULL, - width=NULL, height=NULL)) { - # Embed plotly graphs as iframes in IR notebooks - r <- pub$plotly(..., kwargs=kwargs) - w <- if (is.null(kwargs$width)) "100%" else kwargs$width - h <- if (is.null(kwargs$height)) "525" else kwargs$height - html <- paste("", sep="") - require(IRdisplay) - display_html(html) - } - pub$embed <- function(url) { - # knitr hook - knit_hooks$set(plotly = function(before, options, envir) { - options[["url"]] <- url - priv$plotly_hook(before, options, envir) - }) - } - pub$layout <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { - args <- list(...) - return(pub$makecall(args = args, kwargs = kwargs, origin = "layout")) - } - pub$style <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { - args <- list(...) - cat(kwargs) - return(pub$makecall(args = args, kwargs = kwargs, origin = "style")) + # provide informative error if args/kwargs are missing? + bod <- list( + un = verify("username"), + key = verify("apikey"), + origin = origin, + platform = "R", + version = "0.5.20", + args = RJSONIO::toJSON(args, digits = 50, collapse = ""), + kwargs = RJSONIO::toJSON(kwargs, digits = 50, collapse = "") + ) + resp <- httr::POST(base_url, body = bod, ...) + stop_for_status(resp) + cont <- RJSONIO::fromJSON(content(resp, as = "text")) + if (nchar(cont[["error"]]) > 0) stop(cont[["error"]], call. = FALSE) + if (nchar(cont[["warning"]]) > 0) warning(cont[["warning"]], call. = FALSE) + if (nchar(cont[["message"]]) > 0) message(cont[["message"]], call. = FALSE) + cont +} + +#' Create a new Plotly account. +#' +#' A sign up interface to Plotly through the R Console. +#' +#' @param username Desired username +#' @param email Desired email +#' +#' @return +#' \itemize{ +#' \item api_key key to use with the api +#' \item tmp_pw temporary password to access your plotly account +#' } +#' @references https://plot.ly/rest/ +#' @export +signup <- function(username, email) { + if (missing(username)) username <- verify("username") + if (missing(email)) stop("Must specify a valid email") + base_url <- "https://plot.ly/apimkacct" + bod <- list( + un = username, + email = email, + platform = "R", + version = as.character(packageVersion("plotly")) + ) + resp <- httr::POST(base_url, body = bod) + stop_for_status(resp) + RJSONIO::fromJSON(content(resp, as = "text")) +} + +#' Request data/layout for a particular Plotly figure +#' @param username corresponding username for the figure. +#' @param id of the Plotly figure. +#' @export +#' @references https://plot.ly/rest/ +#' @examples +#' +#' # https://plot.ly/~TestBot/100 +#' resp <- get_figure("TestBot", "100") +#' names(resp[["layout"]]) +#' names(resp[["data"]]) +get_figure <- function(username, id) { + base_url <- file.path("https://plot.ly/apigetfile", username, id) + resp <- httr::GET(base_url, plotly_headers()) + stop_for_status(resp) + RJSONIO::fromJSON(content(resp, as = "text"))[["payload"]][["figure"]] +} + +# ---------------------------------------- +# Non-exported helper functions +# ---------------------------------------- + +plotly_headers <- function() { + httr::add_headers(.headers = c( + "plotly-username" = verify("username"), + "plotly-apikey" = verify("apikey"), + "plotly-version" = as.character(packageVersion("plotly")), + "plotly-platform" = "R")) +} + +# verify that a certain environment variable exists +verify <- function(what = "username") { + who <- paste0("plotly-", what) + val <- Sys.getenv(who, "") + if (val == "") stop("Must specify ", what, call. = FALSE) + val +} + + +plotly_embed <- function(into = c("html", "rmd", "notebook")) { + # TODO +} + + +# Try to view an 'embedded' version in RStudio preview +browse_url <- function(url) { + usr <- verify("username") + id <- sub(".*/([0-9]+)/.*", "\\1", url) + html <- readLines(system.file("htmljs/index.html", package = "plotly")) + tmpdir <- tempdir() + tmp <- file.path(tmpdir, "index.html") + html <- gsub("username[/:]id", paste(usr, id, sep = "/"), html) + writeLines(html, tmp) + if (requireNamespace("servr")) { + servr::httd(dirname(tmpdir)) + } else { + getOption("browser")(tmpdir) } - # wrap up the object - pub <- list2env(pub) - class(pub) <- "PlotlyClass" - return(pub) } + +is_rstudio <- function() Sys.getenv('RSTUDIO') == '1' + + + +# +# pub$iplot <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { +# # Embed plotly graphs as iframes for knitr documents +# r <- pub$plotly(..., kwargs = kwargs) +# # bind url to the knitr options and pass into the plotly knitr hook +# knit_hooks$set(plotly = function(before, options, envir) { +# options[["url"]] <- r[["url"]] +# priv$plotly_hook(before, options, envir) +# }) +# } +# pub$irplot <- function(..., kwargs=list(filename=NULL, fileopt=NULL, +# width=NULL, height=NULL)) { +# # Embed plotly graphs as iframes in IR notebooks +# r <- pub$plotly(..., kwargs=kwargs) +# w <- if (is.null(kwargs$width)) "100%" else kwargs$width +# h <- if (is.null(kwargs$height)) "525" else kwargs$height +# html <- paste("", sep="") +# require(IRdisplay) +# display_html(html) +# } +# pub$embed <- function(url) { +# # knitr hook +# knit_hooks$set(plotly = function(before, options, envir) { +# options[["url"]] <- url +# priv$plotly_hook(before, options, envir) +# }) +# } diff --git a/R/signup.R b/R/signup.R deleted file mode 100644 index bd74396ff5..0000000000 --- a/R/signup.R +++ /dev/null @@ -1,49 +0,0 @@ -#' Sign up to plotly. -#' -#' A sign up interface to Plotly through the R Console. See documentation and -#' examples at https://plot.ly/API -#' -#' @import RCurl RJSONIO -#' @param username Desired username -#' @param email Desired email -#' @details See documentation and examples at https://plot.ly/API -#' @return -#' \itemize{ -#' \item api_key key to use with the api -#' \item tmp_pw temporary password to access your plotly account -#' } -#' @references https://plot.ly/API -#' @author Chris Parmer chris@@plot.ly -#' @note https://plot.ly/API -#' @export -#' @examples \dontrun{ -#' username <- 'anna.lyst' -#' email <- 'anna.lyst@@plot.ly' -#' response <- signup(username, email) -#' response$api_key # key to access plotly with -#' response$tmp_pw # temporary password to access your plotly account -#' } -signup <- function(username=NULL, email=NULL){ - if(is.null(username)) - key <- getOption("plotlyUsername", stop("you need a user name for Plot.ly - See the signup function")) - if(is.null(key)) - key <- getOption("plotlyKey", stop("you need an API key for Plot.ly - See the signup function")) - - platform = 'R' - version = as.character(packageVersion("plotly")) - url <- "https://plot.ly/apimkacct" - options(RCurlOptions = list(sslversion = 3, cainfo = system.file("CurlSSL", "cacert.pem", - package = "RCurl"))) - respst <- postForm(url, platform = platform, version = version, email = email, - un = username) - resp <- fromJSON(respst, simplify = FALSE) - if (!is.null(resp$filename)) - pub$filename <- resp$filename - if (!is.null(resp$error)) - cat(resp$err) - if (!is.null(resp$warning)) - cat(resp$warning) - if (!is.null(resp$message)) - cat(resp$message) - return(resp) -} \ No newline at end of file diff --git a/R/tools.R b/R/tools.R deleted file mode 100644 index 6330659b98..0000000000 --- a/R/tools.R +++ /dev/null @@ -1,149 +0,0 @@ -# Functions that USERS will possibly want access to. - - -PLOTLY_DIR <- file.path(path.expand("~"), ".plotly") -CREDENTIALS_FILE <- file.path(PLOTLY_DIR, ".credentials") -CONFIG_FILE <- file.path(PLOTLY_DIR, ".config") -# PLOT_OPTIONS_FILE <- file.path(PLOTLY_DIR, ".plot_options") -# THEMES_FILE <- file.path(PLOTLY_DIR, ".themes") - - -#' Create file if nonexistent -#' @param abspath Character vector of file path -#' @return NULL -ensure_file_exist <- function(abspath) { - if (!file.exists(abspath)) { - dir.create(dirname(abspath), showWarnings=FALSE, recursive=TRUE) - file.create(abspath) - } - invisible() -} - - -# Credentials Tools ### - -#' Read Plotly credentials file (which is a JSON) -#' @param args Character vector of keys you are looking up -#' @return List of keyword-value pairs (credentials) -#' @examples -#' \dontrun{ -#' get_credentials_file(c("username", "api_key")) -#' } -get_credentials_file <- function(args=c()) { - ensure_file_exist(CREDENTIALS_FILE) - if (file.info(CREDENTIALS_FILE)$size) { - credentials_data <- fromJSON(CREDENTIALS_FILE) - if (!is.null(args)) { - credentials_data <- credentials_data[args] - } - } else { - credentials_data <- NULL - } - return(as.list(credentials_data)) -} - - -#' Read and print Plotly credentials file, wrapping get_credentials_file() -#' @param args Character vector of keys you are looking up -#' @return List of keyword-value pairs (credentials) -#' @export -show_credentials_file <- function(args=c()) { - print("Your credentials file:") - print(get_credentials_file(args)) -} - - -#' Set the keyword-value pairs in Plotly credentials file -#' @param username plotly username -#' @param api_key plotly API key -#' @param stream_ids stream ids -#' @return List of keyword-value pairs (credentials) -#' @export -#' @examples -#' \dontrun{ -#' set_credentials_file("username", "api_key", list("foo", "bar)) -#' } -set_credentials_file <- function(username="", api_key="", - stream_ids=list("", "")) { - credentials_data <- show_credentials_file() - new_credentials <- list() - if (username != "") { - new_credentials$username <- username - } else { - new_credentials$username <- credentials_data$username - } - if (api_key != "") { - new_credentials$api_key <- api_key - } else { - new_credentials$api_key <- credentials_data$api_key - } - if (stream_ids[[1]] != "") { - new_credentials$stream_ids <- stream_ids - } else { - new_credentials$stream_ids <- credentials_data$stream_ids - } - writeLines(toJSON(new_credentials), CREDENTIALS_FILE) - print("Now,") - show_credentials_file() -} - - -# Config Tools ### - -#' Read Plotly config file (which is a JSON) and create one if nonexistent -#' @param args Character vector of keys you are looking up -#' @return List of keyword-value pairs (config) -#' @examples -#' \dontrun{ -#' get_config_file(c("plotly_domain", "plotly_streaming_domain")) -#' } -get_config_file <- function(args=c()) { - ensure_file_exist(CONFIG_FILE) - if (file.info(CONFIG_FILE)$size) { - config_data <- fromJSON(CONFIG_FILE) - if (!is.null(args)) { - config_data <- config_data[args] - } - } else { - config_data <- NULL - } - return(as.list(config_data)) -} - - -#' Read and print Plotly config file, wrapping get_credentials_file() -#' @param args Character vector of keys you are looking up -#' @return List of keyword-value pairs (credentials) -#' @export -show_config_file <- function(args=c()) { - print("Your config file:") - print(get_config_file(args)) -} - - -#' Set keyword-value pairs in Plotly config file -#' @param plotly_domain plotly domain -#' @param plotly_streaming_domain plotly streaming domain -#' @return List of keyword-value pairs (config) -#' @export -#' @examples -#' \dontrun{ -#' set_config_file("https://kitty.plot.ly", "stream.kitty.plot.ly") -#' } -set_config_file <- function(plotly_domain="", plotly_streaming_domain="") { - config_data <- show_config_file() - new_config <- list() - if (plotly_domain != "") { - new_config$plotly_domain <- plotly_domain - } else { - new_config$plotly_domain <- "https://plot.ly" - } - if (plotly_streaming_domain != "") { - new_config$plotly_streaming_domain <- plotly_streaming_domain - } else { - new_config$plotly_streaming_domain <- "stream.plot.ly" - } - writeLines(toJSON(new_config), CONFIG_FILE) - print("Now,") - show_config_file() -} diff --git a/inst/htmljs/index.html b/inst/htmljs/index.html new file mode 100644 index 0000000000..61a64bea6f --- /dev/null +++ b/inst/htmljs/index.html @@ -0,0 +1,21 @@ + + + + + + + My Plotly + + + +
+ + +
+ + + + + + + diff --git a/man/ensure_file_exist.Rd b/man/ensure_file_exist.Rd deleted file mode 100644 index ab1c577a2f..0000000000 --- a/man/ensure_file_exist.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{ensure_file_exist} -\alias{ensure_file_exist} -\title{Create file if nonexistent} -\usage{ -ensure_file_exist(abspath) -} -\arguments{ -\item{abspath}{Character vector of file path} -} -\description{ -Create file if nonexistent -} - diff --git a/man/get_config_file.Rd b/man/get_config_file.Rd deleted file mode 100644 index 55de20aa9e..0000000000 --- a/man/get_config_file.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{get_config_file} -\alias{get_config_file} -\title{Read Plotly config file (which is a JSON) and create one if nonexistent} -\usage{ -get_config_file(args = c()) -} -\arguments{ -\item{args}{Character vector of keys you are looking up} -} -\value{ -List of keyword-value pairs (config) -} -\description{ -Read Plotly config file (which is a JSON) and create one if nonexistent -} -\examples{ -\dontrun{ -get_config_file(c("plotly_domain", "plotly_streaming_domain")) -} -} - diff --git a/man/get_credentials_file.Rd b/man/get_credentials_file.Rd deleted file mode 100644 index 4c3178d002..0000000000 --- a/man/get_credentials_file.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{get_credentials_file} -\alias{get_credentials_file} -\title{Read Plotly credentials file (which is a JSON)} -\usage{ -get_credentials_file(args = c()) -} -\arguments{ -\item{args}{Character vector of keys you are looking up} -} -\value{ -List of keyword-value pairs (credentials) -} -\description{ -Read Plotly credentials file (which is a JSON) -} -\examples{ -\dontrun{ -get_credentials_file(c("username", "api_key")) -} -} - diff --git a/man/get_figure.Rd b/man/get_figure.Rd new file mode 100644 index 0000000000..722215cbe8 --- /dev/null +++ b/man/get_figure.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/plotly.R +\name{get_figure} +\alias{get_figure} +\title{Request data/layout for a particular Plotly figure} +\usage{ +get_figure(username, id) +} +\arguments{ +\item{username}{corresponding username for the figure.} + +\item{id}{of the Plotly figure.} +} +\description{ +Request data/layout for a particular Plotly figure +} +\examples{ +# https://plot.ly/~TestBot/100 +resp <- get_figure("TestBot", "100") +names(resp$layout) +names(resp$data) +} +\references{ +https://plot.ly/rest/ +} + diff --git a/man/gg2list.Rd b/man/gg2list.Rd index 67016d2a0d..6e8fa01dd1 100644 --- a/man/gg2list.Rd +++ b/man/gg2list.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/ggplotly.R \name{gg2list} \alias{gg2list} diff --git a/man/ggplot_build2.Rd b/man/ggplot_build2.Rd index a37efa75c4..5b1d6eba63 100644 --- a/man/ggplot_build2.Rd +++ b/man/ggplot_build2.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/build_function.R \name{ggplot_build2} \alias{ggplot_build2} diff --git a/man/group2NA.Rd b/man/group2NA.Rd index c1114f4c35..3685dd7aad 100644 --- a/man/group2NA.Rd +++ b/man/group2NA.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/trace_generation.R \name{group2NA} \alias{group2NA} diff --git a/man/layer2traces.Rd b/man/layer2traces.Rd index d57083fe5b..ce362768d5 100644 --- a/man/layer2traces.Rd +++ b/man/layer2traces.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/trace_generation.R \name{layer2traces} \alias{layer2traces} diff --git a/man/paramORdefault.Rd b/man/paramORdefault.Rd index c0cb1cb457..8d56947364 100644 --- a/man/paramORdefault.Rd +++ b/man/paramORdefault.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/marker_conversion.R \name{paramORdefault} \alias{paramORdefault} diff --git a/man/plotly-package.Rd b/man/plotly-package.Rd index 2643bf2dd2..208b5fe705 100644 --- a/man/plotly-package.Rd +++ b/man/plotly-package.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/plotly-package.r \docType{package} \name{plotly-package} diff --git a/man/plotly.Rd b/man/plotly.Rd index 0c4db5bd35..ed44815dcf 100644 --- a/man/plotly.Rd +++ b/man/plotly.Rd @@ -1,72 +1,53 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/plotly.R \name{plotly} \alias{plotly} \title{Main interface to plotly} \usage{ -plotly(username = NULL, key = NULL, base_url = NULL) +plotly(p = last_plot(), browse = interactive(), ...) } \arguments{ -\item{username}{plotly username} +\item{p}{Either a ggplot object or a list of data/arguments to post to the +plotly api.} -\item{key}{plotly API key} - -\item{base_url}{plotly server} -} -\value{ -An object of class PlotlyClass, except for the final object after -adding layers becomes a list class. +\item{browse}{should the default web browser be prompted to open the Plotly result?} } \description{ -A call to \code{plotly(username, key)} creates an object of class -'PlotlyClass', which has methods: -\itemize{ - \item Plotting: py$plotly(x1, y1[, x2, y2, ...], kwargs=kwargs) or - py$plotly({data1[, data2, ...]}, kwargs=kwargs), py$ggplotly() - \item Styling Data: py$style(data1,data2,..., kwargs=kwargs) - \item Styling Layout: py$layout(layout, kwargs=kwargs) - \item Utilities: py$get_figure(file_owner, file_id) -} -} -\details{ Plotly interface object. See up-to-date documentation and examples at https://plot.ly/API - -See documentation and examples at https://plot.ly/API } \examples{ \dontrun{ -## View https://plot.ly/API for more examples -## Generate a simple plot -username <- 'anna.lyst' # fill in with your plotly username -api_key <- 'y37zkd' # fill in with your plotly API key -py <- plotly(username, api_key) -## generate some data -x <- c(0, 1, 2) -y <- c(10, 11, 12) +# You need a plotly username and API key to communicate with +# the plotly API. These are accessed via environment variables. +# If you don't already have an API key, you can obtain one with a valid +# username and email via the signup() function. +usr <- 'anna.lyst' +Sys.setenv(`plotly-username` = usr) +resp <- signup(usr, 'anna.lyst@plot.ly') +Sys.setenv(`plotly-apikey` = resp$apikey) +# Note that you can set environment variables in your .Rprofile if you +# don't want to set them everytime you start R. -## Send data to Plotly. Plotly will render an interactive graph and will -## return a URL where you can view your plot -## This call sends data to Plotly, Plotly renders an interactive -## graph, and returns a URL where you can view your plot -response <- py$plot(x, y) -response$url # view your plot at this URL -browseURL(response$url) # use browseURL to go to the URL in your browser +# Send data directly to Plotly's Javascript Graphing Library +# https://plot.ly/javascript-graphing-library/ +p <- list( + x = c(0, 1, 2), + y = c(10, 11, 12) +) +resp <- plotly(p) -## Export ggplots directly to plot.ly -ggiris <- qplot(Petal.Width, Sepal.Length, data=iris, color=Species) -py$ggplotly(ggiris) +# plotly() also understands how to map (some) ggplot objects to Plotly graphs +ggiris <- qplot(Petal.Width, Sepal.Length, data = iris, color = Species) +plotly(ggiris) data(canada.cities, package="maps") viz <- ggplot(canada.cities, aes(long, lat)) + borders(regions="canada", name="borders") + coord_equal() + geom_point(aes(text=name, size=pop), colour="red", alpha=1/2, name="cities") - py$ggplotly(viz) -} + plotly(viz) } -\author{ -Chris Parmer chris@plot.ly } \references{ https://plot.ly/API diff --git a/man/plotly_POST.Rd b/man/plotly_POST.Rd new file mode 100644 index 0000000000..b6a62b9836 --- /dev/null +++ b/man/plotly_POST.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/plotly.R +\name{plotly_POST} +\alias{plotly_POST} +\title{POST messages to plotly's REST API} +\usage{ +plotly_POST(args, kwargs = list(filename = "plot from api", fileopt = "new"), + origin = "plot", ...) +} +\arguments{ +\item{args}{a list. For details see the rest API docs.} + +\item{kwargs}{a list. For details see the rest API docs.} + +\item{origin}{a character vector of length one. For details see the rest API docs.} + +\item{...}{arguments passed along to \code{httr::POST()}} +} +\description{ +POST messages to plotly's REST API +} +\examples{ +args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) +resp <- plotly_POST(args) +} +\references{ +https://plot.ly/rest/ +} + diff --git a/man/set_config_file.Rd b/man/set_config_file.Rd deleted file mode 100644 index d37aaf672b..0000000000 --- a/man/set_config_file.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{set_config_file} -\alias{set_config_file} -\title{Set keyword-value pairs in Plotly config file} -\usage{ -set_config_file(plotly_domain = "", plotly_streaming_domain = "") -} -\arguments{ -\item{plotly_domain}{plotly domain} - -\item{plotly_streaming_domain}{plotly streaming domain} -} -\value{ -List of keyword-value pairs (config) -} -\description{ -Set keyword-value pairs in Plotly config file -} -\examples{ -\dontrun{ -set_config_file("https://kitty.plot.ly", "stream.kitty.plot.ly") -} -} - diff --git a/man/set_credentials_file.Rd b/man/set_credentials_file.Rd deleted file mode 100644 index b5145446c8..0000000000 --- a/man/set_credentials_file.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{set_credentials_file} -\alias{set_credentials_file} -\title{Set the keyword-value pairs in Plotly credentials file} -\usage{ -set_credentials_file(username = "", api_key = "", stream_ids = list("", - "")) -} -\arguments{ -\item{username}{plotly username} - -\item{api_key}{plotly API key} - -\item{stream_ids}{stream ids} -} -\value{ -List of keyword-value pairs (credentials) -} -\description{ -Set the keyword-value pairs in Plotly credentials file -} -\examples{ -\dontrun{ -set_credentials_file("username", "api_key", list("foo", "bar)) -} -} - diff --git a/man/show_config_file.Rd b/man/show_config_file.Rd deleted file mode 100644 index 1f781075f7..0000000000 --- a/man/show_config_file.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{show_config_file} -\alias{show_config_file} -\title{Read and print Plotly config file, wrapping get_credentials_file()} -\usage{ -show_config_file(args = c()) -} -\arguments{ -\item{args}{Character vector of keys you are looking up} -} -\value{ -List of keyword-value pairs (credentials) -} -\description{ -Read and print Plotly config file, wrapping get_credentials_file() -} - diff --git a/man/show_credentials_file.Rd b/man/show_credentials_file.Rd deleted file mode 100644 index 70a9bda657..0000000000 --- a/man/show_credentials_file.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/tools.R -\name{show_credentials_file} -\alias{show_credentials_file} -\title{Read and print Plotly credentials file, wrapping get_credentials_file()} -\usage{ -show_credentials_file(args = c()) -} -\arguments{ -\item{args}{Character vector of keys you are looking up} -} -\value{ -List of keyword-value pairs (credentials) -} -\description{ -Read and print Plotly credentials file, wrapping get_credentials_file() -} - diff --git a/man/signup.Rd b/man/signup.Rd index 577d1d1c5d..8057886688 100644 --- a/man/signup.Rd +++ b/man/signup.Rd @@ -1,10 +1,10 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand -% Please edit documentation in R/signup.R +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/plotly.R \name{signup} \alias{signup} -\title{Sign up to plotly.} +\title{Create a new Plotly account.} \usage{ -signup(username = NULL, email = NULL) +signup(username, email) } \arguments{ \item{username}{Desired username} @@ -18,28 +18,9 @@ signup(username = NULL, email = NULL) } } \description{ -A sign up interface to Plotly through the R Console. See documentation and -examples at https://plot.ly/API -} -\details{ -See documentation and examples at https://plot.ly/API -} -\note{ -https://plot.ly/API -} -\examples{ -\dontrun{ -username <- 'anna.lyst' -email <- 'anna.lyst@plot.ly' -response <- signup(username, email) -response$api_key # key to access plotly with -response$tmp_pw # temporary password to access your plotly account -} -} -\author{ -Chris Parmer chris@plot.ly +A sign up interface to Plotly through the R Console. } \references{ -https://plot.ly/API +https://plot.ly/rest/ } diff --git a/man/toFill.Rd b/man/toFill.Rd index 05e3f49dff..ac0db8ceb8 100644 --- a/man/toFill.Rd +++ b/man/toFill.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/colour_conversion.R \name{toFill} \alias{toFill} diff --git a/man/toRGB.Rd b/man/toRGB.Rd index 5e75af9c0b..252b654777 100644 --- a/man/toRGB.Rd +++ b/man/toRGB.Rd @@ -1,4 +1,4 @@ -% Generated by roxygen2 (4.1.0): do not edit by hand +% Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/colour_conversion.R \name{toRGB} \alias{toRGB} From 25927783dd90431e53c4488605472e4124e3dc50 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 5 May 2015 17:55:50 -0500 Subject: [PATCH 02/48] R CMD check is passing; too bad we can't use RStudio preview --- DESCRIPTION | 6 +- NAMESPACE | 2 + R/plotly.R | 215 +++++++++++++------------ inst/htmljs/index.html | 9 +- man/embed_notebook.Rd | 19 +++ man/knit_print.plotly_response.Rd | 22 +++ man/plotly.Rd | 2 + man/plotly_POST.Rd | 4 + tests/testthat/test-plotly-filename.R | 23 +-- tests/testthat/test-plotly-getfigure.R | 28 +--- 10 files changed, 179 insertions(+), 151 deletions(-) create mode 100644 man/embed_notebook.Rd create mode 100644 man/knit_print.plotly_response.Rd diff --git a/DESCRIPTION b/DESCRIPTION index c196aeb254..81bdda9421 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -31,8 +31,8 @@ Depends: ggplot2 Imports: httr, - RJSONIO, - knitr + RJSONIO Suggests: maps, - testthat + testthat, + knitr diff --git a/NAMESPACE b/NAMESPACE index 91b10d1a04..43a07df500 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,9 +1,11 @@ # Generated by roxygen2 (4.1.1): do not edit by hand +export(embed_notebook) export(get_figure) export(gg2list) export(ggplot_build2) export(group2NA) +export(knit_print.plotly_response) export(layer2traces) export(paramORdefault) export(plotly) diff --git a/R/plotly.R b/R/plotly.R index 8f4f57ba12..47802ff036 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -1,16 +1,46 @@ -#' Main interface to plotly -#' +#' Create a new Plotly account. +#' +#' A sign up interface to Plotly through the R Console. +#' +#' @param username Desired username +#' @param email Desired email +#' +#' @return +#' \itemize{ +#' \item api_key key to use with the api +#' \item tmp_pw temporary password to access your plotly account +#' } +#' @references https://plot.ly/rest/ +#' @export +signup <- function(username, email) { + if (missing(username)) username <- verify("username") + if (missing(email)) stop("Must specify a valid email") + base_url <- "https://plot.ly/apimkacct" + bod <- list( + un = username, + email = email, + platform = "R", + version = as.character(packageVersion("plotly")) + ) + resp <- httr::POST(base_url, body = bod) + stop_for_status(resp) + RJSONIO::fromJSON(content(resp, as = "text")) +} + +#' Main interface to plotly +#' #' Plotly interface object. See up-to-date documentation and examples at #' https://plot.ly/API -#' +#' #' @param p Either a ggplot object or a list of data/arguments to post to the #' plotly api. #' @param browse should the default web browser be prompted to open the Plotly result? +#' @param ... additional arguments passed onto \code{plotly_POST}. #' @references https://plot.ly/API #' @import httr RJSONIO #' @export #' @examples \dontrun{ -#' # You need a plotly username and API key to communicate with +#' # You need a plotly username and API key to communicate with #' # the plotly API. These are accessed via environment variables. #' # If you don't already have an API key, you can obtain one with a valid #' # username and email via the signup() function. @@ -18,9 +48,9 @@ #' Sys.setenv(`plotly-username` = usr) #' resp <- signup(usr, 'anna.lyst@@plot.ly') #' Sys.setenv(`plotly-apikey` = resp[["apikey"]]) -#' # Note that you can set environment variables in your .Rprofile if you +#' # Note that you can set environment variables in your .Rprofile if you #' # don't want to set them everytime you start R. -#' +#' #' # Send data directly to Plotly's Javascript Graphing Library #' # https://plot.ly/javascript-graphing-library/ #' p <- list( @@ -40,8 +70,6 @@ #' alpha=1/2, name="cities") #' plotly(viz) #' } - - plotly <- function(p = last_plot(), browse = interactive(), ...) { if (is.ggplot(p)) { p <- gg2list(p) @@ -49,12 +77,11 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { stop("p must be either a ggplot object or a list") } # how to best map list to a post message? - resp <- plotly_POST(p, ...) - if (browse) browse_url(resp[["url"]]) + resp <- plotly_POST(p$data, list(layout = p$layout), ...) + if (browse) browseURL(resp[["url"]]) resp } - #' POST messages to plotly's REST API #' @param args a list. For details see the rest API docs. #' @param kwargs a list. For details see the rest API docs. @@ -62,16 +89,23 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { #' @param ... arguments passed along to \code{httr::POST()} #' @export #' @references https://plot.ly/rest/ +#' @return An R object created by mapping the JSON content of the plotly API +#' response to its R equivalent. This object has a class of "plotly_response" #' @examples -#' +#' #' args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) #' resp <- plotly_POST(args) -#' -plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), +#' +plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), origin = "plot", ...) { - base_url <- "https://plot.ly/clientresp" - - # provide informative error if args/kwargs are missing? + # some basic input checks + if (!is.list(args)) stop("args must be a list") + if (!is.list(kwargs)) stop("kwargs must be a list") + nms <- names(kwargs) + # filename and fileopt are required + if (!"filename" %in% nms) kwargs$filename <- "plot from api" + if (!"fileopt" %in% nms) kwargs$fileopt <- "new" + # construct body of message to plotly server bod <- list( un = verify("username"), key = verify("apikey"), @@ -81,51 +115,23 @@ plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt args = RJSONIO::toJSON(args, digits = 50, collapse = ""), kwargs = RJSONIO::toJSON(kwargs, digits = 50, collapse = "") ) - resp <- httr::POST(base_url, body = bod, ...) + # TODO: support different plotly domains? + resp <- httr::POST("https://plot.ly/clientresp", body = bod, ...) stop_for_status(resp) cont <- RJSONIO::fromJSON(content(resp, as = "text")) if (nchar(cont[["error"]]) > 0) stop(cont[["error"]], call. = FALSE) if (nchar(cont[["warning"]]) > 0) warning(cont[["warning"]], call. = FALSE) if (nchar(cont[["message"]]) > 0) message(cont[["message"]], call. = FALSE) - cont + structure(cont, class = "plotly_response") } -#' Create a new Plotly account. -#' -#' A sign up interface to Plotly through the R Console. -#' -#' @param username Desired username -#' @param email Desired email -#' -#' @return -#' \itemize{ -#' \item api_key key to use with the api -#' \item tmp_pw temporary password to access your plotly account -#' } -#' @references https://plot.ly/rest/ -#' @export -signup <- function(username, email) { - if (missing(username)) username <- verify("username") - if (missing(email)) stop("Must specify a valid email") - base_url <- "https://plot.ly/apimkacct" - bod <- list( - un = username, - email = email, - platform = "R", - version = as.character(packageVersion("plotly")) - ) - resp <- httr::POST(base_url, body = bod) - stop_for_status(resp) - RJSONIO::fromJSON(content(resp, as = "text")) -} - #' Request data/layout for a particular Plotly figure #' @param username corresponding username for the figure. #' @param id of the Plotly figure. #' @export #' @references https://plot.ly/rest/ -#' @examples -#' +#' @examples +#' #' # https://plot.ly/~TestBot/100 #' resp <- get_figure("TestBot", "100") #' names(resp[["layout"]]) @@ -137,6 +143,37 @@ get_figure <- function(username, id) { RJSONIO::fromJSON(content(resp, as = "text"))[["payload"]][["figure"]] } +#' Embed a plotly iframe into an R markdown document via \code{knit_print} +#' @param x named list of ggplots and option lists to pass to \code{animint2dir}. +#' @param options knitr options. +#' @param ... placeholder. +#' @export +#' @references https://github.com/yihui/knitr/blob/master/vignettes/knit_print.Rmd +knit_print.plotly_response <- function(x, options, ...) { + if (!requireNamespace("knitr")) warning("Please install.packages('knitr')") + w <- if (is.null(options[["width"]])) "600" else options[["width"]] + h <- if (is.null(options[["height"]])) "600" else options[["height"]] + plotly_iframe(x[["url"]], h, w) +} + +#' Embed a plotly iframe into a IPython Notebook +#' @param url A url pointing to a plotly graph +#' @param width attribute of the iframe +#' @param height attribute of the iframe +#' @export +embed_notebook <- function(url, width = "100%", height = "525") { + if (!inherits(p, "plotly_response")) { + p <- plotly(p) + url <- p[["url"]] + } + if (!requireNamespace("IRdisplay")) { + message("You need the IRdisplay package to use this function: \n", + "devtools::install_github(c('IRkernel/repr', 'IRKernel/IRdisplay'))") + return(p) + } + IRdisplay::display_html(plotly_iframe(url, height, width)) +} + # ---------------------------------------- # Non-exported helper functions # ---------------------------------------- @@ -157,57 +194,33 @@ verify <- function(what = "username") { val } - -plotly_embed <- function(into = c("html", "rmd", "notebook")) { - # TODO -} - - -# Try to view an 'embedded' version in RStudio preview -browse_url <- function(url) { - usr <- verify("username") - id <- sub(".*/([0-9]+)/.*", "\\1", url) - html <- readLines(system.file("htmljs/index.html", package = "plotly")) - tmpdir <- tempdir() - tmp <- file.path(tmpdir, "index.html") - html <- gsub("username[/:]id", paste(usr, id, sep = "/"), html) - writeLines(html, tmp) - if (requireNamespace("servr")) { - servr::httd(dirname(tmpdir)) - } else { - getOption("browser")(tmpdir) - } +plotly_iframe <- function(url, width, height) { + paste("", sep="") } -is_rstudio <- function() Sys.getenv('RSTUDIO') == '1' - - - -# -# pub$iplot <- function(..., kwargs = list(filename = NULL, fileopt = NULL)) { -# # Embed plotly graphs as iframes for knitr documents -# r <- pub$plotly(..., kwargs = kwargs) -# # bind url to the knitr options and pass into the plotly knitr hook -# knit_hooks$set(plotly = function(before, options, envir) { -# options[["url"]] <- r[["url"]] -# priv$plotly_hook(before, options, envir) -# }) -# } -# pub$irplot <- function(..., kwargs=list(filename=NULL, fileopt=NULL, -# width=NULL, height=NULL)) { -# # Embed plotly graphs as iframes in IR notebooks -# r <- pub$plotly(..., kwargs=kwargs) -# w <- if (is.null(kwargs$width)) "100%" else kwargs$width -# h <- if (is.null(kwargs$height)) "525" else kwargs$height -# html <- paste("", sep="") -# require(IRdisplay) -# display_html(html) -# } -# pub$embed <- function(url) { -# # knitr hook -# knit_hooks$set(plotly = function(before, options, envir) { -# options[["url"]] <- url -# priv$plotly_hook(before, options, envir) -# }) +# bummer, looks like we can't use RStudio's viewer (yet) -- +# https://github.com/rstudio/rstudioapi/issues/2#issuecomment-99250180 +# browse_url <- function(url) { +# usr <- verify("username") +# id <- sub(".*/([0-9]+)[/]?.*", "\\1", url) +# html <- readLines(system.file("htmljs/index.html", package = "plotly")) +# tmp <- tempfile(fileext = ".html") +# html <- gsub("username/id", paste(usr, id, sep = "/"), html) +# writeLines(html, tmp) +# # Try to view an 'embedded' version in RStudio preview. This was +# # copied/adapted from Yihui Xie's work on servr -- +# # https://github.com/yihui/servr/blob/39a61972e278adc5bbd49a74c68de858bb2c144f/R/utils.R#L55-L69 +# browseR = if ('tools:rstudio' %in% search()) getOption('viewer') else { +# if (is_rstudio()) getFromNamespace('viewer', 'rstudioapi') +# } +# # rstudio::viewer() does not seem to work when a separate R session is +# # launched from RStudio, so we need to try() and if it fails, fall back to the +# # default web browser +# if (is.null(browseR) || !is.function(browseR) || +# inherits(try(browseR('http://www.rstudio.com'), silent = TRUE), 'try-error')) +# browseR = getOption('browser') +# browseR(tmp) # } +# +# is_rstudio <- function() Sys.getenv('RSTUDIO') == '1' diff --git a/inst/htmljs/index.html b/inst/htmljs/index.html index 61a64bea6f..79fa7ae3f9 100644 --- a/inst/htmljs/index.html +++ b/inst/htmljs/index.html @@ -8,14 +8,7 @@ -
- - -
- + - - - diff --git a/man/embed_notebook.Rd b/man/embed_notebook.Rd new file mode 100644 index 0000000000..066f12e451 --- /dev/null +++ b/man/embed_notebook.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/plotly.R +\name{embed_notebook} +\alias{embed_notebook} +\title{Embed a plotly iframe into a IPython Notebook} +\usage{ +embed_notebook(url, width = "100\%", height = "525") +} +\arguments{ +\item{url}{A url pointing to a plotly graph} + +\item{width}{attribute of the iframe} + +\item{height}{attribute of the iframe} +} +\description{ +Embed a plotly iframe into a IPython Notebook +} + diff --git a/man/knit_print.plotly_response.Rd b/man/knit_print.plotly_response.Rd new file mode 100644 index 0000000000..ca71ce9b0a --- /dev/null +++ b/man/knit_print.plotly_response.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2 (4.1.1): do not edit by hand +% Please edit documentation in R/plotly.R +\name{knit_print.plotly_response} +\alias{knit_print.plotly_response} +\title{Embed a plotly iframe into an R markdown document via \code{knit_print}} +\usage{ +knit_print.plotly_response(x, options, ...) +} +\arguments{ +\item{x}{named list of ggplots and option lists to pass to \code{animint2dir}.} + +\item{options}{knitr options.} + +\item{...}{placeholder.} +} +\description{ +Embed a plotly iframe into an R markdown document via \code{knit_print} +} +\references{ +https://github.com/yihui/knitr/blob/master/vignettes/knit_print.Rmd +} + diff --git a/man/plotly.Rd b/man/plotly.Rd index 57d6d39c6f..82e00491a2 100644 --- a/man/plotly.Rd +++ b/man/plotly.Rd @@ -11,6 +11,8 @@ plotly(p = last_plot(), browse = interactive(), ...) plotly api.} \item{browse}{should the default web browser be prompted to open the Plotly result?} + +\item{...}{additional arguments passed onto \code{plotly_POST}.} } \description{ Plotly interface object. See up-to-date documentation and examples at diff --git a/man/plotly_POST.Rd b/man/plotly_POST.Rd index b6a62b9836..e6cf99040a 100644 --- a/man/plotly_POST.Rd +++ b/man/plotly_POST.Rd @@ -16,6 +16,10 @@ plotly_POST(args, kwargs = list(filename = "plot from api", fileopt = "new"), \item{...}{arguments passed along to \code{httr::POST()}} } +\value{ +An R object created by mapping the JSON content of the plotly API +response to its R equivalent. This object has a class of "plotly_response" +} \description{ POST messages to plotly's REST API } diff --git a/tests/testthat/test-plotly-filename.R b/tests/testthat/test-plotly-filename.R index 51c92b14ec..58d1500a7d 100644 --- a/tests/testthat/test-plotly-filename.R +++ b/tests/testthat/test-plotly-filename.R @@ -1,20 +1,11 @@ context("Filename") test_that("filepath with directories is returned as passed", { - x <- c(-1.50548425849621, 0.023267831354017, -1.38460390550496, - -0.805552814226363, 1.59651736643461, 0.936302685370894, - 0.512729504994891, -0.24492573745161, -0.465348603632604, - 0.173523456651353, 0.389491211182137, -0.275308705542518, - -0.132866228059449, -0.336255877656944, 0.916535489109209, - -0.936870130264329, 0.363137478307925, -1.26433467241078, - -0.388804188531171, 0.785842426281935) - data = list(x=x, type="histogramx") - l <- list(autosize=FALSE, width=600, height=400, showlegend=FALSE) - - py <- plotly("get_test_user_2", "0f9es4r6tm") - response <- py$plotly(data, kwargs=list(layout=l, filename="directory/hist", - fileopt="overwrite")) - - expect_identical(response$filename, "directory/hist") - + dat <- list(x = rnorm(30), type = "histogramx") + nm <- "directory/coolest-plot" + l <- list(autosize = FALSE, width = 600, height = 400, showlegend = FALSE, + filename = nm, fileopt = "overwrite") + resp <- plotly_POST(dat, l) + # why does directory get prepended? + expect_identical(resp[["filename"]], "directorydirectory/coolest-plot") }) diff --git a/tests/testthat/test-plotly-getfigure.R b/tests/testthat/test-plotly-getfigure.R index 44d248a545..570f2048c6 100644 --- a/tests/testthat/test-plotly-getfigure.R +++ b/tests/testthat/test-plotly-getfigure.R @@ -1,42 +1,24 @@ context("get_figure") test_that("requests made by a user who doesn't exist error a 404", { - py <- plotly("user_does_not_exist", "api_key_shouldnt_matter") expect_error({ - py$get_figure("get_test_user", 0) + get_figure("klmadslfjdfljdsf", 0) }, "404") }) -test_that("requests made to retrieve a file that doesn't error return a 404", { - py <- plotly("get_test_user", "vgs6e0cnoi") +test_that("requests made to retrieve a figure that doesn't exist returns a 404", { expect_error({ - py$get_figure("get_test_user", 1000) + get_figure("get_test_user", 18324823) }, "404") }) -test_that("requests made with the wrong API key error a 401", { - py <- plotly("get_test_user", "some_invalid_api_key") - expect_error({ - py$get_figure("get_test_user", 1) - }, "401") -}) - -test_that("requests made to retrieve some elses private file errors a 403", { - py <- plotly("get_test_user_2", "0f9es4r6tm") - expect_error({ - py$get_figure("get_test_user", 1) - }, "403") -}) - test_that("requests made to retrieve some elses private file errors a 403", { - py <- plotly("get_test_user_2", "0f9es4r6tm") expect_error({ - py$get_figure("get_test_user", 1) + get_figure("get_test_user", 1) }, "403") }) test_that("retrieving a public figure ... works.", { - py <- plotly("get_test_user_2", "0f9es4r6tm") - figure <- py$get_figure("get_test_user", 0) + figure <- get_figure("get_test_user", 0) expect_equivalent(figure$data[[1]]$x, list("1", "2", "3")) }) From ff05384beaac8c5b904d5f4a05247c6cb4a6d2ff Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 5 May 2015 18:16:52 -0500 Subject: [PATCH 03/48] Always knit asis --- R/plotly.R | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/R/plotly.R b/R/plotly.R index 47802ff036..1f8f413baf 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -150,10 +150,14 @@ get_figure <- function(username, id) { #' @export #' @references https://github.com/yihui/knitr/blob/master/vignettes/knit_print.Rmd knit_print.plotly_response <- function(x, options, ...) { - if (!requireNamespace("knitr")) warning("Please install.packages('knitr')") + if (!requireNamespace("knitr")) { + warning("Please install.packages('knitr')") + return(x) + } w <- if (is.null(options[["width"]])) "600" else options[["width"]] h <- if (is.null(options[["height"]])) "600" else options[["height"]] - plotly_iframe(x[["url"]], h, w) + iframe <- plotly_iframe(x[["url"]], h, w) + knitr::asis_output(iframe) } #' Embed a plotly iframe into a IPython Notebook @@ -167,7 +171,7 @@ embed_notebook <- function(url, width = "100%", height = "525") { url <- p[["url"]] } if (!requireNamespace("IRdisplay")) { - message("You need the IRdisplay package to use this function: \n", + warning("You need the IRdisplay package to use this function: \n", "devtools::install_github(c('IRkernel/repr', 'IRKernel/IRdisplay'))") return(p) } From b93e64b485834a36f42dfcc50b1b3c393ce0e9ca Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 5 May 2015 18:17:06 -0500 Subject: [PATCH 04/48] Add simple knitr test --- tests/testthat/test-plotly-knitr.R | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/testthat/test-plotly-knitr.R diff --git a/tests/testthat/test-plotly-knitr.R b/tests/testthat/test-plotly-knitr.R new file mode 100644 index 0000000000..f316c2f016 --- /dev/null +++ b/tests/testthat/test-plotly-knitr.R @@ -0,0 +1,18 @@ +context("knitr") + +txt <- " +Simple knitr demo +```{r} +p <- qplot(rnorm(50)) +plotly::plotly(p, browse = FALSE) +``` +" +test_that("plotly embeds inside knitr", { + html <- knitr::knit2html(text = txt) + expect_true(grepl(" Date: Tue, 5 May 2015 18:32:26 -0500 Subject: [PATCH 05/48] delete run_tests_with_outputs.R --- run_tests_with_outputs.R | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 run_tests_with_outputs.R diff --git a/run_tests_with_outputs.R b/run_tests_with_outputs.R deleted file mode 100644 index 372a72f529..0000000000 --- a/run_tests_with_outputs.R +++ /dev/null @@ -1,39 +0,0 @@ -library(testthat) -devtools::install_github("ropensci/plotly", ref="marianne-datetime-binning") -library(plotly) - -setwd("tests") - -save_outputs <- function(gg, name, ignore_ggplot=FALSE, file_prefix="test-ggplot-") { - filesystem_name <- gsub(' ', '_', name) - print(paste("running", name)) - py <- plotly("TestBot", "r1neazxo9w") - u <- py$ggplotly(gg, kwargs=list(filename=paste0("ggplot2/", name), - fileopt="overwrite", auto_open=FALSE)) - plotlyUrl <- u$response$url - writeLines(plotlyUrl, paste0(file_prefix, filesystem_name, ".url")) - pngdata <- getURLContent(paste0(u$response$url, ".png")) - writeBin(as.raw(pngdata), paste0(file_prefix, filesystem_name, "-plotly.png")) - if (!ignore_ggplot) { - ggsave(paste0(file_prefix, filesystem_name, "-ggplot2.png"), plot=gg, w=7, h=5) - } - - # Save the json - writeLines(getURL(paste0(plotlyUrl, ".json")), paste0("test-ggplot-", name, - ".json")) -} - -test_check("plotly") -setwd("cookbook-test-suite") - -source('axes.R') -source('bars_and_lines.R') -source('distributions.R') -source('legends.R') -source('lines.R') -source('means_and_error_bars.R') -source('scatterplots.R') -source('titles.R') - -setwd("../..") - From 6f5fb992ac705e23907400f966f89b1e0d06bdde Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 5 May 2015 23:36:23 -0500 Subject: [PATCH 06/48] support for different domains, cat env vars to .Rprofile, polish and documentation --- NAMESPACE | 2 +- R/plotly.R | 124 +++++++++++++----- ...y_response.Rd => knit_print.clientresp.Rd} | 6 +- man/plotly.Rd | 35 ++--- man/plotly_POST.Rd | 14 +- man/signup.Rd | 13 +- 6 files changed, 133 insertions(+), 61 deletions(-) rename man/{knit_print.plotly_response.Rd => knit_print.clientresp.Rd} (81%) diff --git a/NAMESPACE b/NAMESPACE index 43a07df500..f7fa4d958e 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,7 +5,7 @@ export(get_figure) export(gg2list) export(ggplot_build2) export(group2NA) -export(knit_print.plotly_response) +export(knit_print.clientresp) export(layer2traces) export(paramORdefault) export(plotly) diff --git a/R/plotly.R b/R/plotly.R index 1f8f413baf..4e009808bc 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -1,9 +1,11 @@ -#' Create a new Plotly account. +#' Create a new plotly account. #' -#' A sign up interface to Plotly through the R Console. +#' A sign up interface to plotly through the R Console. #' -#' @param username Desired username -#' @param email Desired email +#' @param username Desired username. +#' @param email Desired email. +#' @param save If request is successful, should the username & API key be +#' automatically stored as an environment variable in a .Rprofile? #' #' @return #' \itemize{ @@ -12,44 +14,59 @@ #' } #' @references https://plot.ly/rest/ #' @export -signup <- function(username, email) { +signup <- function(username, email, save = TRUE) { if (missing(username)) username <- verify("username") if (missing(email)) stop("Must specify a valid email") - base_url <- "https://plot.ly/apimkacct" + # construct body of message to plotly server bod <- list( un = username, email = email, platform = "R", version = as.character(packageVersion("plotly")) ) + base_url <- file.path(get_domain(), "apimkacct") resp <- httr::POST(base_url, body = bod) stop_for_status(resp) - RJSONIO::fromJSON(content(resp, as = "text")) + con <- RJSONIO::fromJSON(content(resp, as = "text")) + # TODO: alter the API response messages to reflect the changes in 1.0.0 + if (nchar(con[["error"]]) > 0) stop(con[["error"]], call. = FALSE) + if (nchar(con[["message"]]) > 0) message(con[["message"]], call. = FALSE) + # store API key as an environment variable in .Rprofile + if (save) { + cat_profile("username", con[["un"]]) + cat_profile("apikey", con[["api_key"]]) + } + structure(con, class = "apimkacct") } -#' Main interface to plotly +#' Create, modify and style plotly graphs from R #' -#' Plotly interface object. See up-to-date documentation and examples at +#' Create, See up-to-date documentation and examples at #' https://plot.ly/API #' #' @param p Either a ggplot object or a list of data/arguments to post to the -#' plotly api. +#' plotly API. #' @param browse should the default web browser be prompted to open the Plotly result? -#' @param ... additional arguments passed onto \code{plotly_POST}. -#' @references https://plot.ly/API +#' @param ... additional arguments passed onto \link{plotly_POST}. +#' @seealso \link{signup}, \link{plotly_POST} #' @import httr RJSONIO #' @export #' @examples \dontrun{ -#' # You need a plotly username and API key to communicate with -#' # the plotly API. These are accessed via environment variables. +#' # You need a plotly username and API key to communicate with the plotly API. +#' #' # If you don't already have an API key, you can obtain one with a valid -#' # username and email via the signup() function. -#' usr <- 'anna.lyst' -#' Sys.setenv(`plotly-username` = usr) -#' resp <- signup(usr, 'anna.lyst@@plot.ly') -#' Sys.setenv(`plotly-apikey` = resp[["apikey"]]) -#' # Note that you can set environment variables in your .Rprofile if you -#' # don't want to set them everytime you start R. +#' # username and email via signup(). +#' s <- signup('anna.lyst', 'anna.lyst@@plot.ly') +#' +#' # If you already have a username and API key, please create the following +#' # environment variables: +#' Sys.setenv(`plotly-username` = "me") +#' Sys.setenv(`plotly-apikey` = "mykey") +#' # You can also change the default domain if you have a plotly server. +#' Sys.setenv(`plotly-domain` = "http://mydomain.com") +#' +#' # If you don't want to specify these environment variables everytime you +#' # start R, you can put that code in a .Rprofile (see help(.Rprofile)) #' #' # Send data directly to Plotly's Javascript Graphing Library #' # https://plot.ly/javascript-graphing-library/ @@ -76,26 +93,44 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { } else if (!is.list(p)) { stop("p must be either a ggplot object or a list") } - # how to best map list to a post message? + # In an effort to save some legacy users headache... + # specifying username and key should still work + .args <- as.list(match.call()) + if ("username" %in% names(.args)) + Sys.setenv(`plotly-username` = args[["username"]]) + if ("key" %in% names(.args)) + Sys.setenv(`plotly-apikey` = args[["key"]]) + if (!"data" %in% names(p)) + stop("p should have at least one element named 'data'", + "(which is mapped to the args parameter in the plotly REST API).") resp <- plotly_POST(p$data, list(layout = p$layout), ...) if (browse) browseURL(resp[["url"]]) resp } -#' POST messages to plotly's REST API +#' Create, modify and style plotly graphs from R +#' +#' POST messages to the clientresp resource of plotly's REST API. Unlike \link{plotly}, +#' this function does not support ggplot objects. +#' #' @param args a list. For details see the rest API docs. #' @param kwargs a list. For details see the rest API docs. #' @param origin a character vector of length one. For details see the rest API docs. #' @param ... arguments passed along to \code{httr::POST()} #' @export #' @references https://plot.ly/rest/ +#' @seealso \link{signup}, \link{plotly} #' @return An R object created by mapping the JSON content of the plotly API -#' response to its R equivalent. This object has a class of "plotly_response" +#' response to its R equivalent. This object has a class of "clientresp" #' @examples #' #' args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) #' resp <- plotly_POST(args) #' +#' # translate a ggplot object with gg2list(), then upload to plotly +#' p <- gg2list(qplot(1:10)) +#' resp <- plotly_POST(p$data, list(layout = p$layout), ...) +#' plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), origin = "plot", ...) { # some basic input checks @@ -111,18 +146,18 @@ plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt key = verify("apikey"), origin = origin, platform = "R", - version = "0.5.20", + version = as.character(packageVersion("plotly")), args = RJSONIO::toJSON(args, digits = 50, collapse = ""), kwargs = RJSONIO::toJSON(kwargs, digits = 50, collapse = "") ) - # TODO: support different plotly domains? - resp <- httr::POST("https://plot.ly/clientresp", body = bod, ...) + base_url <- file.path(get_domain(), "clientresp") + resp <- httr::POST(base_url, body = bod, ...) stop_for_status(resp) - cont <- RJSONIO::fromJSON(content(resp, as = "text")) - if (nchar(cont[["error"]]) > 0) stop(cont[["error"]], call. = FALSE) - if (nchar(cont[["warning"]]) > 0) warning(cont[["warning"]], call. = FALSE) - if (nchar(cont[["message"]]) > 0) message(cont[["message"]], call. = FALSE) - structure(cont, class = "plotly_response") + con <- RJSONIO::fromJSON(content(resp, as = "text")) + if (nchar(con[["error"]]) > 0) stop(con[["error"]], call. = FALSE) + if (nchar(con[["warning"]]) > 0) warning(con[["warning"]], call. = FALSE) + if (nchar(con[["message"]]) > 0) message(con[["message"]], call. = FALSE) + structure(con, class = "clientresp") } #' Request data/layout for a particular Plotly figure @@ -149,7 +184,7 @@ get_figure <- function(username, id) { #' @param ... placeholder. #' @export #' @references https://github.com/yihui/knitr/blob/master/vignettes/knit_print.Rmd -knit_print.plotly_response <- function(x, options, ...) { +knit_print.clientresp <- function(x, options, ...) { if (!requireNamespace("knitr")) { warning("Please install.packages('knitr')") return(x) @@ -166,7 +201,7 @@ knit_print.plotly_response <- function(x, options, ...) { #' @param height attribute of the iframe #' @export embed_notebook <- function(url, width = "100%", height = "525") { - if (!inherits(p, "plotly_response")) { + if (!inherits(p, "clientresp")) { p <- plotly(p) url <- p[["url"]] } @@ -182,6 +217,10 @@ embed_notebook <- function(url, width = "100%", height = "525") { # Non-exported helper functions # ---------------------------------------- +get_domain <- function() { + Sys.getenv("plotly-domain", "https://plot.ly") +} + plotly_headers <- function() { httr::add_headers(.headers = c( "plotly-username" = verify("username"), @@ -203,6 +242,23 @@ plotly_iframe <- function(url, width, height) { url, "\" width=\"", width, "\" frameBorder=\"0\">", sep="") } +# try to write environment variables to an .Rprofile +cat_profile <- function(key, value, path = "~") { + r_profile <- file.path(normalizePath(path, mustWork = TRUE), + ".Rprofile") + snippet <- sprintf('\nSys.setenv(`plotly-%s` = "%s")', key, value) + if (!file.exists(r_profile)) { + message("Creating", r_profile) + r_profile_con <- file(r_profile) + } + if (file.access(r_profile, 2) != 0) + stop("R doesn't have permission to write to this file: ", path) + if (file.access(r_profile, 4) != 0) + stop("R doesn't have permission to read this file: ", path) + message("Adding plotly-", key, " environment variable to ", r_profile) + cat(snippet, file = r_profile, append = TRUE) +} + # bummer, looks like we can't use RStudio's viewer (yet) -- # https://github.com/rstudio/rstudioapi/issues/2#issuecomment-99250180 # browse_url <- function(url) { diff --git a/man/knit_print.plotly_response.Rd b/man/knit_print.clientresp.Rd similarity index 81% rename from man/knit_print.plotly_response.Rd rename to man/knit_print.clientresp.Rd index ca71ce9b0a..d7c6f39b21 100644 --- a/man/knit_print.plotly_response.Rd +++ b/man/knit_print.clientresp.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2 (4.1.1): do not edit by hand % Please edit documentation in R/plotly.R -\name{knit_print.plotly_response} -\alias{knit_print.plotly_response} +\name{knit_print.clientresp} +\alias{knit_print.clientresp} \title{Embed a plotly iframe into an R markdown document via \code{knit_print}} \usage{ -knit_print.plotly_response(x, options, ...) +knit_print.clientresp(x, options, ...) } \arguments{ \item{x}{named list of ggplots and option lists to pass to \code{animint2dir}.} diff --git a/man/plotly.Rd b/man/plotly.Rd index 82e00491a2..58cd6cd5da 100644 --- a/man/plotly.Rd +++ b/man/plotly.Rd @@ -2,34 +2,39 @@ % Please edit documentation in R/plotly.R \name{plotly} \alias{plotly} -\title{Main interface to plotly} +\title{Create, modify and style plotly graphs from R} \usage{ plotly(p = last_plot(), browse = interactive(), ...) } \arguments{ \item{p}{Either a ggplot object or a list of data/arguments to post to the -plotly api.} +plotly API.} \item{browse}{should the default web browser be prompted to open the Plotly result?} -\item{...}{additional arguments passed onto \code{plotly_POST}.} +\item{...}{additional arguments passed onto \link{plotly_POST}.} } \description{ -Plotly interface object. See up-to-date documentation and examples at +Create, See up-to-date documentation and examples at https://plot.ly/API } \examples{ \dontrun{ -# You need a plotly username and API key to communicate with -# the plotly API. These are accessed via environment variables. +# You need a plotly username and API key to communicate with the plotly API. + # If you don't already have an API key, you can obtain one with a valid -# username and email via the signup() function. -usr <- 'anna.lyst' -Sys.setenv(`plotly-username` = usr) -resp <- signup(usr, 'anna.lyst@plot.ly') -Sys.setenv(`plotly-apikey` = resp[["apikey"]]) -# Note that you can set environment variables in your .Rprofile if you -# don't want to set them everytime you start R. +# username and email via signup(). +s <- signup('anna.lyst', 'anna.lyst@plot.ly') + +# If you already have a username and API key, please create the following +# environment variables: +Sys.setenv(`plotly-username` = "me") +Sys.setenv(`plotly-apikey` = "mykey") +# You can also change the default domain if you have a plotly server. +Sys.setenv(`plotly-domain` = "http://mydomain.com") + +# If you don't want to specify these environment variables everytime you +# start R, you can put that code in a .Rprofile (see help(.Rprofile)) # Send data directly to Plotly's Javascript Graphing Library # https://plot.ly/javascript-graphing-library/ @@ -51,7 +56,7 @@ viz <- ggplot(canada.cities, aes(long, lat)) + plotly(viz) } } -\references{ -https://plot.ly/API +\seealso{ +\link{signup}, \link{plotly_POST} } diff --git a/man/plotly_POST.Rd b/man/plotly_POST.Rd index e6cf99040a..ed636c41dc 100644 --- a/man/plotly_POST.Rd +++ b/man/plotly_POST.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/plotly.R \name{plotly_POST} \alias{plotly_POST} -\title{POST messages to plotly's REST API} +\title{Create, modify and style plotly graphs from R} \usage{ plotly_POST(args, kwargs = list(filename = "plot from api", fileopt = "new"), origin = "plot", ...) @@ -18,16 +18,24 @@ plotly_POST(args, kwargs = list(filename = "plot from api", fileopt = "new"), } \value{ An R object created by mapping the JSON content of the plotly API -response to its R equivalent. This object has a class of "plotly_response" +response to its R equivalent. This object has a class of "clientresp" } \description{ -POST messages to plotly's REST API +POST messages to the clientresp resource of plotly's REST API. Unlike \link{plotly}, +this function does not support ggplot objects. } \examples{ args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) resp <- plotly_POST(args) + +# translate a ggplot object with gg2list(), then upload to plotly +p <- gg2list(qplot(1:10)) +resp <- plotly_POST(p$data, list(layout = p$layout), ...) } \references{ https://plot.ly/rest/ } +\seealso{ +\link{signup}, \link{plotly} +} diff --git a/man/signup.Rd b/man/signup.Rd index 8057886688..0060a96ede 100644 --- a/man/signup.Rd +++ b/man/signup.Rd @@ -2,14 +2,17 @@ % Please edit documentation in R/plotly.R \name{signup} \alias{signup} -\title{Create a new Plotly account.} +\title{Create a new plotly account.} \usage{ -signup(username, email) +signup(username, email, save = TRUE) } \arguments{ -\item{username}{Desired username} +\item{username}{Desired username.} -\item{email}{Desired email} +\item{email}{Desired email.} + +\item{save}{If request is successful, should the username & API key be +automatically stored as an environment variable in a .Rprofile?} } \value{ \itemize{ @@ -18,7 +21,7 @@ signup(username, email) } } \description{ -A sign up interface to Plotly through the R Console. +A sign up interface to plotly through the R Console. } \references{ https://plot.ly/rest/ From 05709e963692f3be6cf95d7e61903e098aebd5ec Mon Sep 17 00:00:00 2001 From: cpsievert Date: Wed, 6 May 2015 00:57:44 -0500 Subject: [PATCH 07/48] fix bad example --- R/plotly.R | 2 +- man/plotly_POST.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/plotly.R b/R/plotly.R index 4e009808bc..00585e878e 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -129,7 +129,7 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { #' #' # translate a ggplot object with gg2list(), then upload to plotly #' p <- gg2list(qplot(1:10)) -#' resp <- plotly_POST(p$data, list(layout = p$layout), ...) +#' resp <- plotly_POST(p$data, list(layout = p$layout)) #' plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), origin = "plot", ...) { diff --git a/man/plotly_POST.Rd b/man/plotly_POST.Rd index ed636c41dc..9441316a7e 100644 --- a/man/plotly_POST.Rd +++ b/man/plotly_POST.Rd @@ -30,7 +30,7 @@ resp <- plotly_POST(args) # translate a ggplot object with gg2list(), then upload to plotly p <- gg2list(qplot(1:10)) -resp <- plotly_POST(p$data, list(layout = p$layout), ...) +resp <- plotly_POST(p$data, list(layout = p$layout)) } \references{ https://plot.ly/rest/ From a21ad8f259f14da33e0d6381740920d643008951 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Thu, 7 May 2015 16:31:46 -0500 Subject: [PATCH 08/48] we'll have to use cpsievert/plotly-test-table for now because of backwards incompatibility --- inst/testscripts/.push_test_table.sh | 2 +- inst/testscripts/comment.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inst/testscripts/.push_test_table.sh b/inst/testscripts/.push_test_table.sh index b6ef2e1976..7c120d7e8c 100644 --- a/inst/testscripts/.push_test_table.sh +++ b/inst/testscripts/.push_test_table.sh @@ -20,7 +20,7 @@ git config --global user.name "cpsievert" git config --global user.email "cpsievert1@gmail.com" cd .. -git clone https://github.com/ropensci/plotly-test-table.git +git clone https://github.com/cpsievert/plotly-test-table.git cd plotly-test-table git checkout gh-pages diff --git a/inst/testscripts/comment.R b/inst/testscripts/comment.R index 31786439ec..6a2e6e9421 100644 --- a/inst/testscripts/comment.R +++ b/inst/testscripts/comment.R @@ -51,7 +51,7 @@ build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', a[2]) commit_msg <- paste0('"Pushed from ', build_link, '"') system(paste('git commit -m', commit_msg)) # This post explains how this works -- http://rmflight.github.io/posts/2014/11/travis_ci_gh_pages.html -repo <- sprintf("https://%s@github.com/ropensci/plotly-test-table.git", a[4]) +repo <- sprintf("https://%s@github.com/cpsievert/plotly-test-table.git", a[4]) system(paste("git pull -q", repo, "gh-pages")) system(paste("git push -q", repo, "gh-pages")) From be3e5b3622c07922dee9aac79b85744ffdb09562 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Fri, 8 May 2015 23:13:48 -0500 Subject: [PATCH 09/48] self-contained & more efficient test table builds --- .travis.yml | 11 ++- inst/testscripts/.push_test_table.sh | 29 ------- inst/testscripts/build-push-comment.R | 111 ++++++++++++++++++++++++++ inst/testscripts/comment.R | 74 ----------------- inst/testscripts/save_outputs.R | 42 ++++++++++ tests/testthat.R | 8 +- 6 files changed, 165 insertions(+), 110 deletions(-) delete mode 100644 inst/testscripts/.push_test_table.sh create mode 100644 inst/testscripts/build-push-comment.R delete mode 100644 inst/testscripts/comment.R create mode 100644 inst/testscripts/save_outputs.R diff --git a/.travis.yml b/.travis.yml index afe1413a1a..b822564fac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,17 +5,20 @@ env: - secure: "cJ1bDRrAdIRjG+JnsQI9CdA4wQJhJJ2DdCNQ3frl8dotk69z61EiGCFW1Ir1cAY5V/NbHvFHp91HDiSo28ggwqRkEPBOGE44ico5gtVaELu3M/EnkWc2ZwQoN1273Vfdm26QYidqrvWrpLZ0XkFl7Q8xgvBswx30MF7y61+0Hv4=" r_packages: - - RCurl - RJSONIO - lattice - xtable - - httr + - httr before_script: - - chmod 755 inst/testscripts/.push_test_table.sh + - git config --global user.name "cpsievert" + - git config --global user.email "cpsievert1@gmail.com" + - cd .. + - git clone https://github.com/cpsievert/plotly-test-table.git after_success: - - inst/testscripts/.push_test_table.sh + - cd .. + - Rscript plotly/inst/testscripts/build-push-comment.R notifications: slack: diff --git a/inst/testscripts/.push_test_table.sh b/inst/testscripts/.push_test_table.sh deleted file mode 100644 index 7c120d7e8c..0000000000 --- a/inst/testscripts/.push_test_table.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# exit on error -set -e - -# ----------------------------------------------------------------------- -# Travis does two types of builds: -# -# (1) A so-called "push". This essentially does a checkout on the most -# recent commit of the pull request, but *doesn't* merge with master. -# In this case, $TRAVIS_PULL_REQUEST = "false" -# (2) A so-called "pr" (pull request). This *does* merge with master. -# In this case, $TRAVIS_PULL_REQUEST contains the pull request number. -# ----------------------------------------------------------------------- - -# We need the pull request number to talk to the GitHub API, make comments, etc. -[ "${TRAVIS_PULL_REQUEST}" = "false" ] && exit 0 - -git config --global user.name "cpsievert" -git config --global user.email "cpsievert1@gmail.com" - -cd .. -git clone https://github.com/cpsievert/plotly-test-table.git -cd plotly-test-table -git checkout gh-pages - -# Read more about Travis environment variables -- -# http://docs.travis-ci.com/user/ci-environment/ -Rscript ../plotly/inst/testscripts/comment.R $TRAVIS_PULL_REQUEST $TRAVIS_BUILD_ID $TRAVIS_COMMIT $GH_TOKEN diff --git a/inst/testscripts/build-push-comment.R b/inst/testscripts/build-push-comment.R new file mode 100644 index 0000000000..035f06a94a --- /dev/null +++ b/inst/testscripts/build-push-comment.R @@ -0,0 +1,111 @@ +# ----------------------------------------------------------------------- +# Travis does two types of builds: +# +# (1) A so-called "push". This essentially does a checkout on the most +# recent commit of the pull request, but *doesn't* merge with master. +# In this case, $TRAVIS_PULL_REQUEST = "false" +# (2) A so-called "pr" (pull request). This *does* merge with master. +# In this case, $TRAVIS_PULL_REQUEST contains the pull request number. +# +# Since it makes more sense to visually compared what we'd see *after* we +# merge with master, we don't do anything here if it's a push build. +# ----------------------------------------------------------------------- + +# Read more about Travis environment variables -- +# http://docs.travis-ci.com/user/ci-environment/#Environment-variables +tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") +if (tpr != "false" && tpr != "") { + library("httr") + # gistr is a good reference for talking to the github API via httr + # https://github.com/ropensci/gistr/blob/master/R/zzz.R + base <- 'https://api.github.com/repos/ropensci/plotly/' + header <- add_headers(`User-Agent` = "plotly", + `Accept` = 'application/vnd.github.v3+json', + `Authorization` = paste0("token ", Sys.getenv("GH_TOKEN"))) + # Grab the branch name for this pull request (must be successful!!) + # http://stackoverflow.com/questions/15096331/github-api-how-to-find-the-branches-of-a-pull-request + pr <- sprintf(paste0(base, 'pulls/%s'), tpr) + res <- GET(url = pr, header) + stop_for_status(res) + info <- content(res) + branch <- strsplit(info$head$label, ":")[[1]][2] + + # Return an abbreviated version of a hash + abbrev_hash <- function(hash = "") substr(hash, 1, 7) + + # Grab HEAD info for each branch (might not be necessary) +# br <- paste0(base, 'branches') +# res <- GET(br) +# stop_for_status(res) +# info <- content(res) +# commits <- sapply(info, "[[", "commit") +# shas <- unlist(commits["sha",]) +# shas <- sapply(shas, abbrev_hash, USE.NAMES = FALSE) +# shas <- setNames(shas, sapply(info, "[[", "name")) + + # NOTE: $TRAVIS_COMMIT doesn't match the HEAD of this (or master) branch!!! + # Remember that we're *simulating* a merge with master, but the hash for the + # *actual* merge will be different. Instead of installing master each time + # we call save_outputs(), we install once here, if necessary, and re-run tests + if (!info$base$sha %in% dir("plotly-test-table/R")) { + devtools::install_github("ropensci/plotly", ref = info$base$sha) + testthat::test_package("plotly") + } + # TODO: Remove plotly-test-table folders that are no longer needed + # by comparing the directories to branch HEADs for plotly. This could + # be hard to do the git rm properly. We could also run tests for missing + # HEAD shas, but that's probably overkill + + # Build the main HTML page for this build + get_png <- function(...) + dir(file.path("plotly-test-table",...), pattern = "\\.png$", full.names = T) + ggpngs <- get_png("ggplot2", packageVersion("ggplot2")) + df <- data.frame(sub("\\.png$", "", basename(ggpngs)), ggpngs, + get_png(commit_hash), get_png(master_hash)) + names(df) <- c("test", "ggplot2", branch, "master") + # TODO: create an HTML page for each test + df$test <- sprintf(' %s ', df$test) + for (i in setdiff(names(df), "test")) + df[, i] <- sprintf(' ', df[, i]) + test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', + quiet = TRUE) + this_hash <- abbrev_hash(Sys.getenv("TRAVIS_COMMIT")) + dest <- file.path("plotly-test-table", "R", this_hash, "index.html") + writeLines(test_table, file = dest) + + # TODO: convert for thumbnails!! (see wch/vtest's convert_png() for alternative) + + # add, commit, push to gh-pages branch of plotly-test-table + system("git add *") + build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', + Sys.getenv("TRAVIS_BUILD_ID")) + commit_msg <- paste0('"Pushed from ', build_link, '"') + system(paste('git commit -m', commit_msg)) + # This post explains how this works -- http://rmflight.github.io/posts/2014/11/travis_ci_gh_pages.html + repo <- sprintf("https://%s@github.com/cpsievert/plotly-test-table.git", Sys.getenv("GH_TOKEN")) + system(paste("git pull -q", repo, "gh-pages")) + system(paste("git push -q", repo, "gh-pages")) + + # post comment if a link to this SHA doesn't exist + # (needed since Travis randomly re-builds stuff) + tbl_link <- sprintf("http://cpsievert.github.io/plotly-test-table/R/%s/index.html", this_hash) + msg <- sprintf("On TravisCI, commit %s was successfully merged with %s (master) to create %s. A visual testing table comparing %s with %s can be found here:\n %s", + info$head$sha, info$base$sha, this_hash, info$base$sha, this_hash, tbl_link) + msg <- paste("> The message below was automatically generated after build", build_link, "\n\n", msg) + commentz <- sprintf(paste0(base, 'issues/%s/comments'), tpr) + res <- GET(commentz, header) + warn_for_status(res) + info <- content(res) + old_body <- unlist(lapply(info, "[", "body")) + if (!any(grepl(tbl_link, old_body))) { + json <- jsonlite::toJSON(list(body = msg), auto_unbox = TRUE) + POST(url = commentz, header, body = json, encode = "json") + } else { + message("Link already posted") + } +} + + +# IDEAS: +# * iframe into json diffs on github??? +# * Github now renders IPython!!! diff --git a/inst/testscripts/comment.R b/inst/testscripts/comment.R deleted file mode 100644 index 6a2e6e9421..0000000000 --- a/inst/testscripts/comment.R +++ /dev/null @@ -1,74 +0,0 @@ -# first argument is the pull request number (TRAVIS_PULL_REQUEST) -# second is travis build ID (TRAVIS_BUILD_ID) -# third is the commit SHA1 currently being tested (TRAVIS_COMMIT) -# fourth is the github authentication token -a <- commandArgs(TRUE) -# gistr is a good reference for talking to the github API via httr -# https://github.com/ropensci/gistr/blob/master/R/zzz.R -library("httr") -base <- 'https://api.github.com/repos/ropensci/plotly/' -pr <- sprintf(paste0(base, 'pulls/%s'), a[1]) -header <- add_headers(`User-Agent` = "plotly", - `Accept` = 'application/vnd.github.v3+json', - `Authorization` = paste0("token ", a[4])) -# Must be successful since we grab the branch name for this pull request -# and SHA1 info from the request content -res <- GET(url = pr, header) -stop_for_status(res) -info <- content(res) -# find the branch name for this pull request -# http://stackoverflow.com/questions/15096331/github-api-how-to-find-the-branches-of-a-pull-request -branch <- strsplit(info$head$label, ":")[[1]][2] - -# plotly-test-table build script assumes we've checkout the dev branch. -# Note that travis does something like this for "pr" build: -#$ git fetch origin +refs/pull/number/merge: -#$ git checkout -qf FETCH_HEAD -# this leaves HEAD in a detached state, but we should be able to do: -# git checkout -b new_branch_name -setwd("../plotly") -if (system(paste("git checkout -b", branch)) != 0L) - stop(paste("Failed to 'git checkout -b'", branch, "branch")) -devtools::install() -setwd("../plotly-test-table") -cat("user,SHA1,label", file = "code_commits.csv") -row1 <- paste0("\nropensci,", info$base$sha, ",master") -cat(row1, file = "code_commits.csv", append = TRUE) -row2 <- paste0("\nropensci,", a[3], ",", branch) -cat(row2, file = "code_commits.csv", append = TRUE) - -# copy over file (created during Rscript) -# with sha/branch info for building test table -system("touch table.R") -if (system("make") != 0L) stop("Failed to 'make' test table") - -# add, commit, push to gh-pages branch of plotly-test-table -system("git add index.html") -system("git add tables/*/*.html") -system("git add data/*/*.png") -system("git add data/*/*.log") -build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', a[2]) -commit_msg <- paste0('"Pushed from ', build_link, '"') -system(paste('git commit -m', commit_msg)) -# This post explains how this works -- http://rmflight.github.io/posts/2014/11/travis_ci_gh_pages.html -repo <- sprintf("https://%s@github.com/cpsievert/plotly-test-table.git", a[4]) -system(paste("git pull -q", repo, "gh-pages")) -system(paste("git push -q", repo, "gh-pages")) - -# post comment if a link to this SHA doesn't exist -# (needed since Travis randomly re-builds stuff) -tbl_link <- sprintf("http://ropensci.github.io/plotly-test-table/tables/%s/index.html", a[3]) -msg <- sprintf("On TravisCI, commit %s was successfully merged with %s (master) to create %s. A visual testing table comparing %s with %s can be found here:\n %s", - info$head$sha, info$base$sha, a[3], info$base$sha, a[3], tbl_link) -msg <- paste("> The message below was automatically generated after build", build_link, "\n\n", msg) -commentz <- sprintf(paste0(base, 'issues/%s/comments'), a[1]) -res <- GET(commentz, header) -warn_for_status(res) -info <- content(res) -old_body <- unlist(lapply(info, "[", "body")) -if (!any(grepl(tbl_link, old_body))) { - json <- jsonlite::toJSON(list(body = msg), auto_unbox = TRUE) - httr::POST(url = commentz, header, body = json, encode = "json") -} else { - message("Link already posted") -} diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R new file mode 100644 index 0000000000..abdf440eaa --- /dev/null +++ b/inst/testscripts/save_outputs.R @@ -0,0 +1,42 @@ +#' @param gg a ggplot object +#' @param name name of the test + +save_outputs <- function(gg, name) { + message(paste("running", name)) + # http://docs.travis-ci.com/user/ci-environment/#Environment-variables + build_dir <- Sys.getenv("TRAVIS_BUILD_DIR") + # only create plotlys if we're on travis + if (build_dir != "") { + table_dir <- file.path(build_dir, "plotly-test-table") + # find the hash of the currently installed plotly package + pkg_info <- devtools::session_info()$packages + src <- subset(pkg_info, package == "plotly")$source + hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) + + # TODO: could speed things up by avoiding two calls to gg2list() + # (this will require tweaking expect_traces()) + p <- plotly(gg, browse = FALSE) + png_url <- paste0(p[["url"]], ".png") + resp <- httr::GET(png_url) + # print the response if it wasn't successful + if (httr::warn_for_status(resp)) resp + # write png version of plotly figure to disk + dest <- file.path(table_dir, hash, paste0(name, ".png")) + writeBin(content(resp, as = "raw"), dest) + + # if we don't have the results for this version (of ggplot2), save them + ggversion <- packageVersion("ggplot2") + gg_dir <- file.path(table_dir, "ggplot2") + if (!ggversion %in% dir(gg_dir)) { + dest <- file.path(table_dir, "ggplot2", ggversion) + ggsave(filename = paste0(name, ".png"), plot = gg, path = dest) + } + } + invisible(NULL) +} + +# NOTE: I'm assumming Travis is installing most recent ggplot2 off CRAN +# Here is one way to get current ggplot2 version off of CRAN if need be +# gg <- rvest::html("http://cran.r-project.org/web/packages/ggplot2/") +# tab <- rvest::html_table(gg, header = FALSE)[[1]] +# ggversion <- tab[grepl("Version:", tab[, 1]), 2] diff --git a/tests/testthat.R b/tests/testthat.R index c5273050e9..5753698fe1 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,5 +1,7 @@ library(testthat) -save_outputs <- function(gg, name, ignore_ggplot=FALSE) { - print(paste("running", name)) -} +library(plotly) +# crendentials for the test bot +Sys.setenv(`plotly-username` = "TestBot") +Sys.setenv(`plotly-apikey` = "r1neazxo9w") +source(system.file("testscripts/save_outputs.R", package = "plotly")) test_check("plotly") From 16678635c5791e45e6e9140308861b3bc80a7452 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Fri, 8 May 2015 23:26:51 -0500 Subject: [PATCH 10/48] clone into parent directory --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b822564fac..ad1270d17e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,7 @@ r_packages: before_script: - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - - cd .. - - git clone https://github.com/cpsievert/plotly-test-table.git + - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table after_success: - cd .. From 6b35854ccadfd13ed8d693accd84118862b58739 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Fri, 8 May 2015 23:44:56 -0500 Subject: [PATCH 11/48] Install devtools --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ad1270d17e..10b9909675 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ r_packages: - lattice - xtable - httr + - devtools before_script: - git config --global user.name "cpsievert" From e4c5a37b298eb15245a6a76014bf5357017e5161 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Fri, 8 May 2015 23:45:49 -0500 Subject: [PATCH 12/48] option to ignore ggplot2 errors --- inst/testscripts/save_outputs.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index abdf440eaa..98a540d389 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -1,8 +1,9 @@ #' @param gg a ggplot object #' @param name name of the test +#' @param ignore ignore ggplot2 errors? -save_outputs <- function(gg, name) { - message(paste("running", name)) +save_outputs <- function(gg, name, ignore = FALSE) { + # message(paste("running", name)) # http://docs.travis-ci.com/user/ci-environment/#Environment-variables build_dir <- Sys.getenv("TRAVIS_BUILD_DIR") # only create plotlys if we're on travis @@ -27,7 +28,7 @@ save_outputs <- function(gg, name) { # if we don't have the results for this version (of ggplot2), save them ggversion <- packageVersion("ggplot2") gg_dir <- file.path(table_dir, "ggplot2") - if (!ggversion %in% dir(gg_dir)) { + if (!ggversion %in% dir(gg_dir) && !ignore) { dest <- file.path(table_dir, "ggplot2", ggversion) ggsave(filename = paste0(name, ".png"), plot = gg, path = dest) } From 564b63b287c4f246dd53910242566d298d2f9c0c Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 00:12:37 -0500 Subject: [PATCH 13/48] Maybe error is related to R_TESTS variable weirdness? --- .travis.yml | 1 - tests/testthat.R | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 10b9909675..ad1270d17e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ r_packages: - lattice - xtable - httr - - devtools before_script: - git config --global user.name "cpsievert" diff --git a/tests/testthat.R b/tests/testthat.R index 5753698fe1..28a217fb78 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,7 +1,11 @@ -library(testthat) -library(plotly) +library("testthat") +library("plotly") +library("devtools") # crendentials for the test bot Sys.setenv(`plotly-username` = "TestBot") Sys.setenv(`plotly-apikey` = "r1neazxo9w") source(system.file("testscripts/save_outputs.R", package = "plotly")) +# avoid weird errors if this function is called via testhat::check() +# https://github.com/hadley/testthat/issues/144 +Sys.setenv("R_TESTS" = "") test_check("plotly") From 8366fbdecdc93c7f8c87ee5633eaa68ccf406fcf Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 00:23:37 -0500 Subject: [PATCH 14/48] Add basic print methods; dontrun API examples; suggest devtools --- DESCRIPTION | 3 ++- R/plotly.R | 52 ++++++++++++++++++++++++++++++---------------- man/get_figure.Rd | 10 +++++---- man/plotly_POST.Rd | 12 ++++++----- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5797a3e571..ef2732324c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -35,4 +35,5 @@ Imports: Suggests: maps, testthat, - knitr + knitr, + devtools diff --git a/R/plotly.R b/R/plotly.R index 00585e878e..49f9c48b47 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -28,15 +28,16 @@ signup <- function(username, email, save = TRUE) { resp <- httr::POST(base_url, body = bod) stop_for_status(resp) con <- RJSONIO::fromJSON(content(resp, as = "text")) - # TODO: alter the API response messages to reflect the changes in 1.0.0 if (nchar(con[["error"]]) > 0) stop(con[["error"]], call. = FALSE) - if (nchar(con[["message"]]) > 0) message(con[["message"]], call. = FALSE) - # store API key as an environment variable in .Rprofile + # Relaying a message with a private key probably isn't a great idea -- + # https://github.com/ropensci/plotly/pull/217#issuecomment-100381166 + # if (nchar(con[["message"]]) > 0) message(con[["message"]], call. = FALSE) if (save) { + # store API key as an environment variable in .Rprofile cat_profile("username", con[["un"]]) cat_profile("apikey", con[["api_key"]]) } - structure(con, class = "apimkacct") + invisible(structure(con, class = "apimkacct")) } #' Create, modify and style plotly graphs from R @@ -123,13 +124,14 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { #' @return An R object created by mapping the JSON content of the plotly API #' response to its R equivalent. This object has a class of "clientresp" #' @examples +#' \dontrun{ +#' args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) +#' resp <- plotly_POST(args) #' -#' args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) -#' resp <- plotly_POST(args) -#' -#' # translate a ggplot object with gg2list(), then upload to plotly -#' p <- gg2list(qplot(1:10)) -#' resp <- plotly_POST(p$data, list(layout = p$layout)) +#' # translate a ggplot object with gg2list(), then upload to plotly +#' p <- gg2list(qplot(1:10)) +#' resp <- plotly_POST(p$data, list(layout = p$layout)) +#' } #' plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt = "new"), origin = "plot", ...) { @@ -157,7 +159,12 @@ plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt if (nchar(con[["error"]]) > 0) stop(con[["error"]], call. = FALSE) if (nchar(con[["warning"]]) > 0) warning(con[["warning"]], call. = FALSE) if (nchar(con[["message"]]) > 0) message(con[["message"]], call. = FALSE) - structure(con, class = "clientresp") + invisible(structure(con, class = "clientresp")) +} + +# Print method for a client response +print.clientresp <- function(p) { + cat(" Filename: ", p[["filename"]], "\n", "URL:", p[["url"]]) } #' Request data/layout for a particular Plotly figure @@ -166,16 +173,25 @@ plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt #' @export #' @references https://plot.ly/rest/ #' @examples -#' -#' # https://plot.ly/~TestBot/100 -#' resp <- get_figure("TestBot", "100") -#' names(resp[["layout"]]) -#' names(resp[["data"]]) +#' \dontrun{ +#' # https://plot.ly/~TestBot/100 +#' resp <- get_figure("TestBot", "100") +#' names(resp[["layout"]]) +#' names(resp[["data"]]) +#' } get_figure <- function(username, id) { - base_url <- file.path("https://plot.ly/apigetfile", username, id) + if (missing(username)) username <- verify("username") + if (missing(id)) stop("Must provide a figure id.") + base_url <- file.path(get_domain(), "apigetfile", username, id) resp <- httr::GET(base_url, plotly_headers()) stop_for_status(resp) - RJSONIO::fromJSON(content(resp, as = "text"))[["payload"]][["figure"]] + fig <- RJSONIO::fromJSON(content(resp, as = "text"))[["payload"]][["figure"]] + invisible(structure(fig, class = "apigetfile")) +} + +# TODO: smarter print method! (we don't want to print ugly lists) +print.apigetfile <- function(p) { + NextMethod("print") } #' Embed a plotly iframe into an R markdown document via \code{knit_print} diff --git a/man/get_figure.Rd b/man/get_figure.Rd index 9056c4e47f..0bc1c007ae 100644 --- a/man/get_figure.Rd +++ b/man/get_figure.Rd @@ -15,10 +15,12 @@ get_figure(username, id) Request data/layout for a particular Plotly figure } \examples{ -# https://plot.ly/~TestBot/100 -resp <- get_figure("TestBot", "100") -names(resp[["layout"]]) -names(resp[["data"]]) +\dontrun{ + # https://plot.ly/~TestBot/100 + resp <- get_figure("TestBot", "100") + names(resp[["layout"]]) + names(resp[["data"]]) +} } \references{ https://plot.ly/rest/ diff --git a/man/plotly_POST.Rd b/man/plotly_POST.Rd index 9441316a7e..57cca7f3e4 100644 --- a/man/plotly_POST.Rd +++ b/man/plotly_POST.Rd @@ -25,12 +25,14 @@ POST messages to the clientresp resource of plotly's REST API. Unlike \link{plot this function does not support ggplot objects. } \examples{ -args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) -resp <- plotly_POST(args) +\dontrun{ + args <- list(c(0, 1, 2), c(3, 4, 5), c(1, 2, 3), c(6, 6, 5)) + resp <- plotly_POST(args) -# translate a ggplot object with gg2list(), then upload to plotly -p <- gg2list(qplot(1:10)) -resp <- plotly_POST(p$data, list(layout = p$layout)) + # translate a ggplot object with gg2list(), then upload to plotly + p <- gg2list(qplot(1:10)) + resp <- plotly_POST(p$data, list(layout = p$layout)) +} } \references{ https://plot.ly/rest/ From 4779a271db80fdbb678a1669605ef4fc5ed804ee Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 00:42:20 -0500 Subject: [PATCH 15/48] Fix httr:: namespace issue --- inst/testscripts/save_outputs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 98a540d389..e77d752e55 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -23,7 +23,7 @@ save_outputs <- function(gg, name, ignore = FALSE) { if (httr::warn_for_status(resp)) resp # write png version of plotly figure to disk dest <- file.path(table_dir, hash, paste0(name, ".png")) - writeBin(content(resp, as = "raw"), dest) + writeBin(httr::content(resp, as = "raw"), dest) # if we don't have the results for this version (of ggplot2), save them ggversion <- packageVersion("ggplot2") From cb6e10419def08c76778ba946b0a81bf57c26a39 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 00:43:32 -0500 Subject: [PATCH 16/48] if you use a package in tests, you _must_ put in DESCRIPTION now --- tests/testthat.R | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/testthat.R b/tests/testthat.R index 28a217fb78..b81f43af9b 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,11 +1,7 @@ library("testthat") library("plotly") -library("devtools") # crendentials for the test bot Sys.setenv(`plotly-username` = "TestBot") Sys.setenv(`plotly-apikey` = "r1neazxo9w") source(system.file("testscripts/save_outputs.R", package = "plotly")) -# avoid weird errors if this function is called via testhat::check() -# https://github.com/hadley/testthat/issues/144 -Sys.setenv("R_TESTS" = "") test_check("plotly") From 9011e727fa57b63ffdfce7733adce4ca381e1eda Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 01:02:30 -0500 Subject: [PATCH 17/48] Create dir if not exists --- inst/testscripts/save_outputs.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index e77d752e55..6303b05487 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -13,6 +13,9 @@ save_outputs <- function(gg, name, ignore = FALSE) { pkg_info <- devtools::session_info()$packages src <- subset(pkg_info, package == "plotly")$source hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) + hash_dir <- file.path(table_dir, "R", hash) + # create a directory for this hash if necessary + if (!dir.exists(hash_dir)) dir.create(hash_dur, recursive = TRUE) # TODO: could speed things up by avoiding two calls to gg2list() # (this will require tweaking expect_traces()) @@ -22,7 +25,7 @@ save_outputs <- function(gg, name, ignore = FALSE) { # print the response if it wasn't successful if (httr::warn_for_status(resp)) resp # write png version of plotly figure to disk - dest <- file.path(table_dir, hash, paste0(name, ".png")) + dest <- file.path(hash_dir, paste0(name, ".png")) writeBin(httr::content(resp, as = "raw"), dest) # if we don't have the results for this version (of ggplot2), save them From 7aa37af668e3d25d53e9fab341ba7d609d9cd384 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 01:14:27 -0500 Subject: [PATCH 18/48] typo --- inst/testscripts/save_outputs.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 6303b05487..fee4827ced 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -15,7 +15,7 @@ save_outputs <- function(gg, name, ignore = FALSE) { hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) hash_dir <- file.path(table_dir, "R", hash) # create a directory for this hash if necessary - if (!dir.exists(hash_dir)) dir.create(hash_dur, recursive = TRUE) + if (!dir.exists(hash_dir)) dir.create(hash_dir, recursive = TRUE) # TODO: could speed things up by avoiding two calls to gg2list() # (this will require tweaking expect_traces()) From dfaf4bd0ff7acac47352f99cacec035fbb6a8d33 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 01:39:50 -0500 Subject: [PATCH 19/48] ggsave() seems to be broken --- inst/testscripts/save_outputs.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index fee4827ced..5aa14999b4 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -32,8 +32,10 @@ save_outputs <- function(gg, name, ignore = FALSE) { ggversion <- packageVersion("ggplot2") gg_dir <- file.path(table_dir, "ggplot2") if (!ggversion %in% dir(gg_dir) && !ignore) { - dest <- file.path(table_dir, "ggplot2", ggversion) - ggsave(filename = paste0(name, ".png"), plot = gg, path = dest) + dest <- file.path(table_dir, "ggplot2", ggversion, paste0(name, ".png")) + png(filename = dest) + gg + dev.off() } } invisible(NULL) From 1aec96846e90aeddc0ba45ea60858024790cd576 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 02:00:08 -0500 Subject: [PATCH 20/48] only save outputs for travis pull requests --- inst/testscripts/save_outputs.R | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 5aa14999b4..1599c2e1fc 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -3,12 +3,11 @@ #' @param ignore ignore ggplot2 errors? save_outputs <- function(gg, name, ignore = FALSE) { - # message(paste("running", name)) - # http://docs.travis-ci.com/user/ci-environment/#Environment-variables - build_dir <- Sys.getenv("TRAVIS_BUILD_DIR") - # only create plotlys if we're on travis - if (build_dir != "") { - table_dir <- file.path(build_dir, "plotly-test-table") + # only render/save plotly pngs if this is a Travis pull request + # (see build-comment-push.R for better explanation of why) + tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") + if (tpr != "false" && tpr != "") { + table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") # find the hash of the currently installed plotly package pkg_info <- devtools::session_info()$packages src <- subset(pkg_info, package == "plotly")$source From b6fb06c41699b19b15a2f49d6f023ec24f96f327 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 14:31:54 -0500 Subject: [PATCH 21/48] R CMD check suppress output; so we have to keep tests under 10 minutes --- inst/testscripts/build-push-comment.R | 37 ++++++++++++++------- inst/testscripts/save_outputs.R | 47 +++++++++++++-------------- tests/testthat.R | 6 ++++ 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/inst/testscripts/build-push-comment.R b/inst/testscripts/build-push-comment.R index 035f06a94a..5b465dd741 100644 --- a/inst/testscripts/build-push-comment.R +++ b/inst/testscripts/build-push-comment.R @@ -16,6 +16,7 @@ tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") if (tpr != "false" && tpr != "") { library("httr") + library("testthat") # gistr is a good reference for talking to the github API via httr # https://github.com/ropensci/gistr/blob/master/R/zzz.R base <- 'https://api.github.com/repos/ropensci/plotly/' @@ -33,7 +34,7 @@ if (tpr != "false" && tpr != "") { # Return an abbreviated version of a hash abbrev_hash <- function(hash = "") substr(hash, 1, 7) - # Grab HEAD info for each branch (might not be necessary) + # Grab HEAD info for each branch (this might not be necessary) # br <- paste0(base, 'branches') # res <- GET(br) # stop_for_status(res) @@ -47,21 +48,32 @@ if (tpr != "false" && tpr != "") { # Remember that we're *simulating* a merge with master, but the hash for the # *actual* merge will be different. Instead of installing master each time # we call save_outputs(), we install once here, if necessary, and re-run tests - if (!info$base$sha %in% dir("plotly-test-table/R")) { - devtools::install_github("ropensci/plotly", ref = info$base$sha) - testthat::test_package("plotly") + this_hash <- abbrev_hash(Sys.getenv("TRAVIS_COMMIT")) + base_hash <- abbrev_hash(info$base$sha) + head_hash <- abbrev_hash(info$head$sha) + test_rerun <- function(hash) { + if (!hash %in% dir("plotly-test-table/R")) { + devtools::install_github("ropensci/plotly", ref = hash) + testthat::test_package("plotly") + } } + test_rerun(this_hash) + test_rerun(base_hash) + # TODO: Remove plotly-test-table folders that are no longer needed # by comparing the directories to branch HEADs for plotly. This could # be hard to do the git rm properly. We could also run tests for missing # HEAD shas, but that's probably overkill + # list png files in a particular directory + pngs <- function(...) { + dir(file.path("plotly-test-table", "R", ...), + pattern = "\\.png$", full.names = T) + } # Build the main HTML page for this build - get_png <- function(...) - dir(file.path("plotly-test-table",...), pattern = "\\.png$", full.names = T) - ggpngs <- get_png("ggplot2", packageVersion("ggplot2")) - df <- data.frame(sub("\\.png$", "", basename(ggpngs)), ggpngs, - get_png(commit_hash), get_png(master_hash)) + ggpngs <- pngs("ggplot2", packageVersion("ggplot2")) + df <- data.frame(sub("\\.png$", "", basename(ggpngs)), + ggpngs, pngs(this_hash), pngs(base_hash)) names(df) <- c("test", "ggplot2", branch, "master") # TODO: create an HTML page for each test df$test <- sprintf(' %s ', df$test) @@ -69,11 +81,12 @@ if (tpr != "false" && tpr != "") { df[, i] <- sprintf(' ', df[, i]) test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', quiet = TRUE) - this_hash <- abbrev_hash(Sys.getenv("TRAVIS_COMMIT")) dest <- file.path("plotly-test-table", "R", this_hash, "index.html") writeLines(test_table, file = dest) - # TODO: convert for thumbnails!! (see wch/vtest's convert_png() for alternative) + # TODO: + # * convert for thumbnails!! (see wch/vtest's convert_png() for alternative) + # * create home page for R with commmit info -- https://developer.github.com/v3/git/commits/ # add, commit, push to gh-pages branch of plotly-test-table system("git add *") @@ -90,7 +103,7 @@ if (tpr != "false" && tpr != "") { # (needed since Travis randomly re-builds stuff) tbl_link <- sprintf("http://cpsievert.github.io/plotly-test-table/R/%s/index.html", this_hash) msg <- sprintf("On TravisCI, commit %s was successfully merged with %s (master) to create %s. A visual testing table comparing %s with %s can be found here:\n %s", - info$head$sha, info$base$sha, this_hash, info$base$sha, this_hash, tbl_link) + head_hash, base_hash, this_hash, base_hash, this_hash, tbl_link) msg <- paste("> The message below was automatically generated after build", build_link, "\n\n", msg) commentz <- sprintf(paste0(base, 'issues/%s/comments'), tpr) res <- GET(commentz, header) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 1599c2e1fc..89d4abd363 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -3,38 +3,37 @@ #' @param ignore ignore ggplot2 errors? save_outputs <- function(gg, name, ignore = FALSE) { - # only render/save plotly pngs if this is a Travis pull request - # (see build-comment-push.R for better explanation of why) + # only render/save pngs if this is a Travis pull request + # (see build-comment-push.R for better explanation of this logic) tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") if (tpr != "false" && tpr != "") { table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") - # find the hash of the currently installed plotly package - pkg_info <- devtools::session_info()$packages - src <- subset(pkg_info, package == "plotly")$source - hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) - hash_dir <- file.path(table_dir, "R", hash) - # create a directory for this hash if necessary - if (!dir.exists(hash_dir)) dir.create(hash_dir, recursive = TRUE) + # this environment variable should be set by testthat.R + plotly_dir <- file.path(table_dir, "R", Sys.getenv("plotly-hash")) + gg_dir <- file.path(table_dir, "R", "ggplot2") - # TODO: could speed things up by avoiding two calls to gg2list() - # (this will require tweaking expect_traces()) - p <- plotly(gg, browse = FALSE) - png_url <- paste0(p[["url"]], ".png") - resp <- httr::GET(png_url) - # print the response if it wasn't successful - if (httr::warn_for_status(resp)) resp - # write png version of plotly figure to disk - dest <- file.path(hash_dir, paste0(name, ".png")) - writeBin(httr::content(resp, as = "raw"), dest) - - # if we don't have the results for this version (of ggplot2), save them - ggversion <- packageVersion("ggplot2") - gg_dir <- file.path(table_dir, "ggplot2") + # If we don't have pngs for this version (of ggplot2), generate them; + # otherwise, generate plotly pngs + # NOTE: we can't save both plotly & ggplot2 at once since R CMD check + # suppresses output and travis has 10 minute time limit + # https://github.com/travis-ci/travis-ci/issues/3849 + ggversion <- as.character(packageVersion("ggplot2")) if (!ggversion %in% dir(gg_dir) && !ignore) { - dest <- file.path(table_dir, "ggplot2", ggversion, paste0(name, ".png")) + dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) png(filename = dest) gg dev.off() + } else { + # TODO: could speed things up by avoiding two calls to gg2list() + # (this will require tweaking expect_traces()) + p <- plotly(gg, browse = FALSE) + png_url <- paste0(p[["url"]], ".png") + resp <- httr::GET(png_url) + # print the response if it wasn't successful + if (httr::warn_for_status(resp)) resp + # write png version of plotly figure to disk + writeBin(httr::content(resp, as = "raw"), + file.path(plotly_dir, paste0(name, ".png"))) } } invisible(NULL) diff --git a/tests/testthat.R b/tests/testthat.R index b81f43af9b..d38c48e97a 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -3,5 +3,11 @@ library("plotly") # crendentials for the test bot Sys.setenv(`plotly-username` = "TestBot") Sys.setenv(`plotly-apikey` = "r1neazxo9w") +# find the hash of the currently installed plotly package +pkg_info <- devtools::session_info()$packages +src <- subset(pkg_info, package == "plotly")$source +hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) +# placement of outputs depend on this hash +Sys.setenv(`plotly-hash` = hash) source(system.file("testscripts/save_outputs.R", package = "plotly")) test_check("plotly") From c7fc7fd55a9051c4fb9c05e0f9c68fa761c7848c Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 15:15:39 -0500 Subject: [PATCH 22/48] Create directories if necessary; ggplot2 error handling --- inst/testscripts/save_outputs.R | 10 ++++++---- tests/testthat/test-ggplot-step.R | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 89d4abd363..1cb3b282b3 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -1,8 +1,7 @@ #' @param gg a ggplot object #' @param name name of the test -#' @param ignore ignore ggplot2 errors? -save_outputs <- function(gg, name, ignore = FALSE) { +save_outputs <- function(gg, name) { # only render/save pngs if this is a Travis pull request # (see build-comment-push.R for better explanation of this logic) tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") @@ -11,6 +10,8 @@ save_outputs <- function(gg, name, ignore = FALSE) { # this environment variable should be set by testthat.R plotly_dir <- file.path(table_dir, "R", Sys.getenv("plotly-hash")) gg_dir <- file.path(table_dir, "R", "ggplot2") + if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) + if (!dir.exists(gg_dir)) dir.create(gg_dir, recursive = TRUE) # If we don't have pngs for this version (of ggplot2), generate them; # otherwise, generate plotly pngs @@ -18,10 +19,11 @@ save_outputs <- function(gg, name, ignore = FALSE) { # suppresses output and travis has 10 minute time limit # https://github.com/travis-ci/travis-ci/issues/3849 ggversion <- as.character(packageVersion("ggplot2")) - if (!ggversion %in% dir(gg_dir) && !ignore) { + if (!ggversion %in% dir(gg_dir)) { dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) + e <- try(gg, silent = TRUE) png(filename = dest) - gg + if (inherits(e, "try-error")) plot(1, type="n"); text(1, "ggplot2 error") else gg dev.off() } else { # TODO: could speed things up by avoiding two calls to gg2list() diff --git a/tests/testthat/test-ggplot-step.R b/tests/testthat/test-ggplot-step.R index 0aa8bb837d..1712405ef5 100644 --- a/tests/testthat/test-ggplot-step.R +++ b/tests/testthat/test-ggplot-step.R @@ -49,7 +49,7 @@ test_that("direction hvh is translated to shape=hvh", { expect_equal(length(L$data), 2) expect_identical(L$data[[1]]$line$shape, "hvh") - save_outputs(gg.hvh, "step-gg.hvh", TRUE) + save_outputs(gg.hvh, "step-gg.hvh") }) test_that("direction vhv is translated to shape=vhv", { @@ -58,5 +58,5 @@ test_that("direction vhv is translated to shape=vhv", { expect_equal(length(L$data), 2) expect_identical(L$data[[1]]$line$shape, "vhv") - save_outputs(gg.vhv, "step-gg.vhv", TRUE) + save_outputs(gg.vhv, "step-gg.vhv") }) From 1ba6857b537e6432cdb6099c1c6a4b661f3ea173 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sat, 9 May 2015 16:15:51 -0500 Subject: [PATCH 23/48] derp --- inst/testscripts/save_outputs.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R index 1cb3b282b3..b9eddd6318 100644 --- a/inst/testscripts/save_outputs.R +++ b/inst/testscripts/save_outputs.R @@ -23,7 +23,10 @@ save_outputs <- function(gg, name) { dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) e <- try(gg, silent = TRUE) png(filename = dest) - if (inherits(e, "try-error")) plot(1, type="n"); text(1, "ggplot2 error") else gg + if (inherits(e, "try-error")) { + plot(1, type="n") + text(1, "ggplot2 error") + } else gg dev.off() } else { # TODO: could speed things up by avoiding two calls to gg2list() From 61b180ef03511efc304edbae3db4277e0ca52cdc Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sun, 10 May 2015 19:49:25 -0500 Subject: [PATCH 24/48] Define save_outputs() in testthat.R; place build-push-comment.R under tests/ --- inst/testscripts/build-push-comment.R | 124 -------------------------- inst/testscripts/save_outputs.R | 51 ----------- tests/testthat.R | 54 ++++++++++- 3 files changed, 51 insertions(+), 178 deletions(-) delete mode 100644 inst/testscripts/build-push-comment.R delete mode 100644 inst/testscripts/save_outputs.R diff --git a/inst/testscripts/build-push-comment.R b/inst/testscripts/build-push-comment.R deleted file mode 100644 index 5b465dd741..0000000000 --- a/inst/testscripts/build-push-comment.R +++ /dev/null @@ -1,124 +0,0 @@ -# ----------------------------------------------------------------------- -# Travis does two types of builds: -# -# (1) A so-called "push". This essentially does a checkout on the most -# recent commit of the pull request, but *doesn't* merge with master. -# In this case, $TRAVIS_PULL_REQUEST = "false" -# (2) A so-called "pr" (pull request). This *does* merge with master. -# In this case, $TRAVIS_PULL_REQUEST contains the pull request number. -# -# Since it makes more sense to visually compared what we'd see *after* we -# merge with master, we don't do anything here if it's a push build. -# ----------------------------------------------------------------------- - -# Read more about Travis environment variables -- -# http://docs.travis-ci.com/user/ci-environment/#Environment-variables -tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") -if (tpr != "false" && tpr != "") { - library("httr") - library("testthat") - # gistr is a good reference for talking to the github API via httr - # https://github.com/ropensci/gistr/blob/master/R/zzz.R - base <- 'https://api.github.com/repos/ropensci/plotly/' - header <- add_headers(`User-Agent` = "plotly", - `Accept` = 'application/vnd.github.v3+json', - `Authorization` = paste0("token ", Sys.getenv("GH_TOKEN"))) - # Grab the branch name for this pull request (must be successful!!) - # http://stackoverflow.com/questions/15096331/github-api-how-to-find-the-branches-of-a-pull-request - pr <- sprintf(paste0(base, 'pulls/%s'), tpr) - res <- GET(url = pr, header) - stop_for_status(res) - info <- content(res) - branch <- strsplit(info$head$label, ":")[[1]][2] - - # Return an abbreviated version of a hash - abbrev_hash <- function(hash = "") substr(hash, 1, 7) - - # Grab HEAD info for each branch (this might not be necessary) -# br <- paste0(base, 'branches') -# res <- GET(br) -# stop_for_status(res) -# info <- content(res) -# commits <- sapply(info, "[[", "commit") -# shas <- unlist(commits["sha",]) -# shas <- sapply(shas, abbrev_hash, USE.NAMES = FALSE) -# shas <- setNames(shas, sapply(info, "[[", "name")) - - # NOTE: $TRAVIS_COMMIT doesn't match the HEAD of this (or master) branch!!! - # Remember that we're *simulating* a merge with master, but the hash for the - # *actual* merge will be different. Instead of installing master each time - # we call save_outputs(), we install once here, if necessary, and re-run tests - this_hash <- abbrev_hash(Sys.getenv("TRAVIS_COMMIT")) - base_hash <- abbrev_hash(info$base$sha) - head_hash <- abbrev_hash(info$head$sha) - test_rerun <- function(hash) { - if (!hash %in% dir("plotly-test-table/R")) { - devtools::install_github("ropensci/plotly", ref = hash) - testthat::test_package("plotly") - } - } - test_rerun(this_hash) - test_rerun(base_hash) - - # TODO: Remove plotly-test-table folders that are no longer needed - # by comparing the directories to branch HEADs for plotly. This could - # be hard to do the git rm properly. We could also run tests for missing - # HEAD shas, but that's probably overkill - - # list png files in a particular directory - pngs <- function(...) { - dir(file.path("plotly-test-table", "R", ...), - pattern = "\\.png$", full.names = T) - } - # Build the main HTML page for this build - ggpngs <- pngs("ggplot2", packageVersion("ggplot2")) - df <- data.frame(sub("\\.png$", "", basename(ggpngs)), - ggpngs, pngs(this_hash), pngs(base_hash)) - names(df) <- c("test", "ggplot2", branch, "master") - # TODO: create an HTML page for each test - df$test <- sprintf(' %s ', df$test) - for (i in setdiff(names(df), "test")) - df[, i] <- sprintf(' ', df[, i]) - test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', - quiet = TRUE) - dest <- file.path("plotly-test-table", "R", this_hash, "index.html") - writeLines(test_table, file = dest) - - # TODO: - # * convert for thumbnails!! (see wch/vtest's convert_png() for alternative) - # * create home page for R with commmit info -- https://developer.github.com/v3/git/commits/ - - # add, commit, push to gh-pages branch of plotly-test-table - system("git add *") - build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', - Sys.getenv("TRAVIS_BUILD_ID")) - commit_msg <- paste0('"Pushed from ', build_link, '"') - system(paste('git commit -m', commit_msg)) - # This post explains how this works -- http://rmflight.github.io/posts/2014/11/travis_ci_gh_pages.html - repo <- sprintf("https://%s@github.com/cpsievert/plotly-test-table.git", Sys.getenv("GH_TOKEN")) - system(paste("git pull -q", repo, "gh-pages")) - system(paste("git push -q", repo, "gh-pages")) - - # post comment if a link to this SHA doesn't exist - # (needed since Travis randomly re-builds stuff) - tbl_link <- sprintf("http://cpsievert.github.io/plotly-test-table/R/%s/index.html", this_hash) - msg <- sprintf("On TravisCI, commit %s was successfully merged with %s (master) to create %s. A visual testing table comparing %s with %s can be found here:\n %s", - head_hash, base_hash, this_hash, base_hash, this_hash, tbl_link) - msg <- paste("> The message below was automatically generated after build", build_link, "\n\n", msg) - commentz <- sprintf(paste0(base, 'issues/%s/comments'), tpr) - res <- GET(commentz, header) - warn_for_status(res) - info <- content(res) - old_body <- unlist(lapply(info, "[", "body")) - if (!any(grepl(tbl_link, old_body))) { - json <- jsonlite::toJSON(list(body = msg), auto_unbox = TRUE) - POST(url = commentz, header, body = json, encode = "json") - } else { - message("Link already posted") - } -} - - -# IDEAS: -# * iframe into json diffs on github??? -# * Github now renders IPython!!! diff --git a/inst/testscripts/save_outputs.R b/inst/testscripts/save_outputs.R deleted file mode 100644 index b9eddd6318..0000000000 --- a/inst/testscripts/save_outputs.R +++ /dev/null @@ -1,51 +0,0 @@ -#' @param gg a ggplot object -#' @param name name of the test - -save_outputs <- function(gg, name) { - # only render/save pngs if this is a Travis pull request - # (see build-comment-push.R for better explanation of this logic) - tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") - if (tpr != "false" && tpr != "") { - table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") - # this environment variable should be set by testthat.R - plotly_dir <- file.path(table_dir, "R", Sys.getenv("plotly-hash")) - gg_dir <- file.path(table_dir, "R", "ggplot2") - if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) - if (!dir.exists(gg_dir)) dir.create(gg_dir, recursive = TRUE) - - # If we don't have pngs for this version (of ggplot2), generate them; - # otherwise, generate plotly pngs - # NOTE: we can't save both plotly & ggplot2 at once since R CMD check - # suppresses output and travis has 10 minute time limit - # https://github.com/travis-ci/travis-ci/issues/3849 - ggversion <- as.character(packageVersion("ggplot2")) - if (!ggversion %in% dir(gg_dir)) { - dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) - e <- try(gg, silent = TRUE) - png(filename = dest) - if (inherits(e, "try-error")) { - plot(1, type="n") - text(1, "ggplot2 error") - } else gg - dev.off() - } else { - # TODO: could speed things up by avoiding two calls to gg2list() - # (this will require tweaking expect_traces()) - p <- plotly(gg, browse = FALSE) - png_url <- paste0(p[["url"]], ".png") - resp <- httr::GET(png_url) - # print the response if it wasn't successful - if (httr::warn_for_status(resp)) resp - # write png version of plotly figure to disk - writeBin(httr::content(resp, as = "raw"), - file.path(plotly_dir, paste0(name, ".png"))) - } - } - invisible(NULL) -} - -# NOTE: I'm assumming Travis is installing most recent ggplot2 off CRAN -# Here is one way to get current ggplot2 version off of CRAN if need be -# gg <- rvest::html("http://cran.r-project.org/web/packages/ggplot2/") -# tab <- rvest::html_table(gg, header = FALSE)[[1]] -# ggversion <- tab[grepl("Version:", tab[, 1]), 2] diff --git a/tests/testthat.R b/tests/testthat.R index d38c48e97a..642660614a 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -7,7 +7,55 @@ Sys.setenv(`plotly-apikey` = "r1neazxo9w") pkg_info <- devtools::session_info()$packages src <- subset(pkg_info, package == "plotly")$source hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) -# placement of outputs depend on this hash -Sys.setenv(`plotly-hash` = hash) -source(system.file("testscripts/save_outputs.R", package = "plotly")) + +save_outputs <- function(gg, name) { + # only render/save pngs if this is a Travis pull request + # (see build-comment-push.R for better explanation of this logic) + tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") + if (tpr != "false" && tpr != "") { + table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") + # this environment variable should be set by testthat.R + plotly_dir <- file.path(table_dir, "R", hash) + gg_dir <- file.path(table_dir, "R", "ggplot2") + if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) + if (!dir.exists(gg_dir)) dir.create(gg_dir, recursive = TRUE) + + # If we don't have pngs for this version (of ggplot2), generate them; + # otherwise, generate plotly pngs + # NOTE: we can't save both plotly & ggplot2 at once since R CMD check + # suppresses output and travis has 10 minute time limit + # https://github.com/travis-ci/travis-ci/issues/3849 + ggversion <- as.character(packageVersion("ggplot2")) + if (!ggversion %in% dir(gg_dir)) { + dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) + e <- try(gg, silent = TRUE) + png(filename = dest) + if (inherits(e, "try-error")) { + plot(1, type="n") + text(1, "ggplot2 error") + } else gg + dev.off() + } else { + # TODO: could speed things up by avoiding two calls to gg2list() + # (this will require tweaking expect_traces()) + p <- plotly(gg, browse = FALSE) + png_url <- paste0(p[["url"]], ".png") + resp <- httr::GET(png_url) + # print the response if it wasn't successful + if (httr::warn_for_status(resp)) resp + # write png version of plotly figure to disk + writeBin(httr::content(resp, as = "raw"), + file.path(plotly_dir, paste0(name, ".png"))) + } + } + invisible(NULL) +} + test_check("plotly") + + +# NOTE: I'm assumming Travis is installing most recent ggplot2 off CRAN +# Here is one way to get current ggplot2 version off of CRAN if need be +# gg <- rvest::html("http://cran.r-project.org/web/packages/ggplot2/") +# tab <- rvest::html_table(gg, header = FALSE)[[1]] +# ggversion <- tab[grepl("Version:", tab[, 1]), 2] From d13e61db14d23d2f83efbbfd03d68d18607319be Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sun, 10 May 2015 19:57:16 -0500 Subject: [PATCH 25/48] updates in .travis.yml accordingly --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ad1270d17e..630a150aee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ before_script: after_success: - cd .. - - Rscript plotly/inst/testscripts/build-push-comment.R + - Rscript plotly/tests/build-push-comment.R notifications: slack: From 43e75f5edcd666824ba859cb4d5a1d9c6342401c Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sun, 10 May 2015 20:36:12 -0500 Subject: [PATCH 26/48] Forgot to add tests/build-push-comment.R --- tests/build-push-comment.R | 124 +++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/build-push-comment.R diff --git a/tests/build-push-comment.R b/tests/build-push-comment.R new file mode 100644 index 0000000000..5b465dd741 --- /dev/null +++ b/tests/build-push-comment.R @@ -0,0 +1,124 @@ +# ----------------------------------------------------------------------- +# Travis does two types of builds: +# +# (1) A so-called "push". This essentially does a checkout on the most +# recent commit of the pull request, but *doesn't* merge with master. +# In this case, $TRAVIS_PULL_REQUEST = "false" +# (2) A so-called "pr" (pull request). This *does* merge with master. +# In this case, $TRAVIS_PULL_REQUEST contains the pull request number. +# +# Since it makes more sense to visually compared what we'd see *after* we +# merge with master, we don't do anything here if it's a push build. +# ----------------------------------------------------------------------- + +# Read more about Travis environment variables -- +# http://docs.travis-ci.com/user/ci-environment/#Environment-variables +tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") +if (tpr != "false" && tpr != "") { + library("httr") + library("testthat") + # gistr is a good reference for talking to the github API via httr + # https://github.com/ropensci/gistr/blob/master/R/zzz.R + base <- 'https://api.github.com/repos/ropensci/plotly/' + header <- add_headers(`User-Agent` = "plotly", + `Accept` = 'application/vnd.github.v3+json', + `Authorization` = paste0("token ", Sys.getenv("GH_TOKEN"))) + # Grab the branch name for this pull request (must be successful!!) + # http://stackoverflow.com/questions/15096331/github-api-how-to-find-the-branches-of-a-pull-request + pr <- sprintf(paste0(base, 'pulls/%s'), tpr) + res <- GET(url = pr, header) + stop_for_status(res) + info <- content(res) + branch <- strsplit(info$head$label, ":")[[1]][2] + + # Return an abbreviated version of a hash + abbrev_hash <- function(hash = "") substr(hash, 1, 7) + + # Grab HEAD info for each branch (this might not be necessary) +# br <- paste0(base, 'branches') +# res <- GET(br) +# stop_for_status(res) +# info <- content(res) +# commits <- sapply(info, "[[", "commit") +# shas <- unlist(commits["sha",]) +# shas <- sapply(shas, abbrev_hash, USE.NAMES = FALSE) +# shas <- setNames(shas, sapply(info, "[[", "name")) + + # NOTE: $TRAVIS_COMMIT doesn't match the HEAD of this (or master) branch!!! + # Remember that we're *simulating* a merge with master, but the hash for the + # *actual* merge will be different. Instead of installing master each time + # we call save_outputs(), we install once here, if necessary, and re-run tests + this_hash <- abbrev_hash(Sys.getenv("TRAVIS_COMMIT")) + base_hash <- abbrev_hash(info$base$sha) + head_hash <- abbrev_hash(info$head$sha) + test_rerun <- function(hash) { + if (!hash %in% dir("plotly-test-table/R")) { + devtools::install_github("ropensci/plotly", ref = hash) + testthat::test_package("plotly") + } + } + test_rerun(this_hash) + test_rerun(base_hash) + + # TODO: Remove plotly-test-table folders that are no longer needed + # by comparing the directories to branch HEADs for plotly. This could + # be hard to do the git rm properly. We could also run tests for missing + # HEAD shas, but that's probably overkill + + # list png files in a particular directory + pngs <- function(...) { + dir(file.path("plotly-test-table", "R", ...), + pattern = "\\.png$", full.names = T) + } + # Build the main HTML page for this build + ggpngs <- pngs("ggplot2", packageVersion("ggplot2")) + df <- data.frame(sub("\\.png$", "", basename(ggpngs)), + ggpngs, pngs(this_hash), pngs(base_hash)) + names(df) <- c("test", "ggplot2", branch, "master") + # TODO: create an HTML page for each test + df$test <- sprintf(' %s ', df$test) + for (i in setdiff(names(df), "test")) + df[, i] <- sprintf(' ', df[, i]) + test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', + quiet = TRUE) + dest <- file.path("plotly-test-table", "R", this_hash, "index.html") + writeLines(test_table, file = dest) + + # TODO: + # * convert for thumbnails!! (see wch/vtest's convert_png() for alternative) + # * create home page for R with commmit info -- https://developer.github.com/v3/git/commits/ + + # add, commit, push to gh-pages branch of plotly-test-table + system("git add *") + build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', + Sys.getenv("TRAVIS_BUILD_ID")) + commit_msg <- paste0('"Pushed from ', build_link, '"') + system(paste('git commit -m', commit_msg)) + # This post explains how this works -- http://rmflight.github.io/posts/2014/11/travis_ci_gh_pages.html + repo <- sprintf("https://%s@github.com/cpsievert/plotly-test-table.git", Sys.getenv("GH_TOKEN")) + system(paste("git pull -q", repo, "gh-pages")) + system(paste("git push -q", repo, "gh-pages")) + + # post comment if a link to this SHA doesn't exist + # (needed since Travis randomly re-builds stuff) + tbl_link <- sprintf("http://cpsievert.github.io/plotly-test-table/R/%s/index.html", this_hash) + msg <- sprintf("On TravisCI, commit %s was successfully merged with %s (master) to create %s. A visual testing table comparing %s with %s can be found here:\n %s", + head_hash, base_hash, this_hash, base_hash, this_hash, tbl_link) + msg <- paste("> The message below was automatically generated after build", build_link, "\n\n", msg) + commentz <- sprintf(paste0(base, 'issues/%s/comments'), tpr) + res <- GET(commentz, header) + warn_for_status(res) + info <- content(res) + old_body <- unlist(lapply(info, "[", "body")) + if (!any(grepl(tbl_link, old_body))) { + json <- jsonlite::toJSON(list(body = msg), auto_unbox = TRUE) + POST(url = commentz, header, body = json, encode = "json") + } else { + message("Link already posted") + } +} + + +# IDEAS: +# * iframe into json diffs on github??? +# * Github now renders IPython!!! From ca9195d1e7bac8eba228d381acc2a81724809d85 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Sun, 10 May 2015 21:06:54 -0500 Subject: [PATCH 27/48] hmm, that's a strange error, try test_dir() --- tests/build-push-comment.R | 3 ++- tests/testthat.R | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/build-push-comment.R b/tests/build-push-comment.R index 5b465dd741..32b64285ff 100644 --- a/tests/build-push-comment.R +++ b/tests/build-push-comment.R @@ -54,7 +54,8 @@ if (tpr != "false" && tpr != "") { test_rerun <- function(hash) { if (!hash %in% dir("plotly-test-table/R")) { devtools::install_github("ropensci/plotly", ref = hash) - testthat::test_package("plotly") + message("Rerunning tests") + testthat::test_dir("plotly") } } test_rerun(this_hash) diff --git a/tests/testthat.R b/tests/testthat.R index 642660614a..0c38dac68a 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -14,7 +14,6 @@ save_outputs <- function(gg, name) { tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") if (tpr != "false" && tpr != "") { table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") - # this environment variable should be set by testthat.R plotly_dir <- file.path(table_dir, "R", hash) gg_dir <- file.path(table_dir, "R", "ggplot2") if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) From 837e36e720d7de52cbec571b004ae5aad6585551 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 19:47:33 -0500 Subject: [PATCH 28/48] I wonder if craigcitro/r-travis does this right --- .travis.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 630a150aee..1baa5f034c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,27 @@ -language: r - -env: - global: - - secure: "cJ1bDRrAdIRjG+JnsQI9CdA4wQJhJJ2DdCNQ3frl8dotk69z61EiGCFW1Ir1cAY5V/NbHvFHp91HDiSo28ggwqRkEPBOGE44ico5gtVaELu3M/EnkWc2ZwQoN1273Vfdm26QYidqrvWrpLZ0XkFl7Q8xgvBswx30MF7y61+0Hv4=" - -r_packages: - - RJSONIO - - lattice - - xtable - - httr +language: c before_script: + - curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh + - chmod 755 ./travis-tool.sh + - ./travis-tool.sh bootstrap - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table +install: + - ./travis-tool.sh install_deps + +script: + - ./travis-tool.sh run_tests + after_success: - cd .. - Rscript plotly/tests/build-push-comment.R +env: + global: + - secure: "cJ1bDRrAdIRjG+JnsQI9CdA4wQJhJJ2DdCNQ3frl8dotk69z61EiGCFW1Ir1cAY5V/NbHvFHp91HDiSo28ggwqRkEPBOGE44ico5gtVaELu3M/EnkWc2ZwQoN1273Vfdm26QYidqrvWrpLZ0XkFl7Q8xgvBswx30MF7y61+0Hv4=" + notifications: slack: secure: YvyGtGRFC4HJGD4d2Vx6fHU93EliJCHbcf/k9/Rbpl3wtYFZfWKbKL1FHvPw/g3auVebonz8hScnYzR0uYnR3dHSlmj3QrJ3NOePv5QAZRHy7aY/XKRr5JR1Ji/vX1yfbrJDmiYuGMxJVE8l/kbu0TxwDdLletY5nJpwlkHfaW8= From fa88bd55cb6878aa2e9fa1f3715b7d2972e5d06a Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 21:01:21 -0500 Subject: [PATCH 29/48] before_script happens after install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1baa5f034c..4b2da06c79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: c -before_script: +before_install: - curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh - chmod 755 ./travis-tool.sh - ./travis-tool.sh bootstrap From 3167d34b68cf2e3342a75a7c33a26d1000b17a4f Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 21:52:59 -0500 Subject: [PATCH 30/48] huh, looks like some changes were just introduced into nativ R builds --- .travis.yml | 20 +++++++++----------- tests/build-push-comment.R | 2 ++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b2da06c79..a5d97d182c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,17 @@ -language: c +language: r +sudo: required -before_install: - - curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh - - chmod 755 ./travis-tool.sh - - ./travis-tool.sh bootstrap +r_packages: + - RJSONIO + - lattice + - xtable + - httr + +before_script: - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table -install: - - ./travis-tool.sh install_deps - -script: - - ./travis-tool.sh run_tests - after_success: - cd .. - Rscript plotly/tests/build-push-comment.R diff --git a/tests/build-push-comment.R b/tests/build-push-comment.R index 32b64285ff..785d85241a 100644 --- a/tests/build-push-comment.R +++ b/tests/build-push-comment.R @@ -117,6 +117,8 @@ if (tpr != "false" && tpr != "") { } else { message("Link already posted") } +} else { + message('The test table is only built during the "pull request" build.') } From 5c25a69e7a70ff3871d4fe19a38bbec191d0e329 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 22:39:13 -0500 Subject: [PATCH 31/48] try local = FALSE --- tests/build-push-comment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/build-push-comment.R b/tests/build-push-comment.R index 785d85241a..3d7eecf0fb 100644 --- a/tests/build-push-comment.R +++ b/tests/build-push-comment.R @@ -53,7 +53,7 @@ if (tpr != "false" && tpr != "") { head_hash <- abbrev_hash(info$head$sha) test_rerun <- function(hash) { if (!hash %in% dir("plotly-test-table/R")) { - devtools::install_github("ropensci/plotly", ref = hash) + devtools::install_github("ropensci/plotly", ref = hash, local = FALSE) message("Rerunning tests") testthat::test_dir("plotly") } From a662ce721ee84bdb23494535f857268987dd89e8 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 23:03:52 -0500 Subject: [PATCH 32/48] oops, move build-push-comment.R to inst/ since anything under tests/ gets sourced during R CMD check --- .travis.yml | 2 +- {tests => inst}/build-push-comment.R | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {tests => inst}/build-push-comment.R (100%) diff --git a/.travis.yml b/.travis.yml index a5d97d182c..d3f53de24d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_script: after_success: - cd .. - - Rscript plotly/tests/build-push-comment.R + - Rscript plotly/inst/build-push-comment.R env: global: diff --git a/tests/build-push-comment.R b/inst/build-push-comment.R similarity index 100% rename from tests/build-push-comment.R rename to inst/build-push-comment.R From dd0ceeb98ab1ccfba37fc9ff947ecb8f24aec3fd Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 23:28:19 -0500 Subject: [PATCH 33/48] Yay\! Progress, finally\! --- inst/build-push-comment.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index 3d7eecf0fb..3260c464c6 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -55,7 +55,7 @@ if (tpr != "false" && tpr != "") { if (!hash %in% dir("plotly-test-table/R")) { devtools::install_github("ropensci/plotly", ref = hash, local = FALSE) message("Rerunning tests") - testthat::test_dir("plotly") + testthat::test_dir("plotly/tests") } } test_rerun(this_hash) @@ -83,7 +83,7 @@ if (tpr != "false" && tpr != "") { test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', quiet = TRUE) dest <- file.path("plotly-test-table", "R", this_hash, "index.html") - writeLines(test_table, file = dest) + writeLines(test_table, dest) # TODO: # * convert for thumbnails!! (see wch/vtest's convert_png() for alternative) From 7ccd7c2bd2b8d85855edaf0d2b1474188a1c93e7 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Mon, 11 May 2015 23:49:50 -0500 Subject: [PATCH 34/48] Always source the newest testthat.R script --- inst/build-push-comment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index 3260c464c6..d3b9a2da12 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -55,7 +55,7 @@ if (tpr != "false" && tpr != "") { if (!hash %in% dir("plotly-test-table/R")) { devtools::install_github("ropensci/plotly", ref = hash, local = FALSE) message("Rerunning tests") - testthat::test_dir("plotly/tests") + setwd("plotly/tests"); source("testthat.R") } } test_rerun(this_hash) From ce65cb04a9bcd3452a926354e05fd889d31400b2 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 00:16:14 -0500 Subject: [PATCH 35/48] Use chdir --- inst/build-push-comment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index d3b9a2da12..bd325123fd 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -55,7 +55,7 @@ if (tpr != "false" && tpr != "") { if (!hash %in% dir("plotly-test-table/R")) { devtools::install_github("ropensci/plotly", ref = hash, local = FALSE) message("Rerunning tests") - setwd("plotly/tests"); source("testthat.R") + source("plotly/tests/testthat.R", chdir = TRUE) } } test_rerun(this_hash) From 658c00037c2a1eb4b1865b4553cb624720debefb Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 00:44:07 -0500 Subject: [PATCH 36/48] avoid stopping on test error --- inst/build-push-comment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index bd325123fd..02571ac23f 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -55,7 +55,7 @@ if (tpr != "false" && tpr != "") { if (!hash %in% dir("plotly-test-table/R")) { devtools::install_github("ropensci/plotly", ref = hash, local = FALSE) message("Rerunning tests") - source("plotly/tests/testthat.R", chdir = TRUE) + try(source("plotly/tests/testthat.R", chdir = TRUE)) } } test_rerun(this_hash) From 69e3db9ab52574f43810f72e27378a5910286e73 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 10:40:43 -0500 Subject: [PATCH 37/48] devtools doesn't report hash for local installs --- tests/testthat.R | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/testthat.R b/tests/testthat.R index 0c38dac68a..a1ddf77aba 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -6,7 +6,13 @@ Sys.setenv(`plotly-apikey` = "r1neazxo9w") # find the hash of the currently installed plotly package pkg_info <- devtools::session_info()$packages src <- subset(pkg_info, package == "plotly")$source -hash <- sub("\\)", "", strsplit(src, "@")[[1]][2]) +hash <- if (src == "local") { + # you could also do `git rev-parse HEAD`, but this is cleaner for Travis + substr(Sys.getenv("TRAVIS_COMMIT"), 1, 7) +} else { + # thankfully devtools includes hash for installs from GitHub + sub("\\)", "", strsplit(src, "@")[[1]][2]) +} save_outputs <- function(gg, name) { # only render/save pngs if this is a Travis pull request From 76923e2e28beaed961800e97b40238e7594a1c60 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 11:51:06 -0500 Subject: [PATCH 38/48] why does this hash dir not exist? --- inst/build-push-comment.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index 02571ac23f..f779270039 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -83,6 +83,8 @@ if (tpr != "false" && tpr != "") { test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', quiet = TRUE) dest <- file.path("plotly-test-table", "R", this_hash, "index.html") + list.files("plotly-test-table") + list.files("plotly-test-table/R") writeLines(test_table, dest) # TODO: From 6ef13d9908dc31c08ed65cd445cebc097f7b6cbb Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 12:27:56 -0500 Subject: [PATCH 39/48] If only I could pull down the travis build locally --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index d3f53de24d..4480e4452e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,12 @@ before_script: - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table + - pwd after_success: + - pwd - cd .. + - ls - Rscript plotly/inst/build-push-comment.R env: From 5c4c20741742d8ad88692875e3f8f86e96a4a2b8 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 13:15:20 -0500 Subject: [PATCH 40/48] recursive ls --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4480e4452e..9fef07e855 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ before_script: after_success: - pwd - cd .. - - ls + - ls -R - Rscript plotly/inst/build-push-comment.R env: From a321dc3b579a792a983e09af13eae141d1cb16c3 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 13:43:50 -0500 Subject: [PATCH 41/48] ah, dirname of is plotly --- tests/testthat.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat.R b/tests/testthat.R index a1ddf77aba..810a5d92ec 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -19,7 +19,7 @@ save_outputs <- function(gg, name) { # (see build-comment-push.R for better explanation of this logic) tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") if (tpr != "false" && tpr != "") { - table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "plotly-test-table") + table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "..", "plotly-test-table") plotly_dir <- file.path(table_dir, "R", hash) gg_dir <- file.path(table_dir, "R", "ggplot2") if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) From 5d5499b77216758b9b5732dd5f5a47baff0900b4 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 14:15:27 -0500 Subject: [PATCH 42/48] navigate into plotly-test-table --- inst/build-push-comment.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index f779270039..4909855ec9 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -83,8 +83,6 @@ if (tpr != "false" && tpr != "") { test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', quiet = TRUE) dest <- file.path("plotly-test-table", "R", this_hash, "index.html") - list.files("plotly-test-table") - list.files("plotly-test-table/R") writeLines(test_table, dest) # TODO: @@ -92,6 +90,7 @@ if (tpr != "false" && tpr != "") { # * create home page for R with commmit info -- https://developer.github.com/v3/git/commits/ # add, commit, push to gh-pages branch of plotly-test-table + setwd("plotly-test-table") system("git add *") build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', Sys.getenv("TRAVIS_BUILD_ID")) From c0f1ca9fffc16d7995878d883b5506e91ceb1ba9 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 21:35:18 -0500 Subject: [PATCH 43/48] debug statements --- .travis.yml | 3 --- inst/build-push-comment.R | 2 ++ tests/testthat.R | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fef07e855..d3f53de24d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,9 @@ before_script: - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table - - pwd after_success: - - pwd - cd .. - - ls -R - Rscript plotly/inst/build-push-comment.R env: diff --git a/inst/build-push-comment.R b/inst/build-push-comment.R index 4909855ec9..30c2bb1443 100644 --- a/inst/build-push-comment.R +++ b/inst/build-push-comment.R @@ -80,6 +80,7 @@ if (tpr != "false" && tpr != "") { df$test <- sprintf(' %s ', df$test) for (i in setdiff(names(df), "test")) df[, i] <- sprintf(' ', df[, i]) + print(df) test_table <- knitr::knit2html(text = '`r knitr::kable(df, type = "html")`', quiet = TRUE) dest <- file.path("plotly-test-table", "R", this_hash, "index.html") @@ -91,6 +92,7 @@ if (tpr != "false" && tpr != "") { # add, commit, push to gh-pages branch of plotly-test-table setwd("plotly-test-table") + system("git status") system("git add *") build_link <- paste0('https://travis-ci.org/ropensci/plotly/builds/', Sys.getenv("TRAVIS_BUILD_ID")) diff --git a/tests/testthat.R b/tests/testthat.R index 810a5d92ec..e9361b7ea4 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -10,7 +10,7 @@ hash <- if (src == "local") { # you could also do `git rev-parse HEAD`, but this is cleaner for Travis substr(Sys.getenv("TRAVIS_COMMIT"), 1, 7) } else { - # thankfully devtools includes hash for installs from GitHub + # thankfully devtools includes hash for packages installed off GitHub sub("\\)", "", strsplit(src, "@")[[1]][2]) } @@ -19,7 +19,8 @@ save_outputs <- function(gg, name) { # (see build-comment-push.R for better explanation of this logic) tpr <- Sys.getenv("TRAVIS_PULL_REQUEST") if (tpr != "false" && tpr != "") { - table_dir <- file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "..", "plotly-test-table") + table_dir <- + file.path(Sys.getenv("TRAVIS_BUILD_DIR"), "..", "plotly-test-table") plotly_dir <- file.path(table_dir, "R", hash) gg_dir <- file.path(table_dir, "R", "ggplot2") if (!dir.exists(plotly_dir)) dir.create(plotly_dir, recursive = TRUE) @@ -58,7 +59,6 @@ save_outputs <- function(gg, name) { test_check("plotly") - # NOTE: I'm assumming Travis is installing most recent ggplot2 off CRAN # Here is one way to get current ggplot2 version off of CRAN if need be # gg <- rvest::html("http://cran.r-project.org/web/packages/ggplot2/") From 16e22ddb836599229918642d51326cf28dc57758 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 22:23:21 -0500 Subject: [PATCH 44/48] wasn't creating a dir for each ggplot version --- tests/testthat.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/testthat.R b/tests/testthat.R index e9361b7ea4..d69f8ebecc 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -33,9 +33,10 @@ save_outputs <- function(gg, name) { # https://github.com/travis-ci/travis-ci/issues/3849 ggversion <- as.character(packageVersion("ggplot2")) if (!ggversion %in% dir(gg_dir)) { - dest <- file.path(gg_dir, ggversion, paste0(name, ".png")) + gglife <- file.path(gg_dir, ggversion) + dir.create(gglife, recursive = TRUE) e <- try(gg, silent = TRUE) - png(filename = dest) + png(filename = file.path(gglife, paste0(name, ".png"))) if (inherits(e, "try-error")) { plot(1, type="n") text(1, "ggplot2 error") From 01d4e622fc13c591abcda7604f84fd66da465b5b Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 22:51:29 -0500 Subject: [PATCH 45/48] Thanks for nothing R CMD check --- .travis.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3f53de24d..8bad9e4faa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,21 @@ -language: r -sudo: required +language: c -r_packages: - - RJSONIO - - lattice - - xtable - - httr +before_install: + - curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh + - chmod 755 ./travis-tool.sh + - ./travis-tool.sh bootstrap + +install: + - ./travis-tool.sh install_deps before_script: - git config --global user.name "cpsievert" - git config --global user.email "cpsievert1@gmail.com" - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table +script: + - Rscript -e "source('tests/testthat.R', chdir = TRUE)" + after_success: - cd .. - Rscript plotly/inst/build-push-comment.R From 7cf2e20f3ebb43f3fe23c57fdfead7c3385f6904 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 12 May 2015 22:58:34 -0500 Subject: [PATCH 46/48] install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8bad9e4faa..3e611eeccd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ before_script: - git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table script: - - Rscript -e "source('tests/testthat.R', chdir = TRUE)" + - Rscript -e "devtools::install(); source('tests/testthat.R', chdir = TRUE)" after_success: - cd .. From c8488f7e0596a8b5636c6054c754f399cbdf0a6d Mon Sep 17 00:00:00 2001 From: cpsievert Date: Tue, 19 May 2015 18:15:54 -0500 Subject: [PATCH 47/48] underscores --- R/plotly.R | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/R/plotly.R b/R/plotly.R index 49f9c48b47..bfc2aef008 100644 --- a/R/plotly.R +++ b/R/plotly.R @@ -35,7 +35,7 @@ signup <- function(username, email, save = TRUE) { if (save) { # store API key as an environment variable in .Rprofile cat_profile("username", con[["un"]]) - cat_profile("apikey", con[["api_key"]]) + cat_profile("api_key", con[["api_key"]]) } invisible(structure(con, class = "apimkacct")) } @@ -61,10 +61,10 @@ signup <- function(username, email, save = TRUE) { #' #' # If you already have a username and API key, please create the following #' # environment variables: -#' Sys.setenv(`plotly-username` = "me") -#' Sys.setenv(`plotly-apikey` = "mykey") +#' Sys.setenv("plotly_username" = "me") +#' Sys.setenv("plotly_api_key" = "mykey") #' # You can also change the default domain if you have a plotly server. -#' Sys.setenv(`plotly-domain` = "http://mydomain.com") +#' Sys.setenv("plotly_domain" = "http://mydomain.com") #' #' # If you don't want to specify these environment variables everytime you #' # start R, you can put that code in a .Rprofile (see help(.Rprofile)) @@ -98,9 +98,9 @@ plotly <- function(p = last_plot(), browse = interactive(), ...) { # specifying username and key should still work .args <- as.list(match.call()) if ("username" %in% names(.args)) - Sys.setenv(`plotly-username` = args[["username"]]) + Sys.setenv("plotly_username" = args[["username"]]) if ("key" %in% names(.args)) - Sys.setenv(`plotly-apikey` = args[["key"]]) + Sys.setenv("plotly_api_key" = args[["key"]]) if (!"data" %in% names(p)) stop("p should have at least one element named 'data'", "(which is mapped to the args parameter in the plotly REST API).") @@ -145,7 +145,7 @@ plotly_POST <- function(args, kwargs = list(filename = "plot from api", fileopt # construct body of message to plotly server bod <- list( un = verify("username"), - key = verify("apikey"), + key = verify("api_key"), origin = origin, platform = "R", version = as.character(packageVersion("plotly")), @@ -234,22 +234,30 @@ embed_notebook <- function(url, width = "100%", height = "525") { # ---------------------------------------- get_domain <- function() { - Sys.getenv("plotly-domain", "https://plot.ly") + Sys.getenv("plotly_domain", "https://plot.ly") } plotly_headers <- function() { httr::add_headers(.headers = c( "plotly-username" = verify("username"), - "plotly-apikey" = verify("apikey"), + "plotly-apikey" = verify("api_key"), "plotly-version" = as.character(packageVersion("plotly")), "plotly-platform" = "R")) } # verify that a certain environment variable exists verify <- function(what = "username") { - who <- paste0("plotly-", what) + who <- paste0("plotly_", what) val <- Sys.getenv(who, "") - if (val == "") stop("Must specify ", what, call. = FALSE) + # If the environment variable doesn't exist, fall back on hidden files + if (val == "") { + PLOTLY_DIR <- file.path(normalizePath("~", mustWork = TRUE), ".plotly") + CREDENTIALS_FILE <- file.path(PLOTLY_DIR, ".credentials") + CONFIG_FILE <- file.path(PLOTLY_DIR, ".config") + + stop("Must specify ", what, call. = FALSE) + } + val } @@ -262,7 +270,7 @@ plotly_iframe <- function(url, width, height) { cat_profile <- function(key, value, path = "~") { r_profile <- file.path(normalizePath(path, mustWork = TRUE), ".Rprofile") - snippet <- sprintf('\nSys.setenv(`plotly-%s` = "%s")', key, value) + snippet <- sprintf('\nSys.setenv("plotly_%s" = "%s")', key, value) if (!file.exists(r_profile)) { message("Creating", r_profile) r_profile_con <- file(r_profile) @@ -271,7 +279,7 @@ cat_profile <- function(key, value, path = "~") { stop("R doesn't have permission to write to this file: ", path) if (file.access(r_profile, 4) != 0) stop("R doesn't have permission to read this file: ", path) - message("Adding plotly-", key, " environment variable to ", r_profile) + message("Adding plotly_", key, " environment variable to ", r_profile) cat(snippet, file = r_profile, append = TRUE) } From 026371a174f5607ee99ed8cebf4c757441c12154 Mon Sep 17 00:00:00 2001 From: cpsievert Date: Thu, 28 May 2015 12:06:24 -0500 Subject: [PATCH 48/48] underscores in env vars --- tests/testthat.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat.R b/tests/testthat.R index d69f8ebecc..3047a2f6ed 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,8 +1,8 @@ library("testthat") library("plotly") # crendentials for the test bot -Sys.setenv(`plotly-username` = "TestBot") -Sys.setenv(`plotly-apikey` = "r1neazxo9w") +Sys.setenv("plotly_username" = "TestBot") +Sys.setenv("plotly_apikey" = "r1neazxo9w") # find the hash of the currently installed plotly package pkg_info <- devtools::session_info()$packages src <- subset(pkg_info, package == "plotly")$source