21
21
# ' }
22
22
23
23
subplot <- function (... , nrows = 1 , which_layout = " merge" , margin = 0.02 ) {
24
- # build each plot
24
+ # build each plot and collect relevant info
25
25
plots <- lapply(list (... ), plotly_build )
26
- # rename axes, respecting the fact that each plot could be a subplot itself
27
26
traces <- lapply(plots , " [[" , " data" )
28
27
layouts <- lapply(plots , " [[" , " layout" )
29
-
30
- annotations <- compact(lapply(layouts , " [[" , " annotations" ))
31
- shapes <- compact(lapply(layouts , " [[" , " shapes" ))
28
+ shapes <- lapply(layouts , " [[" , " shapes" )
29
+ # keep non axis title annotations
30
+ annotations <- lapply(layouts , function (x ) {
31
+ axes <- vapply(x $ annotations , function (a ) identical(a $ annotationType , " axis" ), logical (1 ))
32
+ x $ annotations [! axes ]
33
+ })
34
+ # collect axis objects, and remove their titles
32
35
xAxes <- lapply(layouts , function (x ) {
33
- x [grepl(" ^xaxis" , names(x ))] %|| %
36
+ xaxis <- x [grepl(" ^xaxis" , names(x ))] %|| %
34
37
list (xaxis = list (domain = c(0 , 1 ), anchor = " y" ))
38
+ xaxis $ title <- NULL
39
+ xaxis
35
40
})
36
41
yAxes <- lapply(layouts , function (x ) {
37
- x [grepl(" ^yaxis" , names(x ))] %|| %
42
+ yaxis <- x [grepl(" ^yaxis" , names(x ))] %|| %
38
43
list (yaxis = list (domain = c(0 , 1 ), anchor = " x" ))
44
+ yaxis $ title <- NULL
45
+ yaxis
39
46
})
40
47
# number of x/y axes per plot
41
48
xAxisN <- vapply(xAxes , length , numeric (1 ))
@@ -52,9 +59,13 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
52
59
# split the map by plot ID
53
60
xAxisMap <- split(xAxisMap , rep(seq_along(plots ), xAxisN ))
54
61
yAxisMap <- split(yAxisMap , rep(seq_along(plots ), yAxisN ))
55
- # get the domain of each "viewport"
62
+ # domains of each subplot
56
63
# TODO: allow control of column width and row height!
57
64
domainInfo <- get_domains(length(plots ), nrows , margin )
65
+ # reposition shapes and annotations
66
+ annotations <- Map(reposition , annotations , split(domainInfo , seq_along(plots )))
67
+ shapes <- Map(reposition , shapes , split(domainInfo , seq_along(plots )))
68
+ # rename axis objects, anchors, and scale their domains
58
69
for (i in seq_along(plots )) {
59
70
xMap <- xAxisMap [[i ]]
60
71
yMap <- yAxisMap [[i ]]
@@ -69,7 +80,6 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
69
80
# bump anchors
70
81
map <- yMap [yMap %in% sub(" y" , " yaxis" , xAxes [[i ]][[j ]]$ anchor )]
71
82
xAxes [[i ]][[j ]]$ anchor <- sub(" axis" , " " , names(map ))
72
- browser()
73
83
xAxes [[i ]][[j ]]$ domain <- sort(scales :: rescale(
74
84
xAxes [[i ]][[j ]]$ domain , xDom , from = c(0 , 1 )
75
85
))
@@ -94,8 +104,8 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
94
104
data = Reduce(c , traces ),
95
105
layout = Reduce(c , c(xAxes , yAxes ))
96
106
)
97
- # TODO: scale shape/annotation coordinates and incorporate them!
98
- # Should we throw warning if [x-y]ref != "paper"?
107
+ p $ layout $ annotations <- Reduce( c , annotations )
108
+ p $ layout $ shapes <- Reduce( c , shapes )
99
109
100
110
# merge non-axis layout stuff
101
111
layouts <- lapply(layouts , function (x ) x [! grepl(" ^[x-y]axis" , names(x ))])
@@ -145,3 +155,29 @@ list2df <- function(x, nms) {
145
155
df <- data.frame (m )
146
156
if (! missing(nms )) setNames(df , nms ) else df
147
157
}
158
+
159
+ # translate x/y positions according to domain objects
160
+ # (useful mostly for repositioning annotations/shapes in subplots)
161
+ reposition <- function (obj , domains ) {
162
+ # we need x and y in order to rescale them!
163
+ for (i in seq_along(obj )) {
164
+ o <- obj [[i ]]
165
+ # TODO: this implementation currently assumes xref/yref == "paper"
166
+ # should we support references to axis objects as well?
167
+ for (j in c(" x" , " x0" , " x1" )) {
168
+ if (is.numeric(o [[j ]])) {
169
+ obj [[i ]][[j ]] <- scales :: rescale(
170
+ o [[j ]], as.numeric(domains [c(" xstart" , " xend" )]), from = c(0 , 1 )
171
+ )
172
+ }
173
+ }
174
+ for (j in c(" y" , " y0" , " y1" )) {
175
+ if (is.numeric(o [[j ]])) {
176
+ obj [[i ]][[j ]] <- scales :: rescale(
177
+ o [[j ]], as.numeric(domains [c(" yend" , " ystart" )]), from = c(0 , 1 )
178
+ )
179
+ }
180
+ }
181
+ }
182
+ obj
183
+ }
0 commit comments