Skip to content

Commit 0dd4d63

Browse files
committed
reposition shapes/annotations
1 parent c7098c7 commit 0dd4d63

File tree

1 file changed

+47
-11
lines changed

1 file changed

+47
-11
lines changed

R/subplots.R

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,28 @@
2121
#' }
2222

2323
subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
24-
# build each plot
24+
# build each plot and collect relevant info
2525
plots <- lapply(list(...), plotly_build)
26-
# rename axes, respecting the fact that each plot could be a subplot itself
2726
traces <- lapply(plots, "[[", "data")
2827
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
3235
xAxes <- lapply(layouts, function(x) {
33-
x[grepl("^xaxis", names(x))] %||%
36+
xaxis <- x[grepl("^xaxis", names(x))] %||%
3437
list(xaxis = list(domain = c(0, 1), anchor = "y"))
38+
xaxis$title <- NULL
39+
xaxis
3540
})
3641
yAxes <- lapply(layouts, function(x) {
37-
x[grepl("^yaxis", names(x))] %||%
42+
yaxis <- x[grepl("^yaxis", names(x))] %||%
3843
list(yaxis = list(domain = c(0, 1), anchor = "x"))
44+
yaxis$title <- NULL
45+
yaxis
3946
})
4047
# number of x/y axes per plot
4148
xAxisN <- vapply(xAxes, length, numeric(1))
@@ -52,9 +59,13 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
5259
# split the map by plot ID
5360
xAxisMap <- split(xAxisMap, rep(seq_along(plots), xAxisN))
5461
yAxisMap <- split(yAxisMap, rep(seq_along(plots), yAxisN))
55-
# get the domain of each "viewport"
62+
# domains of each subplot
5663
# TODO: allow control of column width and row height!
5764
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
5869
for (i in seq_along(plots)) {
5970
xMap <- xAxisMap[[i]]
6071
yMap <- yAxisMap[[i]]
@@ -69,7 +80,6 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
6980
# bump anchors
7081
map <- yMap[yMap %in% sub("y", "yaxis", xAxes[[i]][[j]]$anchor)]
7182
xAxes[[i]][[j]]$anchor <- sub("axis", "", names(map))
72-
browser()
7383
xAxes[[i]][[j]]$domain <- sort(scales::rescale(
7484
xAxes[[i]][[j]]$domain, xDom, from = c(0, 1)
7585
))
@@ -94,8 +104,8 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
94104
data = Reduce(c, traces),
95105
layout = Reduce(c, c(xAxes, yAxes))
96106
)
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)
99109

100110
# merge non-axis layout stuff
101111
layouts <- lapply(layouts, function(x) x[!grepl("^[x-y]axis", names(x))])
@@ -145,3 +155,29 @@ list2df <- function(x, nms) {
145155
df <- data.frame(m)
146156
if (!missing(nms)) setNames(df, nms) else df
147157
}
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

Comments
 (0)