2222# ' hang during image generating are skipped.
2323# ' @export
2424# ' @author Carson Sievert
25+ # ' @seealso [orca_serve]
2526# ' @examples
2627# '
2728# ' \dontrun{
@@ -35,13 +36,7 @@ orca <- function(p, file = "plot.png", format = tools::file_ext(file),
3536 parallel_limit = NULL , verbose = FALSE , debug = FALSE ,
3637 safe = FALSE ) {
3738
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- }
39+ orca_available()
4540
4641 b <- plotly_build(p )
4742
@@ -68,8 +63,156 @@ orca <- function(p, file = "plot.png", format = tools::file_ext(file),
6863 if (! is.null(parallel_limit )) args <- c(args , " --parallel-limit" , parallel_limit )
6964 if (! is.null(tryNULL(mapbox_token()))) args <- c(args , " --mapbox-access-token" , mapbox_token())
7065 if (isTRUE(mathjax )) args <- c(args , " --mathjax" , file.path(mathjax_path(), " MathJax.js" ))
71-
66+
7267 # TODO: point to local topojson? Should this only work if plot_geo(standalone = TRUE)?
7368 try_library(" processx" , " orca" )
7469 invisible (processx :: run(" orca" , args , echo = TRUE , spinner = TRUE ))
7570}
71+
72+ # ' Orca image export server
73+ # '
74+ # ' @description Compared to [orca], [orca_serve] is more efficient at exporting many plotly
75+ # ' graphs because the former must startup/shutdown an external process for every image.
76+ # ' The server (background) process is launched upon initialization of a [orca_serve] class
77+ # ' (i.e., when the `new()` method is called). The `export()` method accepts any valid plotly
78+ # ' object as input and spits out an image file to disk. To kill the background server process,
79+ # ' use `close()`.
80+ # '
81+ # ' @section Constructor:
82+ # '
83+ # ' \code{orca_serve$new(port = 5151)}
84+ # '
85+ # ' \describe{
86+ # ' \item{\code{port}}{Sets the server's port number.}
87+ # ' \item{\code{mathjax}}{
88+ # ' whether or not to include MathJax (required to render [TeX]).
89+ # ' If `TRUE`, the PLOTLY_MATHJAX_PATH environment variable must be set and point
90+ # ' to the location of MathJax (this variable is also used to render [TeX] in
91+ # ' interactive graphs, see [config]).
92+ # ' }
93+ # ' \item{\code{safe}}{
94+ # ' Turns on safe mode: where figures likely to make browser window hang during image generating are skipped.
95+ # ' }
96+ # ' \item{\code{request_limit}}{
97+ # ' Sets a request limit that makes orca exit when reached.
98+ # ' }
99+ # ' \item{\code{keep_alive}}{
100+ # ' Turn on keep alive mode where orca will (try to) relaunch server if process unexpectedly exits.
101+ # ' }
102+ # ' \item{\code{window_max_number}}{
103+ # ' Sets maximum number of browser windows the server can keep open at a given time.
104+ # ' }
105+ # ' \item{\code{quiet}}{Suppress all logging info.}
106+ # ' \item{\code{debug}}{Starts app in debug mode.}
107+ # ' }
108+ # '
109+ # ' @export
110+ # ' @author Carson Sievert
111+ # ' @seealso [orca]
112+ # ' @examples
113+ # '
114+ # ' \dontrun{
115+ # ' # launch the server
116+ # ' server <- orca_serve$new()
117+ # '
118+ # ' # export as many graphs as you'd like
119+ # ' server$export(qplot(1:10), "test1.pdf")
120+ # ' server$export(plot_ly(x = 1:10, y = 1:10), "test2.pdf")
121+ # '
122+ # ' # the underlying process is exposed as a field, so you
123+ # ' # have full control over the external process
124+ # ' server$process$is_alive()
125+ # '
126+ # ' # convenience method for closing down the server
127+ # ' server$close()
128+ # '
129+ # ' # remove the exported files from disk
130+ # ' unlink("test1.pdf")
131+ # ' unlink("test2.pdf")
132+ # ' }
133+ # '
134+ orca_serve <- R6 :: R6Class(
135+ " orcaServe" ,
136+ public = list (
137+ process = NULL ,
138+ port = NULL ,
139+
140+ initialize = function (port = 5151 , mathjax = FALSE , safe = FALSE , request_limit = NULL ,
141+ keep_alive = TRUE , window_max_number = NULL , quiet = FALSE ,
142+ debug = FALSE , ... ) {
143+
144+ # make sure we have the required infrastructure
145+ orca_available()
146+ try_library(" processx" , " orca" )
147+
148+ # use main bundle since any plot can be thrown at the server
149+ plotlyjs <- plotlyMainBundle()
150+ plotlyjs_file <- file.path(plotlyjs $ src $ file , plotlyjs $ script )
151+
152+ args <- c(
153+ " serve" ,
154+ " -p" , port ,
155+ " --plotly" , plotlyjs_file ,
156+ if (safe ) " --safe-mode" ,
157+ if (orca_version() > = " 1.1.1" ) " --graph-only" ,
158+ if (keep_alive ) " --keep-alive" ,
159+ if (debug ) " --debug" ,
160+ if (quiet ) " --quiet"
161+ )
162+
163+ if (! is.null(request_limit ))
164+ args <- c(args , " --request-limit" , request_limit )
165+
166+ if (! is.null(window_max_number ))
167+ args <- c(args , " --window-max-number" , window_max_number )
168+
169+ if (! is.null(tryNULL(mapbox_token())))
170+ args <- c(args , " --mapbox-access-token" , mapbox_token())
171+
172+ if (isTRUE(mathjax ))
173+ args <- c(args , " --mathjax" , file.path(mathjax_path(), " MathJax.js" ))
174+
175+ self $ process <- processx :: process $ new(" orca" , args , ... )
176+ self $ port <- port
177+ },
178+ export = function (p , file = " plot.png" , format = tools :: file_ext(file ), width = 1000 , height = 500 ) {
179+
180+ # request/response model works similarly to plotly_IMAGE()
181+ bod <- list (
182+ figure = plotly_build(p )$ x [c(" data" , " layout" )],
183+ format = format ,
184+ width = width ,
185+ height = height ,
186+ scale = scale
187+ )
188+ res <- httr :: POST(
189+ paste0(" http://localhost:" , self $ port ),
190+ body = to_JSON(bod )
191+ )
192+ httr :: stop_for_status(res )
193+ httr :: warn_for_status(res )
194+ con <- httr :: content(res , as = " raw" )
195+ writeBin(con , file )
196+ },
197+ close = function () {
198+ self $ process $ kill()
199+ }
200+ )
201+ )
202+
203+ orca_available <- function () {
204+ if (Sys.which(" orca" ) == " " ) {
205+ stop(
206+ " The orca command-line utility is required for this functionality.\n\n " ,
207+ " Please follow the installation instructions here -- https://github.com/plotly/orca#installation" ,
208+ call. = FALSE
209+ )
210+ }
211+
212+ TRUE
213+ }
214+
215+ orca_version <- function () {
216+ orca_available()
217+ as.package_version(system(" orca --version" , intern = TRUE ))
218+ }
0 commit comments