@@ -69,6 +69,7 @@ gg2list <- function(p){
69
69
}
70
70
# Always use identity size scale so that plot.ly gets the real
71
71
# units for the size variables.
72
+ original.p <- p
72
73
p <- tryCatch({
73
74
# this will be an error for discrete variables.
74
75
suppressMessages({
@@ -117,7 +118,8 @@ gg2list <- function(p){
117
118
ggsizemin <- min(unlist(sizerange ))
118
119
ggsizemax <- max(unlist(sizerange ))
119
120
}
120
-
121
+
122
+ layer.legends <- list ()
121
123
for (i in seq_along(built $ plot $ layers )){
122
124
# This is the layer from the original ggplot object.
123
125
L <- p $ layers [[i ]]
@@ -134,14 +136,14 @@ gg2list <- function(p){
134
136
# sent to plotly as characters, not as numeric data (which is
135
137
# what ggplot_build gives us).
136
138
misc <- list ()
137
- for (a in c(" fill" , " colour" , " x" , " y" )){
139
+ for (a in c(" fill" , " colour" , " x" , " y" , " size " )){
138
140
for (data.type in c(" continuous" , " date" , " datetime" , " discrete" )){
139
141
fun.name <- sprintf(" scale_%s_%s" , a , data.type )
140
142
misc.name <- paste0(" is." , data.type )
141
143
misc [[misc.name ]][[a ]] <- tryCatch({
142
144
fun <- get(fun.name )
143
145
suppressMessages({
144
- with.scale <- p + fun()
146
+ with.scale <- original.p + fun()
145
147
})
146
148
ggplot_build(with.scale )
147
149
TRUE
@@ -152,13 +154,16 @@ gg2list <- function(p){
152
154
}
153
155
154
156
# scales are needed for legend ordering.
157
+ misc $ breaks <- list ()
155
158
for (sc in p $ scales $ scales ){
156
- a <- sc $ aesthetics
157
- if (length(a ) == 1 ){
159
+ a.vec <- sc $ aesthetics
160
+ default.breaks <- inherits(sc $ breaks , " waiver" )
161
+ if (length(a.vec ) == 1 && (! default.breaks ) ) {
162
+ # TODO: generalize for x/y scales too.
158
163
br <- sc $ breaks
159
164
ranks <- seq_along(br )
160
165
names(ranks ) <- br
161
- misc $ breaks [[sc $ aesthetics ]] <- ranks
166
+ misc $ breaks [[a.vec ]] <- ranks
162
167
}
163
168
# # store if this is a reverse scale so we can undo that later.
164
169
if (is.character(sc $ trans $ name )){
@@ -205,6 +210,10 @@ gg2list <- function(p){
205
210
206
211
# This extracts essential info for this geom/layer.
207
212
traces <- layer2traces(L , df , misc )
213
+
214
+ possible.legends <- markLegends [[L $ geom $ objname ]]
215
+ actual.legends <- possible.legends [possible.legends %in% names(L $ mapping )]
216
+ layer.legends [[paste(i )]] <- actual.legends
208
217
209
218
# Do we really need to coord_transform?
210
219
# g$data <- ggplot2:::coord_transform(built$plot$coord, g$data,
@@ -308,17 +317,33 @@ gg2list <- function(p){
308
317
ax.list $ tickangle <- - tick.text $ angle
309
318
}
310
319
ax.list $ tickfont <- theme2font(tick.text )
320
+
321
+ # # determine axis type first, since this information is used later
322
+ # # (trace.order.list is only used for type=category).
323
+ title.text <- e(s(" axis.title.%s" ))
324
+ ax.list $ titlefont <- theme2font(title.text )
325
+ ax.list $ type <- if (misc $ is.continuous [[xy ]]){
326
+ " linear"
327
+ } else if (misc $ is.discrete [[xy ]]){
328
+ " category"
329
+ } else if (misc $ is.date [[xy ]] || misc $ is.datetime [[xy ]]){
330
+ " date"
331
+ } else {
332
+ stop(" unrecognized data type for " , xy , " axis" )
333
+ }
311
334
312
335
# Translate axes labels.
313
336
scale.i <- which(p $ scales $ find(xy ))
314
337
ax.list $ title <- if (length(scale.i )){
315
338
sc <- p $ scales $ scales [[scale.i ]]
316
- trace.order.list [[xy ]] <- sc $ limits
317
- if (is.character(sc $ breaks )){
318
- if (is.character(sc $ labels )){
319
- trace.name.map [sc $ breaks ] <- sc $ labels
339
+ if (ax.list $ type == " category" ){
340
+ trace.order.list [[xy ]] <- sc $ limits
341
+ if (is.character(sc $ breaks )){
342
+ if (is.character(sc $ labels )){
343
+ trace.name.map [sc $ breaks ] <- sc $ labels
344
+ }
345
+ # #TODO: if(is.function(sc$labels)){
320
346
}
321
- # #TODO: if(is.function(sc$labels)){
322
347
}
323
348
if (is.null(sc $ breaks )) {
324
349
ax.list $ showticklabels <- FALSE
@@ -354,18 +379,6 @@ gg2list <- function(p){
354
379
p $ labels [[xy ]]
355
380
}
356
381
357
- title.text <- e(s(" axis.title.%s" ))
358
- ax.list $ titlefont <- theme2font(title.text )
359
- ax.list $ type <- if (misc $ is.continuous [[xy ]]){
360
- " linear"
361
- }else if (misc $ is.discrete [[xy ]]){
362
- " category"
363
- }else if (misc $ is.date [[xy ]] || misc $ is.datetime [[xy ]]){
364
- " date"
365
- }else {
366
- stop(" unrecognized data type for " , xy , " axis" )
367
- }
368
-
369
382
ax.list $ zeroline <- FALSE # ggplot2 plots do not show zero lines
370
383
# Lines drawn around the plot border.
371
384
ax.list $ showline <- ! is.blank(" panel.border" , TRUE )
@@ -532,7 +545,27 @@ gg2list <- function(p){
532
545
if (any(names(layer.aes ) %in% markUnique [markUnique != " x" ]) == FALSE )
533
546
layout $ showlegend <- FALSE
534
547
535
- if (layout $ showlegend && length(p $ data )) {
548
+ # # Legend hiding when guides(fill="none").
549
+ legends.present <- unique(unlist(layer.legends ))
550
+ is.false <- function (x ){
551
+ is.logical(x ) && length(x ) == 1 && x == FALSE
552
+ }
553
+ is.none <- function (x ){
554
+ is.character(x ) && length(x ) == 1 && x == " none"
555
+ }
556
+ is.hidden <- function (x ){
557
+ is.false(x ) || is.none(x )
558
+ }
559
+ for (a in legends.present ){
560
+ if (is.hidden(p $ guides [[a ]])){
561
+ layout $ showlegend <- FALSE
562
+ }
563
+ }
564
+
565
+ # Only show a legend title if there is at least 1 trace with
566
+ # showlegend=TRUE.
567
+ trace.showlegend <- sapply(trace.list , " [[" , " showlegend" )
568
+ if (any(trace.showlegend ) && layout $ showlegend && length(p $ data )) {
536
569
# Retrieve legend title
537
570
legend.elements <- sapply(traces , " [[" , " name" )
538
571
legend.title <- " "
@@ -691,7 +724,13 @@ gg2list <- function(p){
691
724
}
692
725
693
726
# Put the traces in correct order, according to any manually
694
- # specified scales.
727
+ # specified scales. This seems to be repetitive with the trace$rank
728
+ # attribute in layer2traces (which is useful for sorting traces that
729
+ # get different legend entries but come from the same geom, as in
730
+ # test-ggplot-legend.R), but in fact this is better since it could
731
+ # be used for sorting traces that come from different geoms
732
+ # (currently we don't have a test for this). TODO: write such a
733
+ # test, delete the trace$rank code, and have it work here instead.
695
734
trace.order <- unlist(trace.order.list )
696
735
ordered.traces <- if (length(trace.order )){
697
736
trace.order.score <- seq_along(trace.order )
0 commit comments