Skip to content

Add support for images endpoint #279

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 14, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: plotly
Title: Create interactive web-based graphs via plotly's API
Version: 1.0.7
Version: 1.0.8
Authors@R: c(person("Chris", "Parmer", role = c("aut", "cph"),
email = "chris@plot.ly"),
person("Scott", "Chamberlain", role = "aut",
@@ -30,7 +30,8 @@ Imports:
jsonlite,
magrittr,
digest,
viridis
viridis,
base64enc
Suggests:
dplyr,
maps,
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ export(paramORdefault)
export(plot_ly)
export(plotly)
export(plotlyOutput)
export(plotly_IMAGE)
export(plotly_POST)
export(plotly_build)
export(plotly_empty)
@@ -31,5 +32,6 @@ export(toRGB)
import(ggplot2)
import(httr)
import(jsonlite)
importFrom(base64enc,base64encode)
importFrom(magrittr,"%>%")
importFrom(viridis,viridis)
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
1.0.8 -- 14 Sep 2015

Added the plotly_IMAGES() function which interfaces to the images endpoint https://api.plot.ly/v2/#images

Details -> https://github.com/ropensci/plotly/pull/279

1.0.7 -- 26 Aug 2015

See https://github.com/ropensci/plotly/pull/275
22 changes: 20 additions & 2 deletions R/plotly.R
Original file line number Diff line number Diff line change
@@ -316,8 +316,26 @@ plotly_build <- function(l = last_plot()) {
}
# search for keyword args in traces and place them at the top level
kwargs <- lapply(x$data, function(z) z[get_kwargs()])
if (length(kwargs) == 1) kwargs <- c(kwargs, kwargs)
x <- c(x, Reduce(modifyList, kwargs))
# later keywords args take precedence
kwargs <- Reduce(modifyList, kwargs)
# empty keyword arguments can cause problems
kwargs <- kwargs[sapply(kwargs, length) > 0]
# filename & fileopt are keyword arguments required by the API
if (!is.null(x$url) || !is.null(kwargs$filename))
kwargs$fileopt <- "overwrite"
kwargs$fileopt <- kwargs$fileopt %||% "new"
# try our damndest to assign a sensible filename
if (is.null(kwargs$filename)) {
kwargs$filename <-
as.character(kwargs$layout$title) %||%
paste(
c(kwargs$layout$xaxis$title,
kwargs$layout$yaxis$title,
kwargs$layout$zaxis$title),
collapse = " vs. "
) %||%
"plot from api"
}
# traces shouldn't have any names
x$data <- setNames(x$data, NULL)
# add plotly class mainly for printing method
42 changes: 42 additions & 0 deletions R/plotly_IMAGE.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#' Create/Modify plotly images
#'
#' The images endpoint turn a plot (which may be given in multiple forms)
#' into an image of the desired format.
#'
#' @param x either a plotly object or a list.
#' @param width Image width in pixels
#' @param height Image height in pixels
#' @param format The desired image format 'png', 'jpeg', 'svg', 'pdf', 'eps', or 'webp'
#' @param scale Both png and jpeg formats will be scaled beyond the specified width and height by this number.
#' @param out_file A filename for writing the image to a file.
#' @param ... arguments passed onto \code{httr::POST}
#' @export
#' @examples
#'
#' p <- plot_ly(x = 1:10)
#'
#' Png <- plotly_IMAGE(p, out_file = "plotly-test-image.png")
#' Jpeg <- plotly_IMAGE(p, format = "jpeg", out_file = "plotly-test-image.jpeg")
#' Svg <- plotly_IMAGE(p, format = "svg", out_file = "plotly-test-image.svg")
#' Pdf <- plotly_IMAGE(p, format = "pdf", out_file = "plotly-test-image.pdf")
#'

plotly_IMAGE <- function(x, width = 1000, height = 500, format = "png",
scale = 4, out_file, ...) {
x <- plotly_build(x)

bod <- list(
figure = x[c("data", "layout")],
width = width,
height = height,
format = format,
scale = scale,
encoded = FALSE
)
base_url <- paste0(get_domain("v2"), "images")
resp <- httr::POST(base_url, plotly_headers("v2"), body = to_JSON(bod),
if (!missing(out_file)) write_disk(out_file, overwrite = TRUE),
...)
con <- process(struct(resp, "image"))
invisible(con)
}
23 changes: 2 additions & 21 deletions R/plotly_POST.R
Original file line number Diff line number Diff line change
@@ -28,25 +28,6 @@

plotly_POST <- function(x) {
x <- plotly_build(x)
# empty keyword arguments can cause problems
kwargs <- x[get_kwargs()]
kwargs <- kwargs[sapply(kwargs, length) > 0]

# filename & fileopt are keyword arguments required by the API
# (note they can also be specified by the user)
if (!is.null(x$url) || !is.null(kwargs$filename)) kwargs$fileopt <- "overwrite"
if (is.null(kwargs$filename)) {
kwargs$filename <-
as.character(kwargs$layout$title) %||%
paste(
c(kwargs$layout$xaxis$title,
kwargs$layout$yaxis$title,
kwargs$layout$zaxis$title),
collapse = " vs. "
) %||%
"plot from api"
}
if (is.null(kwargs$fileopt)) kwargs$fileopt <- "new"
# construct body of message to plotly server
bod <- list(
un = verify("username"),
@@ -55,12 +36,12 @@ plotly_POST <- function(x) {
platform = "R",
version = as.character(packageVersion("plotly")),
args = to_JSON(x$data),
kwargs = to_JSON(kwargs)
kwargs = to_JSON(x[get_kwargs()])
)
base_url <- file.path(get_domain(), "clientresp")
resp <- httr::POST(base_url, body = bod)
con <- process(struct(resp, "clientresp"))
msg <- switch(kwargs$fileopt,
msg <- switch(x$fileopt %||% "new",
new = "Success! Created a new plotly here -> ",
overwrite = "Success! Modified your plotly here -> ")
message(msg, con$url)
7 changes: 7 additions & 0 deletions R/process.R
Original file line number Diff line number Diff line change
@@ -15,6 +15,13 @@ process.clientresp <- function(resp) {
con
}

process.image <- function(resp) {
httr::stop_for_status(resp)
# httr (should) know to call png::readPNG() which returns raster array
tryCatch(httr::content(resp, as = "parsed"),
error = function(e) httr::content(resp, as = "raw"))
}

process.figure <- function(resp) {
httr::stop_for_status(resp)
con <- from_JSON(content(resp, as = "text"))
31 changes: 24 additions & 7 deletions R/utils.R
Original file line number Diff line number Diff line change
@@ -141,10 +141,11 @@ struct <- function(x, y, ...) {
get_domain <- function(type = "main") {
if (type == "stream") {
Sys.getenv("plotly_streaming_domain", "http://stream.plot.ly")
} else if (type == "v2") {
Sys.getenv("plotly_domain", "https://api.plot.ly/v2/")
} else {
Sys.getenv("plotly_domain", "https://plot.ly")
}

}

# plotly's special keyword arguments in POST body
@@ -153,12 +154,28 @@ get_kwargs <- function() {
}

# POST header fields
plotly_headers <- function() {
httr::add_headers(.headers = c(
"plotly-username" = verify("username"),
"plotly-apikey" = verify("api_key"),
"plotly-version" = as.character(packageVersion("plotly")),
"plotly-platform" = "R"))
#' @importFrom base64enc base64encode
plotly_headers <- function(type = "main") {
usr <- verify("username")
key <- verify("api_key")
v <- as.character(packageVersion("plotly"))
h <- if (type == "v2") {
auth <- base64enc::base64encode(charToRaw(paste(usr, key, sep = ":")))
c(
"authorization" = paste("Basic", auth),
"plotly-client-platform" = paste("R", v),
"plotly_version" = v,
"content-type" = "application/json"
)
} else {
c(
"plotly-username" = usr,
"plotly-apikey" = key,
"plotly-version" = v,
"plotly-platform" = "R"
)
}
httr::add_headers(.headers = h)
}

# try to write environment variables to an .Rprofile
38 changes: 38 additions & 0 deletions man/plotly_IMAGE.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/plotly_IMAGE.R
\name{plotly_IMAGE}
\alias{plotly_IMAGE}
\title{Create/Modify plotly images}
\usage{
plotly_IMAGE(x, width = 1000, height = 500, format = "png", scale = 4,
out_file, ...)
}
\arguments{
\item{x}{either a plotly object or a list.}

\item{width}{Image width in pixels}

\item{height}{Image height in pixels}

\item{format}{The desired image format 'png', 'jpeg', 'svg', 'pdf', 'eps', or 'webp'}

\item{scale}{Both png and jpeg formats will be scaled beyond the specified width and height by this number.}

\item{out_file}{A filename for writing the image to a file.}

\item{...}{arguments passed onto \code{httr::POST}}
}
\description{
The images endpoint turn a plot (which may be given in multiple forms)
into an image of the desired format.
}
\examples{
p <- plot_ly(x = 1:10)

# returns raster array representing the image
img <- plotly_IMAGE(p, out_file = "plotly-test-image.png", overwrite = TRUE)

img <- plotly_IMAGE(p, format = "pdf",
out_file = "plotly-test-image.pdf")
}

3 changes: 1 addition & 2 deletions tests/testthat/test-plotly-filename.R
Original file line number Diff line number Diff line change
@@ -2,6 +2,5 @@ context("Filename")

test_that("filepath with directories is returned as passed", {
p <- print(plot_ly(mtcars, x = wt, y = vs, filename = "directory/awesome"))
# why is the directory name replicated in the response?
expect_identical(p$filename, "directorydirectory/awesome")
expect_match(p$filename, "directory/awesome")
})