Skip to content

Commit 6a08410

Browse files
committed
merge with master
2 parents cac9b55 + 417a404 commit 6a08410

File tree

355 files changed

+3618
-686
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

355 files changed

+3618
-686
lines changed

.travis.yml

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,36 @@ language: R
22
cache: packages
33
sudo: true
44
dist: trusty
5-
6-
r:
7-
- oldrel
8-
- release
9-
- devel
10-
5+
warnings_are_errors: false
6+
7+
matrix:
8+
include:
9+
- r:
10+
- devel
11+
- oldrel
12+
- release
13+
# run visual tests
14+
# TODO: push the svg files somewhere on after_failure?
15+
before_script: docker run -e MAPBOX_TOKEN=$MAPBOX_TOKEN -v $(pwd):/home/plotly --privileged cpsievert/plotly-orca R -e "devtools::install_deps('/home/plotly', dep = T); res <- devtools::test('/home/plotly', reporter='summary'); df <- as.data.frame(res); if (sum(df\$failed) > 0 || any(df\$error)) q(status=1)"
16+
17+
1118
env:
1219
global:
13-
- _R_CHECK_FORCE_SUGGESTS_=false R_PKG="$(basename $TRAVIS_REPO_SLUG)"
20+
# don't treat missing suggested packages as error
21+
- _R_CHECK_FORCE_SUGGESTS_=false
1422
# plotly_api_key (for posting to plot.ly)
1523
- secure: "WsvmMHN4YVhnk0bLRE04APcLbs5s4vWKSHjEdU0bPXd0xdMTzZeP5D7pxyF1983C+P5LpSnGHv4dgwLMBkNzxJwBR7/Ta7lfO1akYILWwxib+1DVbCqUH5Z4Ba1FSCQptIrLNGR3P7+0Lem4hEhqKdPKltFnxhnXO0Y+MeG71IQ="
16-
# GITHUB_PAT (for pushing to plotly-test-table)
17-
- secure: "Ar5FRxsMJHxb8CQmmsoFx5Tm6ncFvF3LHtAMtfcOE2e9JAbXQ471PGzOMM7yudGa2vVuQJBpB6bWktuE30J68MQxgRmxeaJYmOp+ePqyW80y/zEa2P3R4//eb9Rif2lmsmaqz7HtVfX4xr3YX4N+ZjfyI8TFt5Phue18tXeMoJw="
1824
# MAPBOX_TOKEN (for testing `plot_mapbox()`)
1925
- secure: "QPBEqtLRdwb4ablJORzD0JdCT9ESe3nNdIehM1oxfcNKfpSdf2OFxH3TkeYY1nMpv0mLxiMNTy6xcj9Yk5MaaBCIA0P7q6OdZv9ruzQD1j3g84gP45KwBilbPGjb+/EvOS0fM25vR/pAmA8IyoUfPC2J8HwiNnW8DYdt/hJOJ9A="
2026

21-
# installing Rserve from source requires non-standard R build (--enable-R-shlib)
22-
r_binary_packages:
23-
- rserve
24-
25-
r_packages:
26-
- devtools
27-
- quantreg
28-
29-
r_github_packages:
30-
- tidyverse/ggplot2
31-
3227
before_install:
33-
# mainly for installing sf (which requires units/rgeos/rgdal)
28+
- echo "Sys.setenv('plotly_username' = 'cpsievert')" > ~/.Rprofile
29+
# sf system dependencies
3430
- sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable --yes
3531
- sudo apt-get --yes --force-yes update -qq
3632
- sudo apt-get install --yes libudunits2-dev libproj-dev libgeos-dev libgdal-dev
33+
# make sure R pkgs are upt-to-date
3734
- Rscript -e 'update.packages(ask = FALSE)'
3835

39-
before_script:
40-
- git config --global user.email "[email protected]"
41-
- git config --global user.name "cpsievert"
42-
- echo "Sys.setenv('plotly_username' = 'cpsievert')" > ~/.Rprofile
43-
- git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table
44-
- cd ..; rm -f *.tar.gz; R CMD build $R_PKG
45-
46-
script:
47-
# run R CMD check on the non-pull request build
48-
- sh -c "if [ '$TRAVIS_PULL_REQUEST' = 'false' ]; then R CMD check ${R_PKG}_*.tar.gz --no-manual; fi"
49-
# we do some fancy stuff on the pull request build that confuses R CMD check
50-
- sh -c "if [ '$TRAVIS_PULL_REQUEST' != 'false' ]; then Rscript -e 'source(\"plotly/tests/testthat.R\", chdir = T)'; fi"
51-
52-
after_success:
53-
- cd plotly-test-table
54-
- Rscript ../plotly/inst/build-push-comment.R
36+
# work around temporary travis + R 3.5 bug
37+
r_packages: devtools

CONTRIBUTING.md

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,24 @@ See the [opening issues template](https://github.com/ropensci/plotly/blob/master
66

77
## Development guidelines
88

9-
If you'd like to contribute changes to plotly, we use [the GitHub flow](https://guides.github.com/introduction/flow/index.html) for proposing, submitting, reviewing, and accepting changes. If you haven't done this before, Hadley Wickham provides a nice overview of git (<http://r-pkgs.had.co.nz/git.html>), as well as best practices for submitting pull requests (<http://r-pkgs.had.co.nz/git.html#pr-make>). We also recommend using his style guide when writing code (<http://adv-r.had.co.nz/Style.html>).
9+
If you'd like to contribute changes to plotly, we use [the GitHub flow](https://guides.github.com/introduction/flow/index.html) for proposing, submitting, reviewing, and accepting changes. If you aren't familiar with git and/or GitHub, we recommend studying these excellent free resources by [Hadley Wickham](http://r-pkgs.had.co.nz/git.html) and [Jenny Bryan](http://happygitwithr.com). We also prefer R coding style that adheres to <http://style.tidyverse.org/>.
1010

11-
If your pull request fixes a bug, or implements a new feature, it's a good idea to write a test (<http://r-pkgs.had.co.nz/tests.html>) to demonstrate it's working. If you'd like to closely simulate the tests that run when you submit your pull request, open R under your local plotly git repo, then do the following:
11+
If your pull request fixes a bug and/or implements a new feature, please [write a test via testthat](http://r-pkgs.had.co.nz/tests.html) to demonstrate it's working. Tests should generally check the return value of `plotly_build()`, but can also use **vdiffr**'s `expect_doppelganger()` to add a visual test! By default, `devtools::tests()` won't run the visual tests, but you *can* run visual tests on your machine via `Sys.setenv("VDIFFR" = "true"); devtools::test()`. That being said, false positives are likely to occur simply due to superfluous differences in your system environment, so we recommend running visual tests via docker.
1212

13-
```r
14-
# the pull request number is arbitrary when running locally
15-
Sys.setenv('TRAVIS_PULL_REQUEST' = '1')
16-
Sys.setenv('TRAVIS_COMMIT' = substr(system('git rev-parse HEAD', intern = T), 1, 7))
17-
devtools::load_all(); source('tests/testthat.R', chdir = TRUE)
18-
```
13+
### Running visual tests via docker
1914

20-
You can also build a ggplot2/plotly comparison table. To do so, you'll first need to clone the [plotly-test-table](https://github.com/cpsievert/plotly-test-table) repo.
15+
To ensure a consistent and reproducible environment, visual tests should be run against the [cpsievert/plotly-orca](https://hub.docker.com/r/cpsievert/plotly-orca/) docker image. If you add a new visual test and/or expect any differences, run a container like so:
2116

2217
```shell
23-
$ git clone https://github.com/cpsievert/plotly-test-table.git ../plotly-test-table
18+
git clone https://github.com/ropensci/plotly.git
19+
cd plotly
20+
docker run -v $(pwd):/home/plotly --privileged -p 3838:3838 cpsievert/plotly-orca
2421
```
2522

26-
Then, from R:
23+
This will launch a shiny app for inspecting and validating any visual differences. To see the shiny app, open your browser to <http://0.0.0.0/3838>. If there are differences that look 'good', you should validate them via the shiny app. This will automatically copy over the new "baseline" figures over to your host machine (so that you can git add/commit/push the new baselines). If, for some reason, you want to just run the visual tests to see if they'll pass, do:
2724

28-
```r
29-
Sys.setenv('PLOTLY_TABLE' = 'TRUE')
30-
devtools::load_all(); source('tests/testthat.R', chdir = TRUE)
25+
```shell
26+
docker run -e VMODE="ci" -v $(pwd):/home/plotly --privileged cpsievert/plotly-orca
3127
```
3228

3329
## Code of Conduct

DESCRIPTION

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Imports:
3333
viridisLite,
3434
base64enc,
3535
htmltools,
36-
htmlwidgets (>= 1.2),
36+
htmlwidgets (>= 1.3),
3737
tidyr,
3838
hexbin,
3939
RColorBrewer,
@@ -56,8 +56,7 @@ Suggests:
5656
shiny (>= 1.1.0),
5757
curl,
5858
rmarkdown,
59-
Rserve,
60-
RSclient,
59+
vdiffr,
6160
Cairo,
6261
broom,
6362
webshot,

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ export(mutate)
153153
export(mutate_)
154154
export(offline)
155155
export(orca)
156+
export(orca_serve)
156157
export(partial_bundle)
157158
export(plot_dendro)
158159
export(plot_geo)
@@ -244,6 +245,7 @@ importFrom(httr,add_headers)
244245
importFrom(httr,config)
245246
importFrom(httr,content)
246247
importFrom(httr,stop_for_status)
248+
importFrom(httr,warn_for_status)
247249
importFrom(jsonlite,fromJSON)
248250
importFrom(jsonlite,toJSON)
249251
importFrom(lazyeval,all_dots)

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# 4.8.0.9000
22

3+
## NEW FEATURES
4+
5+
* The `orca_serve()` function was added for efficient exporting of many plotly graphs. For examples, see `help(orca_serve)`.
6+
* The `orca()` function gains new arguments `more_args` and `...` for finer control over the underlying system commands.
7+
38
## IMPROVEMENTS
49

510
* Upgraded to plotly.js v1.40.1.

R/imports.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#' @importFrom tidyr unnest
77
#' @importFrom viridisLite viridis
88
#' @importFrom jsonlite toJSON fromJSON
9-
#' @importFrom httr GET POST PATCH content config add_headers stop_for_status
9+
#' @importFrom httr GET POST PATCH content config add_headers stop_for_status warn_for_status
1010
#' @importFrom htmlwidgets createWidget sizingPolicy saveWidget onRender prependContent
1111
#' @importFrom lazyeval f_eval is_formula all_dots is_lang f_new
1212
#' @importFrom tibble as_tibble

R/orca.R

Lines changed: 158 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
#' Static image export via orca
1+
#' Static image exporting
22
#'
3-
#' The function makes a system call to the orca command-line utility,
4-
#' see the installation instructions [here](https://github.com/plotly/orca#installation)
3+
#' Export plotly objects to static images (e.g., pdf, png, jpeg, svg, etc) via the
4+
#' [orca command-line utility](https://github.com/plotly/orca#installation).
5+
#'
6+
#' The `orca()` function is designed for exporting one plotly graph whereas `orca_serve()`
7+
#' is meant for exporting many graphs at once. The former starts and stops an external (nodejs)
8+
#' process everytime it is called whereas the latter starts up a process when called, then
9+
#' returns an `export()` method for exporting graphs as well as a `close()` method for stopping
10+
#' the external (background) process.
511
#'
612
#' @param p a plotly object.
713
#' @param file output filename.
@@ -20,28 +26,48 @@
2026
#' @param debug Starts app in debug mode and turn on verbose logs on stdout.
2127
#' @param safe Turns on safe mode: where figures likely to make browser window
2228
#' hang during image generating are skipped.
29+
#' @param more_args additional arguments to pass along to system command. This is useful
30+
#' for specifying display and/or electron options, such as `--enable-webgl` or `--disable-gpu`.
31+
#' @param ... for `orca()`, additional arguments passed along to `processx::run`. For
32+
#' `orca_serve()`, additional arguments passed along to `processx::process`.
2333
#' @export
2434
#' @author Carson Sievert
35+
#' @md
36+
#' @rdname orca
2537
#' @examples
2638
#'
2739
#' \dontrun{
40+
#' # NOTE: in a headless environment, you may need to set `more_args="--enable-webgl"`
41+
#' # to export webgl correctly
2842
#' p <- plot_ly(z = ~volcano) %>% add_surface()
2943
#' orca(p, "surface-plot.svg")
44+
#'
45+
#' #' # launch the server
46+
#' server <- orca_serve()
47+
#'
48+
#' # export as many graphs as you'd like
49+
#' server$export(qplot(1:10), "test1.pdf")
50+
#' server$export(plot_ly(x = 1:10, y = 1:10), "test2.pdf")
51+
#'
52+
#' # the underlying process is exposed as a field, so you
53+
#' # have full control over the external process
54+
#' server$process$is_alive()
55+
#'
56+
#' # convenience method for closing down the server
57+
#' server$close()
58+
#'
59+
#' # remove the exported files from disk
60+
#' unlink("test1.pdf")
61+
#' unlink("test2.pdf")
3062
#' }
3163
#'
3264

3365
orca <- function(p, file = "plot.png", format = tools::file_ext(file),
3466
scale = NULL, width = NULL, height = NULL, mathjax = FALSE,
3567
parallel_limit = NULL, verbose = FALSE, debug = FALSE,
36-
safe = FALSE) {
68+
safe = FALSE, more_args = NULL, ...) {
3769

38-
if (Sys.which("orca") == "") {
39-
stop(
40-
"The orca command-line utility is required to use the `orca()` function.\n\n",
41-
"Follow the installation instructions here -- https://github.com/plotly/orca#installation",
42-
call. = FALSE
43-
)
44-
}
70+
orca_available()
4571

4672
b <- plotly_build(p)
4773

@@ -59,7 +85,8 @@ orca <- function(p, file = "plot.png", format = tools::file_ext(file),
5985
"--plotlyjs", plotlyjs_file,
6086
if (debug) "--debug",
6187
if (verbose) "--verbose",
62-
if (safe) "--safe-mode"
88+
if (safe) "--safe-mode",
89+
more_args
6390
)
6491

6592
if (!is.null(scale)) args <- c(args, "--scale", scale)
@@ -68,8 +95,125 @@ orca <- function(p, file = "plot.png", format = tools::file_ext(file),
6895
if (!is.null(parallel_limit)) args <- c(args, "--parallel-limit", parallel_limit)
6996
if (!is.null(tryNULL(mapbox_token()))) args <- c(args, "--mapbox-access-token", mapbox_token())
7097
if (isTRUE(mathjax)) args <- c(args, "--mathjax", file.path(mathjax_path(), "MathJax.js"))
71-
98+
7299
# TODO: point to local topojson? Should this only work if plot_geo(standalone = TRUE)?
73100
try_library("processx", "orca")
74-
invisible(processx::run("orca", args, echo = TRUE, spinner = TRUE))
101+
invisible(processx::run("orca", args, echo = TRUE, spinner = TRUE, ...))
102+
}
103+
104+
#' Orca image export server
105+
#'
106+
#' @inheritParams orca
107+
#' @param port Sets the server's port number.
108+
#' @param keep_alive Turn on keep alive mode where orca will (try to) relaunch server if process unexpectedly exits.
109+
#' @param window_max_number Sets maximum number of browser windows the server can keep open at a given time.
110+
#' @param request_limit Sets a request limit that makes orca exit when reached.
111+
#' @param quiet Suppress all logging info.
112+
#'
113+
#' @section Methods:
114+
#'
115+
#' The `orca_serve()` function returns an object with two methods:
116+
#'
117+
#' \describe{
118+
#' \item{\code{export(p, file = "plot.png", format = tools::file_ext(file), scale = NULL, width = NULL, height = NULL)}}{
119+
#' Export a static image of a plotly graph. Arguments found here are the same as those found in `orca()`
120+
#' }
121+
#' \item{\code{close()}}{Close down the orca server and kill the underlying node process.}
122+
#' }
123+
#'
124+
#' @section Fields:
125+
#'
126+
#' The `orca_serve()` function returns an object with two fields:
127+
#'
128+
#' \describe{
129+
#' \item{\code{port}}{The port number that the server is listening to.}
130+
#' \item{\code{process}}{An R6 class for controlling and querying the underlying node process.}
131+
#' }
132+
#'
133+
#' @export
134+
#' @rdname orca
135+
136+
orca_serve <- function(port = 5151, mathjax = FALSE, safe = FALSE, request_limit = NULL,
137+
keep_alive = TRUE, window_max_number = NULL, quiet = FALSE,
138+
debug = FALSE, more_args = NULL, ...) {
139+
140+
# make sure we have the required infrastructure
141+
orca_available()
142+
try_library("processx", "orca_serve")
143+
144+
# use main bundle since any plot can be thrown at the server
145+
plotlyjs <- plotlyMainBundle()
146+
plotlyjs_file <- file.path(plotlyjs$src$file, plotlyjs$script)
147+
148+
args <- c(
149+
"serve",
150+
"-p", port,
151+
"--plotly", plotlyjs_file,
152+
if (safe) "--safe-mode",
153+
if (orca_version() >= "1.1.1") "--graph-only",
154+
if (keep_alive) "--keep-alive",
155+
if (debug) "--debug",
156+
if (quiet) "--quiet",
157+
more_args
158+
)
159+
160+
if (!is.null(request_limit))
161+
args <- c(args, "--request-limit", request_limit)
162+
163+
if (!is.null(window_max_number))
164+
args <- c(args, "--window-max-number", window_max_number)
165+
166+
if (!is.null(tryNULL(mapbox_token())))
167+
args <- c(args, "--mapbox-access-token", mapbox_token())
168+
169+
if (isTRUE(mathjax))
170+
args <- c(args, "--mathjax", file.path(mathjax_path(), "MathJax.js"))
171+
172+
process <- processx::process$new("orca", args, ...)
173+
174+
list(
175+
port = port,
176+
process = process,
177+
close = function() process$kill(),
178+
export = function(p, file = "plot.png", format = tools::file_ext(file), scale = NULL, width = NULL, height = NULL) {
179+
# request/response model works similarly to plotly_IMAGE()
180+
bod <- list(
181+
figure = plotly_build(p)$x[c("data", "layout")],
182+
format = format,
183+
width = width,
184+
height = height,
185+
scale = scale
186+
)
187+
res <- httr::POST(
188+
paste0("http://127.0.0.1:", port),
189+
body = to_JSON(bod)
190+
)
191+
httr::stop_for_status(res)
192+
httr::warn_for_status(res)
193+
con <- httr::content(res, as = "raw")
194+
writeBin(con, file)
195+
}
196+
)
197+
}
198+
199+
200+
orca_available <- function() {
201+
if (Sys.which("orca") == "") {
202+
stop(
203+
"The orca command-line utility is required for this functionality.\n\n",
204+
"Please follow the installation instructions here -- https://github.com/plotly/orca#installation",
205+
call. = FALSE
206+
)
207+
}
208+
209+
TRUE
210+
}
211+
212+
orca_version <- function() {
213+
orca_available()
214+
# default to initial release if we can't correctly parse version
215+
tryCatch(
216+
as.package_version(system("orca --version", intern = TRUE)),
217+
error = function(e) "1.0.0"
218+
)
75219
}

R/style.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ style <- function(p, ..., traces = NULL) {
6262
}
6363

6464
#' @param path character vector of path elements: c("marker", "line", "size")
65+
trace_replace <- function(trace, path, value) {
6566
if (length(path) == 0) return(trace)
6667
if (length(path == 1)) {
6768
trace[[path]] <- value

demo/crosstalk-highlight-leaflet.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ library(htmltools)
77
# leaflet should respect these "global" highlight() options
88
options(opacityDim = 0.5)
99

10-
sd <- crosstalk_unit(quakes)
10+
sd <- highlight_key(quakes)
1111

1212
p <- plot_ly(sd, x = ~depth, y = ~mag) %>%
1313
add_markers(alpha = 0.5) %>%

0 commit comments

Comments
 (0)