Skip to content

Commit 2a043c0

Browse files
committed
Merge pull request #279 from ropensci/images
Add support for images endpoint
2 parents b0532b9 + de951de commit 2a043c0

File tree

10 files changed

+145
-34
lines changed

10 files changed

+145
-34
lines changed

DESCRIPTION

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: plotly
22
Title: Create interactive web-based graphs via plotly's API
3-
Version: 1.0.7
3+
Version: 1.0.8
44
Authors@R: c(person("Chris", "Parmer", role = c("aut", "cph"),
55
email = "[email protected]"),
66
person("Scott", "Chamberlain", role = "aut",
@@ -30,7 +30,8 @@ Imports:
3030
jsonlite,
3131
magrittr,
3232
digest,
33-
viridis
33+
viridis,
34+
base64enc
3435
Suggests:
3536
dplyr,
3637
maps,

NAMESPACE

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export(paramORdefault)
2020
export(plot_ly)
2121
export(plotly)
2222
export(plotlyOutput)
23+
export(plotly_IMAGE)
2324
export(plotly_POST)
2425
export(plotly_build)
2526
export(plotly_empty)
@@ -31,5 +32,6 @@ export(toRGB)
3132
import(ggplot2)
3233
import(httr)
3334
import(jsonlite)
35+
importFrom(base64enc,base64encode)
3436
importFrom(magrittr,"%>%")
3537
importFrom(viridis,viridis)

NEWS

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
1.0.8 -- 14 Sep 2015
2+
3+
Added the plotly_IMAGES() function which interfaces to the images endpoint https://api.plot.ly/v2/#images
4+
5+
Details -> https://github.com/ropensci/plotly/pull/279
6+
17
1.0.7 -- 26 Aug 2015
28

39
See https://github.com/ropensci/plotly/pull/275

R/plotly.R

+20-2
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,26 @@ plotly_build <- function(l = last_plot()) {
316316
}
317317
# search for keyword args in traces and place them at the top level
318318
kwargs <- lapply(x$data, function(z) z[get_kwargs()])
319-
if (length(kwargs) == 1) kwargs <- c(kwargs, kwargs)
320-
x <- c(x, Reduce(modifyList, kwargs))
319+
# later keywords args take precedence
320+
kwargs <- Reduce(modifyList, kwargs)
321+
# empty keyword arguments can cause problems
322+
kwargs <- kwargs[sapply(kwargs, length) > 0]
323+
# filename & fileopt are keyword arguments required by the API
324+
if (!is.null(x$url) || !is.null(kwargs$filename))
325+
kwargs$fileopt <- "overwrite"
326+
kwargs$fileopt <- kwargs$fileopt %||% "new"
327+
# try our damndest to assign a sensible filename
328+
if (is.null(kwargs$filename)) {
329+
kwargs$filename <-
330+
as.character(kwargs$layout$title) %||%
331+
paste(
332+
c(kwargs$layout$xaxis$title,
333+
kwargs$layout$yaxis$title,
334+
kwargs$layout$zaxis$title),
335+
collapse = " vs. "
336+
) %||%
337+
"plot from api"
338+
}
321339
# traces shouldn't have any names
322340
x$data <- setNames(x$data, NULL)
323341
# add plotly class mainly for printing method

R/plotly_IMAGE.R

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#' Create/Modify plotly images
2+
#'
3+
#' The images endpoint turn a plot (which may be given in multiple forms)
4+
#' into an image of the desired format.
5+
#'
6+
#' @param x either a plotly object or a list.
7+
#' @param width Image width in pixels
8+
#' @param height Image height in pixels
9+
#' @param format The desired image format 'png', 'jpeg', 'svg', 'pdf', 'eps', or 'webp'
10+
#' @param scale Both png and jpeg formats will be scaled beyond the specified width and height by this number.
11+
#' @param out_file A filename for writing the image to a file.
12+
#' @param ... arguments passed onto \code{httr::POST}
13+
#' @export
14+
#' @examples
15+
#'
16+
#' p <- plot_ly(x = 1:10)
17+
#'
18+
#' Png <- plotly_IMAGE(p, out_file = "plotly-test-image.png")
19+
#' Jpeg <- plotly_IMAGE(p, format = "jpeg", out_file = "plotly-test-image.jpeg")
20+
#' Svg <- plotly_IMAGE(p, format = "svg", out_file = "plotly-test-image.svg")
21+
#' Pdf <- plotly_IMAGE(p, format = "pdf", out_file = "plotly-test-image.pdf")
22+
#'
23+
24+
plotly_IMAGE <- function(x, width = 1000, height = 500, format = "png",
25+
scale = 4, out_file, ...) {
26+
x <- plotly_build(x)
27+
28+
bod <- list(
29+
figure = x[c("data", "layout")],
30+
width = width,
31+
height = height,
32+
format = format,
33+
scale = scale,
34+
encoded = FALSE
35+
)
36+
base_url <- paste0(get_domain("v2"), "images")
37+
resp <- httr::POST(base_url, plotly_headers("v2"), body = to_JSON(bod),
38+
if (!missing(out_file)) write_disk(out_file, overwrite = TRUE),
39+
...)
40+
con <- process(struct(resp, "image"))
41+
invisible(con)
42+
}

R/plotly_POST.R

+2-21
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,6 @@
2828

2929
plotly_POST <- function(x) {
3030
x <- plotly_build(x)
31-
# empty keyword arguments can cause problems
32-
kwargs <- x[get_kwargs()]
33-
kwargs <- kwargs[sapply(kwargs, length) > 0]
34-
35-
# filename & fileopt are keyword arguments required by the API
36-
# (note they can also be specified by the user)
37-
if (!is.null(x$url) || !is.null(kwargs$filename)) kwargs$fileopt <- "overwrite"
38-
if (is.null(kwargs$filename)) {
39-
kwargs$filename <-
40-
as.character(kwargs$layout$title) %||%
41-
paste(
42-
c(kwargs$layout$xaxis$title,
43-
kwargs$layout$yaxis$title,
44-
kwargs$layout$zaxis$title),
45-
collapse = " vs. "
46-
) %||%
47-
"plot from api"
48-
}
49-
if (is.null(kwargs$fileopt)) kwargs$fileopt <- "new"
5031
# construct body of message to plotly server
5132
bod <- list(
5233
un = verify("username"),
@@ -55,12 +36,12 @@ plotly_POST <- function(x) {
5536
platform = "R",
5637
version = as.character(packageVersion("plotly")),
5738
args = to_JSON(x$data),
58-
kwargs = to_JSON(kwargs)
39+
kwargs = to_JSON(x[get_kwargs()])
5940
)
6041
base_url <- file.path(get_domain(), "clientresp")
6142
resp <- httr::POST(base_url, body = bod)
6243
con <- process(struct(resp, "clientresp"))
63-
msg <- switch(kwargs$fileopt,
44+
msg <- switch(x$fileopt %||% "new",
6445
new = "Success! Created a new plotly here -> ",
6546
overwrite = "Success! Modified your plotly here -> ")
6647
message(msg, con$url)

R/process.R

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ process.clientresp <- function(resp) {
1515
con
1616
}
1717

18+
process.image <- function(resp) {
19+
httr::stop_for_status(resp)
20+
# httr (should) know to call png::readPNG() which returns raster array
21+
tryCatch(httr::content(resp, as = "parsed"),
22+
error = function(e) httr::content(resp, as = "raw"))
23+
}
24+
1825
process.figure <- function(resp) {
1926
httr::stop_for_status(resp)
2027
con <- from_JSON(content(resp, as = "text"))

R/utils.R

+24-7
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,11 @@ struct <- function(x, y, ...) {
141141
get_domain <- function(type = "main") {
142142
if (type == "stream") {
143143
Sys.getenv("plotly_streaming_domain", "http://stream.plot.ly")
144+
} else if (type == "v2") {
145+
Sys.getenv("plotly_domain", "https://api.plot.ly/v2/")
144146
} else {
145147
Sys.getenv("plotly_domain", "https://plot.ly")
146148
}
147-
148149
}
149150

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

155156
# POST header fields
156-
plotly_headers <- function() {
157-
httr::add_headers(.headers = c(
158-
"plotly-username" = verify("username"),
159-
"plotly-apikey" = verify("api_key"),
160-
"plotly-version" = as.character(packageVersion("plotly")),
161-
"plotly-platform" = "R"))
157+
#' @importFrom base64enc base64encode
158+
plotly_headers <- function(type = "main") {
159+
usr <- verify("username")
160+
key <- verify("api_key")
161+
v <- as.character(packageVersion("plotly"))
162+
h <- if (type == "v2") {
163+
auth <- base64enc::base64encode(charToRaw(paste(usr, key, sep = ":")))
164+
c(
165+
"authorization" = paste("Basic", auth),
166+
"plotly-client-platform" = paste("R", v),
167+
"plotly_version" = v,
168+
"content-type" = "application/json"
169+
)
170+
} else {
171+
c(
172+
"plotly-username" = usr,
173+
"plotly-apikey" = key,
174+
"plotly-version" = v,
175+
"plotly-platform" = "R"
176+
)
177+
}
178+
httr::add_headers(.headers = h)
162179
}
163180

164181
# try to write environment variables to an .Rprofile

man/plotly_IMAGE.Rd

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
% Generated by roxygen2 (4.1.1): do not edit by hand
2+
% Please edit documentation in R/plotly_IMAGE.R
3+
\name{plotly_IMAGE}
4+
\alias{plotly_IMAGE}
5+
\title{Create/Modify plotly images}
6+
\usage{
7+
plotly_IMAGE(x, width = 1000, height = 500, format = "png", scale = 4,
8+
out_file, ...)
9+
}
10+
\arguments{
11+
\item{x}{either a plotly object or a list.}
12+
13+
\item{width}{Image width in pixels}
14+
15+
\item{height}{Image height in pixels}
16+
17+
\item{format}{The desired image format 'png', 'jpeg', 'svg', 'pdf', 'eps', or 'webp'}
18+
19+
\item{scale}{Both png and jpeg formats will be scaled beyond the specified width and height by this number.}
20+
21+
\item{out_file}{A filename for writing the image to a file.}
22+
23+
\item{...}{arguments passed onto \code{httr::POST}}
24+
}
25+
\description{
26+
The images endpoint turn a plot (which may be given in multiple forms)
27+
into an image of the desired format.
28+
}
29+
\examples{
30+
p <- plot_ly(x = 1:10)
31+
32+
# returns raster array representing the image
33+
img <- plotly_IMAGE(p, out_file = "plotly-test-image.png", overwrite = TRUE)
34+
35+
img <- plotly_IMAGE(p, format = "pdf",
36+
out_file = "plotly-test-image.pdf")
37+
}
38+

tests/testthat/test-plotly-filename.R

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ context("Filename")
22

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

0 commit comments

Comments
 (0)