@@ -86,7 +86,8 @@ gg2list <- function(p){
86
86
# # Always use identity size scale so that plot.ly gets the real
87
87
# # units for the size variables.
88
88
p <- p + scale_size_identity()
89
- plist <- list ()
89
+ layout <- list ()
90
+ trace.list <- list ()
90
91
# # Before building the ggplot, we would like to add aes(name) to
91
92
# # figure out what the object group is later.
92
93
for (layer.i in seq_along(p $ layers )){
@@ -106,53 +107,24 @@ gg2list <- function(p){
106
107
}
107
108
p $ layers [[layer.i ]]$ mapping $ name <- group.var
108
109
}
109
- plistextra <- ggplot2 :: ggplot_build(p )
110
- # # NOTE: data from ggplot_build have scales already applied. This
111
- # # may be a bad thing for log scales.
112
- for (sc in plistextra $ plot $ scales $ scales ){
113
- if (sc $ scale_name == " manual" ){
114
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(0 )
115
- }else if (sc $ scale_name == " brewer" ){
116
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(length(sc $ range $ range ))
117
- }else if (sc $ scale_name == " hue" ){
118
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(length(sc $ range $ range ))
119
- }else if (sc $ scale_name == " linetype_d" ){
120
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(length(sc $ range $ range ))
121
- }else if (sc $ scale_name == " alpha_c" ){
122
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(sc $ range $ range )
123
- }else if (sc $ scale_name == " size_c" ){
124
- plist $ scales [[sc $ aesthetics ]] <- sc $ palette(sc $ range $ range )
125
- }else if (sc $ scale_name == " gradient" ){
126
- plist $ scales [[sc $ aesthetics ]] <- ggplot2 ::: scale_map(sc , ggplot2 ::: scale_breaks(sc ))
127
- }
128
- }
129
- for (i in seq_along(plistextra $ plot $ layers )){
110
+ # # Extract data from built ggplots
111
+ built <- ggplot2 :: ggplot_build(p )
112
+ ranges <- built $ panel $ ranges [[1 ]]
113
+ for (i in seq_along(built $ plot $ layers )){
130
114
# # This is the layer from the original ggplot object.
131
- L <- plistextra $ plot $ layers [[i ]]
115
+ L <- built $ plot $ layers [[i ]]
132
116
133
117
# # for each layer, there is a correpsonding data.frame which
134
118
# # evaluates the aesthetic mapping.
135
- df <- plistextra $ data [[i ]]
119
+ df <- built $ data [[i ]]
136
120
137
121
# # This extracts essential info for this geom/layer.
138
- g <- layer2list(L , df , plistextra $ panel $ ranges [[1 ]])
139
-
140
- # # Idea: use the ggplot2:::coord_transform(coords, data, scales)
141
- # # function to handle cases like coord_flip. scales is a list of
142
- # # 12, coords is a list(limits=list(x=NULL,y=NULL)) with class
143
- # # e.g. c("cartesian","coord"). The result is a transformed data
144
- # # frame where all the data values are between 0 and 1.
145
-
146
- # # TODO: coord_transform maybe won't work for
147
- # # geom_dotplot|rect|segment and polar/log transformations, which
148
- # # could result in something nonlinear. For the time being it is
149
- # # best to just ignore this, but you can look at the source of
150
- # # e.g. geom-rect.r in ggplot2 to see how they deal with this by
151
- # # doing a piecewise linear interpolation of the shape.
122
+ traces <- layer2traces(L , df , ranges )
152
123
153
- g $ data <- ggplot2 ::: coord_transform(plistextra $ plot $ coord , g $ data ,
154
- plistextra $ panel $ ranges [[1 ]])
155
- plist $ geoms [[i ]] <- g
124
+ # # Do we really need to coord_transform?
125
+ # #g$data <- ggplot2:::coord_transform(built$plot$coord, g$data,
126
+ # # built$panel$ranges[[1]])
127
+ trace.list <- c(trace.list , traces )
156
128
}
157
129
# Export axis specification as a combination of breaks and
158
130
# labels, on the relevant axis scale (i.e. so that it can
@@ -164,64 +136,90 @@ gg2list <- function(p){
164
136
# # Flip labels if coords are flipped - transform does not take care
165
137
# # of this. Do this BEFORE checking if it is blank or not, so that
166
138
# # individual axes can be hidden appropriately, e.g. #1.
167
- ranges <- plistextra $ panel $ ranges [[1 ]]
168
- if (" flip" %in% attr(plistextra $ plot $ coordinates , " class" )){
169
- temp <- plistextra $ plot $ labels $ x
170
- plistextra $ plot $ labels $ x <- plistextra $ plot $ labels $ y
171
- plistextra $ plot $ labels $ y <- temp
139
+ # # ranges <- built$panel$ranges[[1]]
140
+ # # if("flip"%in%attr(built$plot$coordinates, "class")){
141
+ # # temp <- built$plot$labels$x
142
+ # # built$plot$labels$x <- built$plot$labels$y
143
+ # # built$plot$labels$y <- temp
144
+ # # }
145
+ e <- function (el.name ){
146
+ ggplot2 :: calc_element(el.name , p $ theme )
172
147
}
173
148
is.blank <- function (el.name ){
174
- x <- ggplot2 :: calc_element(el.name , p $ theme )
175
- " element_blank" %in% attr(x ," class" )
149
+ " element_blank" %in% attr(e(el.name )," class" )
176
150
}
177
- plist $ axis <- list ()
178
151
for (xy in c(" x" ," y" )){
152
+ ax.list <- list ()
179
153
s <- function (tmp )sprintf(tmp , xy )
180
- plist $ axis [[xy ]] <- ranges [[s(" %s.major" )]]
181
- plist $ axis [[s(" %slab" )]] <- if (is.blank(s(" axis.text.%s" ))){
182
- NULL
183
- }else {
184
- ranges [[s(" %s.labels" )]]
154
+ ax.list $ tickcolor <- toRGB(theme.pars $ axis.ticks $ colour )
155
+ ax.list $ gridcolor <- toRGB(theme.pars $ panel.grid.major $ colour )
156
+ # # These numeric length variables are not easily convertible.
157
+ # #ax.list$gridwidth <- as.numeric(theme.pars$panel.grid.major$size)
158
+ # #ax.list$ticklen <- as.numeric(theme.pars$axis.ticks.length)
159
+ ax.list $ tickwidth <- theme.pars $ axis.ticks $ size
160
+ tick.text.name <- s(" axis.text.%s" )
161
+ ax.list $ showticklabels <- ifelse(is.blank(tick.text.name ), FALSE , TRUE )
162
+ tick.text <- e(tick.text.name )
163
+ ax.list $ tickangle <- if (is.numeric(tick.text $ angle )){
164
+ - tick.text $ angle
165
+ }
166
+ theme2font <- function (text ){
167
+ if (! is.null(text )){
168
+ with(text , {
169
+ list (family = family ,
170
+ size = size ,
171
+ color = toRGB(colour ))
172
+ })
173
+ }
185
174
}
186
- plist $ axis [[s(" %srange" )]] <- ranges [[s(" %s.range" )]]
187
- plist $ axis [[s(" %sname" )]] <- if (is.blank(s(" axis.title.%s" ))){
188
- " "
175
+ # # Translate axes labels.
176
+ scale.i <- which(p $ scales $ find(xy ))
177
+ ax.list $ title <- if (length(scale.i )){
178
+ sc <- p $ scales $ scales [[scale.i ]]
179
+ if (! is.null(sc $ name )){
180
+ sc $ name
181
+ }else {
182
+ p $ labels [[xy ]]
183
+ }
189
184
}else {
190
- plistextra $ plot $ labels [[xy ]]
185
+ p $ labels [[xy ]]
191
186
}
192
- plist $ axis [[s(" %sline" )]] <- ! is.blank(s(" axis.line.%s" ))
193
- plist $ axis [[s(" %sticks" )]] <- ! is.blank(s(" axis.ticks.%s" ))
187
+ ax.list $ tickfont <- theme2font(tick.text )
188
+ title.text <- e(s(" axis.title.%s" ))
189
+ ax.list $ titlefont <- theme2font(title.text )
190
+ ax.list $ type <- " linear" # # TODO: log scales?
191
+ # # Lines drawn around the plot border:
192
+ ax.list $ showline <- ifelse(is.blank(" panel.border" ), FALSE , TRUE )
193
+ ax.list $ linecolor <- toRGB(theme.pars $ panel.border $ colour )
194
+ ax.list $ linewidth <- theme.pars $ panel.border $ size
195
+ # # Some other params that we used in animint but we don't yet
196
+ # # translate to plotly:
197
+ ! is.blank(s(" axis.line.%s" ))
198
+ ! is.blank(s(" axis.ticks.%s" ))
199
+ layout [[s(" %saxis" )]] <- ax.list
194
200
}
195
201
196
- plist $ legend <- getLegendList(plistextra )
197
- if (length(plist $ legend )> 0 ){
198
- plist $ legend <- plist $ legend [which(sapply(plist $ legend , function (i ) length(i )> 0 ))]
199
- } # only pass out legends that have guide = "legend" or guide="colorbar"
200
-
201
- # Remove legend if theme has no legend position
202
- if (theme.pars $ legend.position == " none" ) plist $ legend <- NULL
203
-
204
- if (" element_blank" %in% attr(theme.pars $ plot.title , " class" )){
205
- plist $ title <- " "
206
- } else {
207
- plist $ title <- plistextra $ plot $ labels $ title
208
- }
202
+ # # Remove legend if theme has no legend position
203
+ if (theme.pars $ legend.position == " none" ) layout $ showlegend <- FALSE
209
204
210
- pargs <- list ()
211
- for (g in plist $ geoms ){
212
- pargs <- c(pargs , g $ traces )
213
- }
214
- pargs $ kwargs <- list ()
215
- pargs
205
+ # # Main plot title.
206
+ layout $ title <- built $ plot $ labels $ title
207
+
208
+ # # Background color.
209
+ layout $ plot_bgcolor <- toRGB(theme.pars $ panel.background $ fill )
210
+ layout $ paper_bgcolor <- toRGB(theme.pars $ plot.background $ fill )
211
+
212
+ trace.list $ kwargs <- list (layout = layout )
213
+ trace.list
216
214
}
217
215
218
- # ' Convert a layer to a list. Called from gg2list()
216
+ # ' Convert a layer to a list of traces . Called from gg2list()
219
217
# ' @param l one layer of the ggplot object
220
218
# ' @param d one layer of calculated data from ggplot2::ggplot_build(p)
221
219
# ' @param ranges axes ranges
222
220
# ' @return list representing a layer, with corresponding aesthetics, ranges, and groups.
223
221
# ' @export
224
- layer2list <- function (l , d , ranges ){
222
+ layer2traces <- function (l , d , ranges ){
225
223
g <- list (geom = l $ geom $ objname ,
226
224
data = d )
227
225
g $ aes <- sapply(l $ mapping , function (k ) as.character(as.expression(k ))) # needed for when group, etc. is an expression
@@ -233,7 +231,7 @@ layer2list <- function(l, d, ranges){
233
231
# # non-ggplot2 params like name are useful for plot.ly and ggplot2
234
232
# # places them into stat_params.
235
233
for (p.name in names(g $ params )){
236
- names(g $ params [[p.name ]]) <- NULL
234
+ names(g $ params [[p.name ]]) <- NULL # why?
237
235
}
238
236
239
237
# # Convert complex ggplot2 geoms so that they are treated as special
@@ -384,19 +382,10 @@ layer2list <- function(l, d, ranges){
384
382
g $ data <- poly.na.df
385
383
}
386
384
387
- # # Check g$data for color/fill - convert to hexadecimal so JS can
388
- # # parse correctly.
389
- for (color.var in c(" colour" , " color" , " fill" )){
390
- if (color.var %in% names(g $ data )){
391
- g $ data [,color.var ] <- toRGB(g $ data [,color.var ])
392
- }
393
- }
394
-
395
385
if (any(g $ data $ size == 0 , na.rm = TRUE )){
396
386
warning(sprintf(" geom_%s with size=0 will be invisible" ,g $ geom ))
397
387
}
398
388
399
- g $ traces <- list ()
400
389
group.vars <- c(" group" ,
401
390
" color" , " colour" ,
402
391
" fill" ) # TODO.
@@ -417,6 +406,7 @@ layer2list <- function(l, d, ranges){
417
406
}else {
418
407
list (g $ data )
419
408
}
409
+ # # Construct a list of traces.
420
410
for (group.i in seq_along(group.list )){
421
411
group.data <- group.list [[group.i ]]
422
412
tr <- group2trace(group.data , g $ params , g $ geom )
@@ -426,7 +416,7 @@ layer2list <- function(l, d, ranges){
426
416
tr $ name <- as.character(tr $ name [1 ])
427
417
g $ traces [[group.i ]] <- tr
428
418
}
429
- g
419
+ g $ traces
430
420
}
431
421
432
422
getMarker <- function (df , params , aesConverter , defaults , only = NULL ){
@@ -442,6 +432,10 @@ getMarker <- function(df, params, aesConverter, defaults, only=NULL){
442
432
}
443
433
take.from <- as.list(take.from )
444
434
to.write <- take.from [[name ]]
435
+ if (plotly.name == " color" ){ # convert from R to RGB codes.
436
+ # # TODO: fill?
437
+ to.write <- toRGB(to.write )
438
+ }
445
439
# # if(is.null(to.write)){
446
440
# # print(take.from)
447
441
# # stop("undefined marker ", name)
0 commit comments