@@ -80,6 +80,14 @@ plotly_build.plotly <- function(p) {
8080 rapply(x , eval_attr , data = dat , how = " list" ),
8181 class = oldClass(x )
8282 )
83+ # if appropriate, tack on a group index
84+ grps <- tryCatch(
85+ as.character(dplyr :: groups(dat )),
86+ error = function (e ) character (0 )
87+ )
88+ if (length(grps ) && any(lengths(trace ) == NROW(dat ))) {
89+ trace [[" .plotlyGroupIndex" ]] <- interaction(dat [, grps , drop = F ])
90+ }
8391
8492 # determine trace type (if not specified, can depend on the # of data points)
8593 # note that this should also determine a sensible mode, if appropriate
@@ -118,13 +126,16 @@ plotly_build.plotly <- function(p) {
118126 })
119127 # I don't think we ever want mesh3d's data attrs
120128 dataArrayAttrs <- if (identical(trace [[" type" ]], " mesh3d" )) NULL else names(Attrs )[as.logical(isArray )]
121- # for some reason, text isn't listed as a data array attributein some traces
122- # I'm looking at you scattergeo...
123- tr <- trace [names(trace ) %in% c(npscales(), special_attrs(trace ), dataArrayAttrs , " text" )]
129+ allAttrs <- c(
130+ dataArrayAttrs , special_attrs(trace ), npscales(), " .plotlyGroupIndex" ,
131+ # for some reason, text isn't listed as a data array in some traces
132+ # I'm looking at you scattergeo...
133+ " text"
134+ )
135+ tr <- trace [names(trace ) %in% allAttrs ]
124136 # TODO: does it make sense to "train" matrices/2D-tables (e.g. z)?
125137 tr <- tr [vapply(tr , function (x ) is.null(dim(x )) && is.atomic(x ), logical (1 ))]
126138 builtData <- tibble :: as_tibble(tr )
127-
128139 # avoid clobbering I() (i.e., variables that shouldn't be scaled)
129140 for (i in seq_along(tr )) {
130141 if (inherits(tr [[i ]], " AsIs" )) builtData [[i ]] <- I(builtData [[i ]])
@@ -139,7 +150,7 @@ plotly_build.plotly <- function(p) {
139150 ! isAsIs & isDiscrete & names(builtData ) %in% c(" symbol" , " color" )
140151 if (any(isSplit )) {
141152 paste2 <- function (x , y ) paste(x , y , sep = " <br>" )
142- builtData $ .plotlyTraceIndex <- Reduce(paste2 , builtData [isSplit ])
153+ builtData [[ " .plotlyTraceIndex" ]] <- Reduce(paste2 , builtData [isSplit ])
143154 }
144155 # Build the index used to determine grouping (later on, NAs are inserted
145156 # via group2NA() to create the groups). This is done in 3 parts:
@@ -158,30 +169,23 @@ plotly_build.plotly <- function(p) {
158169 if (any(! isComplete ) && ! hasGrp ) {
159170 warning(" Ignoring " , sum(! isComplete ), " observations" , call. = FALSE )
160171 }
161- builtData $ .plotlyGroupIndex <- cumsum(! isComplete )
172+ builtData [[ " .plotlyMissingIndex " ]] <- cumsum(! isComplete )
162173 builtData <- builtData [isComplete , ]
163- grps <- tryCatch(
164- as.character(dplyr :: groups(dat )),
165- error = function (e ) character (0 )
166- )
167- if (length(grps ) && hasGrp ) {
168- if (isTRUE(trace [[" connectgaps" ]])) {
169- stop(
170- " Can't use connectgaps=TRUE when data has group(s)." ,
171- call. = FALSE
172- )
173- }
174- builtData $ .plotlyGroupIndex <- interaction(
175- interaction(dat [isComplete , grps , drop = FALSE ]),
176- builtData $ .plotlyGroupIndex %|| % " "
174+ if (length(grps ) && hasGrp && isTRUE(trace [[" connectgaps" ]])) {
175+ stop(
176+ " Can't use connectgaps=TRUE when data has group(s)." , call. = FALSE
177177 )
178178 }
179-
179+ builtData [[" .plotlyGroupIndex" ]] <- interaction(
180+ builtData [[" .plotlyGroupIndex" ]] %|| % " " ,
181+ builtData [[" .plotlyMissingIndex" ]]
182+ )
180183 builtData <- arrange_safe(builtData ,
181- c(" .plotlyTraceIndex" , " .plotlyGroupIndex" , if (inherits(trace , " plotly_line" )) " x" )
184+ c(" .plotlyTraceIndex" , " .plotlyGroupIndex" ,
185+ if (inherits(trace , " plotly_line" )) " x" )
182186 )
183187 builtData <- train_data(builtData , trace )
184- trace $ .plotlyVariableMapping <- names(builtData )
188+ trace [[ " .plotlyVariableMapping" ]] <- names(builtData )
185189
186190 # copy over to the trace data
187191 for (i in names(builtData )) {
@@ -191,7 +195,6 @@ plotly_build.plotly <- function(p) {
191195
192196 # TODO: provide a better way to clean up "high-level" attrs
193197 trace [c(" ymin" , " ymax" , " yend" , " xend" )] <- NULL
194-
195198 trace [lengths(trace ) > 0 ]
196199
197200 }, p $ x $ attrs , names2(p $ x $ attrs ))
@@ -235,7 +238,8 @@ plotly_build.plotly <- function(p) {
235238 for (i in seq_along(traces )) {
236239 mappingAttrs <- c(
237240 " alpha" , npscales(), paste0(npscales(), " s" ),
238- " .plotlyGroupIndex" , " .plotlyTraceIndex" , " .plotlyVariableMapping"
241+ " .plotlyGroupIndex" , " .plotlyMissingIndex" ,
242+ " .plotlyTraceIndex" , " .plotlyVariableMapping"
239243 )
240244 for (j in mappingAttrs ) {
241245 traces [[i ]][[j ]] <- NULL
@@ -246,8 +250,6 @@ plotly_build.plotly <- function(p) {
246250 # (like figures pulled from a plotly server)
247251 p $ x $ data <- setNames(c(p $ x $ data , traces ), NULL )
248252
249-
250-
251253 # get rid of data -> vis mapping stuff
252254 p $ x [c(" visdat" , " cur_data" , " attrs" )] <- NULL
253255
0 commit comments