@@ -61,6 +61,7 @@ plotly_build.plotly <- function(p) {
6161 rapply(x , eval_attr , data = dat , how = " list" ),
6262 class = oldClass(x )
6363 )
64+
6465 # determine trace type (if not specified, can depend on the # of data points)
6566 # note that this should also determine a sensible mode, if appropriate
6667 trace <- verify_type(trace )
@@ -96,8 +97,11 @@ plotly_build.plotly <- function(p) {
9697 isArray <- lapply(Attrs , function (x ) {
9798 tryCatch(identical(x [[" valType" ]], " data_array" ), error = function (e ) FALSE )
9899 })
99- dataArrayAttrs <- names(Attrs )[as.logical(isArray )]
100- tr <- trace [names(trace ) %in% c(npscales(), special_attrs(trace ), dataArrayAttrs )]
100+ # I don't think we ever want mesh3d's data attrs
101+ dataArrayAttrs <- if (identical(trace [[" type" ]], " mesh3d" )) NULL else names(Attrs )[as.logical(isArray )]
102+ # for some reason, text isn't listed as a data array attributein some traces
103+ # I'm looking at you scattergeo...
104+ tr <- trace [names(trace ) %in% c(npscales(), special_attrs(trace ), dataArrayAttrs , " text" )]
101105 # TODO: does it make sense to "train" matrices/2D-tables (e.g. z)?
102106 tr <- tr [vapply(tr , function (x ) is.null(dim(x )), logical (1 ))]
103107 builtData <- tibble :: as_tibble(tr )
@@ -246,6 +250,10 @@ plotly_build.plotly <- function(p) {
246250 }
247251 }
248252
253+ # polar charts don't like null width/height keys
254+ if (is.null(p $ x $ layout [[" height" ]])) p $ x $ layout [[" height" ]] <- NULL
255+ if (is.null(p $ x $ layout [[" width" ]])) p $ x $ layout [[" width" ]] <- NULL
256+
249257 # ensure we get the order of categories correct
250258 # (plotly.js uses the order in which categories appear by default)
251259 p <- populate_categorical_axes(p )
@@ -281,13 +289,13 @@ train_data <- function(data, trace) {
281289 if (inherits(trace , " plotly_segment" )) {
282290 # TODO: this could be faster, more efficient
283291 data $ .plotlyGroupIndex <- seq_len(NROW(data ))
284- data <- gather_(
285- gather_ (data , " tmp " , " x " , c( " x " , " xend " )),
286- " tmp " , " y " , c( " y " , " yend " )
287- )
288- data <- dplyr :: arrange_( data [! names( data ) %in% " tmp " ], " .plotlyGroupIndex " )
289- data <- dplyr :: distinct( data )
290- data <- dplyr :: group_by_(data , " .plotlyGroupIndex" , add = TRUE )
292+ idx <- rep(seq_len(NROW( data )), each = 2 )
293+ dat <- as.data.frame (data [ ! grepl( " ^xend$|^yend " , names( data ))])
294+ dat <- dat [ idx , ]
295+ idx2 <- seq.int( 2 , NROW( dat ), by = 2 )
296+ dat [ idx2 , " x " ] <- data [[ " xend " ]]
297+ dat [ idx2 , " y " ] <- data [[ " yend " ]]
298+ data <- dplyr :: group_by_(dat , " .plotlyGroupIndex" , add = TRUE )
291299 }
292300 # TODO: a lot more geoms!!!
293301 data
@@ -323,8 +331,6 @@ map_size <- function(traces) {
323331 scales :: rescale(s , from = sizeRange , to = traces [[1 ]]$ sizes )
324332 }
325333 if (hasMarker [[i ]]) {
326- # plotly.js
327- sizeI <- rep(sizeI , length.out = max(lengths(traces [[i ]])))
328334 traces [[i ]]$ marker <- modify_list(
329335 list (size = sizeI , sizemode = " area" ),
330336 traces [[i ]]$ marker
@@ -381,8 +387,9 @@ map_color <- function(traces, title = "", na.color = "transparent") {
381387
382388 colorDefaults <- traceColorDefaults()
383389 for (i in which(isConstant )) {
384- # https://github.com/plotly/plotly.js/blob/c83735/src/plots/plots.js#L581
385- col <- color [[i ]] %|| % colorDefaults [[i %% length(colorDefaults )]]
390+ # https://github.com/plotly/plotly.js/blob/c83735/src/plots/plots.js#L58
391+ idx <- i %% length(colorDefaults ) + i %/% length(colorDefaults )
392+ col <- color [[i ]] %|| % colorDefaults [[idx ]]
386393 alpha <- traces [[i ]]$ alpha %|| % 1
387394 rgb <- toRGB(col , alpha )
388395 obj <- if (hasLine [[i ]]) " line" else if (hasMarker [[i ]]) " marker" else if (hasText [[i ]]) " textfont"
@@ -407,7 +414,8 @@ map_color <- function(traces, title = "", na.color = "transparent") {
407414 ncol = 2
408415 )
409416 colorObj <- list (
410- colorbar = list (title = as.character(title ), ticklen = 2 ),
417+ colorbar = Reduce(modify_list , lapply(traces , function (x ) x $ marker [[" colorbar" ]])) %|| %
418+ list (title = as.character(title ), ticklen = 2 ),
411419 cmin = rng [1 ],
412420 cmax = rng [2 ],
413421 colorscale = colorScale ,
@@ -434,12 +442,12 @@ map_color <- function(traces, title = "", na.color = "transparent") {
434442 hasMarker [[i ]] <- TRUE
435443 } else {
436444 # scatter3d supports data arrays for color
437- traces [[i ]]$ line <- modify_list(colorObj , traces [[i ]]$ line )
445+ traces [[i ]][[ " line" ]] <- modify_list(colorObj , traces [[i ]][[ " line" ]] )
438446 traces [[i ]]$ marker $ colorscale <- as_df(traces [[i ]]$ marker $ colorscale )
439447 }
440448 }
441449 if (hasMarker [[i ]]) {
442- traces [[i ]]$ marker <- modify_list(colorObj , traces [[i ]]$ marker )
450+ traces [[i ]][[ " marker" ]] <- modify_list(colorObj , traces [[i ]][[ " marker" ]] )
443451 traces [[i ]]$ marker $ colorscale <- as_df(traces [[i ]]$ marker $ colorscale )
444452 }
445453 if (hasText [[i ]]) {
@@ -462,10 +470,18 @@ map_color <- function(traces, title = "", na.color = "transparent") {
462470 showlegend = FALSE ,
463471 marker = colorObj
464472 )
465- if (" scatter3d" %in% unlist(lapply(traces , " [[" , " type" ))) {
473+ # yay for consistency plotly.js
474+ if (" scatter3d" %in% types ) {
466475 colorBarTrace $ type <- " scatter3d"
467476 colorBarTrace $ z <- range(unlist(lapply(traces , " [[" , " z" )), na.rm = TRUE )
468477 }
478+ if (length(type <- intersect(c(" scattergeo" , " scattermapbox" ), types ))) {
479+ colorBarTrace $ type <- type
480+ colorBarTrace $ lat <- range(unlist(lapply(traces , " [[" , " lat" )), na.rm = TRUE )
481+ colorBarTrace $ lon <- range(unlist(lapply(traces , " [[" , " lon" )), na.rm = TRUE )
482+ colorBarTrace [[" x" ]] <- NULL
483+ colorBarTrace [[" y" ]] <- NULL
484+ }
469485 traces [[length(traces ) + 1 ]] <- structure(colorBarTrace , class = " plotly_colorbar" )
470486 }
471487
@@ -486,7 +502,22 @@ map_color <- function(traces, title = "", na.color = "transparent") {
486502 traces [[i ]][[obj ]] <- modify_list(list (fillcolor = toRGB(rgb , 0.5 )), traces [[i ]][[obj ]])
487503 }
488504 }
489-
505+
506+ # marker.line.color (stroke) inherits from marker.color (color)
507+ # TODO: allow users to control via a `stroke`` argument
508+ # to make consistent, in "filled polygons", color -> fillcolor, stroke -> line.color
509+ for (i in seq_along(color )) {
510+ if (! is.null(traces [[i ]]$ marker $ color )) {
511+ traces [[i ]]$ marker $ line $ color <- traces [[i ]]$ marker $ line $ color %|| % " transparent"
512+ for (j in c(" error_x" , " error_y" )) {
513+ if (! is.null(traces [[i ]][[j ]])) {
514+ traces [[i ]][[j ]][[" color" ]] <- traces [[i ]][[j ]][[" color" ]] %|| %
515+ traces [[i ]]$ marker [[" color" ]]
516+ }
517+ }
518+ }
519+ }
520+
490521 traces
491522}
492523
0 commit comments