Skip to content

Commit d9e213e

Browse files
committed
update subplot layout
- don't subtract the margins from the subplots width/height as both margins are subtracted from the inner subplots and only one margin from the outer ones, so the proportions are broken - automatically scale widths/heights to fit into 0..1 when summed with the margins - update subplot margins tests to the new logic (+ include the tests for inner subplots dimensions)
1 parent 51a9357 commit d9e213e

File tree

2 files changed

+33
-84
lines changed

2 files changed

+33
-84
lines changed

R/subplots.R

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -339,37 +339,36 @@ get_domains <- function(nplots = 1, nrows = 1, margins = 0.01,
339339
stop("The length of the heights argument is ", length(heights),
340340
", but the number of rows is ", nrows, call. = FALSE)
341341
}
342-
if (any(widths < 0) | any(heights < 0)) {
342+
if (sum(margins[1:2]) < 0 || sum(margins[3:4]) < 0) {
343+
stop("Subplot margins cannot be negative")
344+
}
345+
if (any(widths < 0) || any(heights < 0)) {
343346
stop("The widths and heights arguments must contain positive values")
344347
}
345-
if (sum(widths) > 1 | sum(heights) > 1) {
346-
stop("The sum of the widths and heights arguments must be less than 1")
348+
total_margins_width <- sum(margins[1:2])*(ncols-1)
349+
if (total_margins_width >= 1.0) stop("The total width of margins should be less than 1.0, reduce margin[1:2]")
350+
total_margins_height <- sum(margins[3:4])*(nrows-1)
351+
if (total_margins_height >= 1.0) stop("The total height of margins should be less than 1.0, reduce margin[3:4]")
352+
# if needed, rescale subplot widths and heights to fit in 0..1 range
353+
total_width <- sum(widths) + total_margins_width
354+
if (total_width > 1.0) {
355+
widths <- widths/sum(widths)*(1.0 - total_margins_width)
356+
total_width <- 1.0
347357
}
348-
349-
widths <- cumsum(c(0, widths))
350-
heights <- cumsum(c(0, heights))
351-
# 'center' these values if there is still room left
352-
widths <- widths + (1 - max(widths)) / 2
353-
heights <- heights + (1 - max(heights)) / 2
354-
355-
xs <- vector("list", ncols)
356-
for (i in seq_len(ncols)) {
357-
xs[[i]] <- c(
358-
xstart = widths[i] + if (i == 1) 0 else margins[1],
359-
xend = widths[i + 1] - if (i == ncols) 0 else margins[2]
360-
)
358+
total_height <- sum(heights) + total_margins_height
359+
if (total_height > 1.0) {
360+
heights <- heights/sum(heights)*(1.0 - total_margins_height)
361+
total_height <- 1.0
361362
}
362-
xz <- rep_len(xs, nplots)
363-
364-
ys <- vector("list", nrows)
365-
for (i in seq_len(nplots)) {
366-
j <- ceiling(i / ncols)
367-
ys[[i]] <- c(
368-
ystart = 1 - (heights[j]) - if (j == 1) 0 else margins[3],
369-
yend = 1 - (heights[j + 1]) + if (j == nrows) 0 else margins[4]
370-
)
371-
}
372-
list2df(Map(c, xz, ys))
363+
364+
# panel offsets (centered in the whole plot)
365+
xstarts <- c(0, cumsum(widths[-length(widths)]+sum(margins[1:2]))) + (1-total_width)/2
366+
ystarts <- c(0, cumsum(heights[-length(heights)]+sum(margins[3:4]))) + (1-total_height)/2
367+
368+
data.frame(xstart = rep_len(xstarts, nplots),
369+
xend = pmin(1.0, rep_len(xstarts+widths, nplots)),
370+
ystart = rep(1-ystarts, each=ncols, length.out=nplots),
371+
yend = pmax(0.0, rep(1-ystarts-heights, each=ncols, length.out=nplots)))
373372
}
374373

375374
list2df <- function(x, nms) {

tests/testthat/test-plotly-subplot.R

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,18 @@ empty <- ggplot() + geom_blank()
8080
scatter <- ggplot(d) + geom_point(aes(x = x, y = y))
8181
hist_right <- ggplot(d) + geom_histogram(aes(x = y)) + coord_flip()
8282
s <- subplot(
83-
hist_top, empty, scatter, hist_right,
84-
nrows = 2, widths = c(0.8, 0.2), heights = c(0.2, 0.8),
83+
hist_top, empty, empty, scatter, empty, hist_right,
84+
nrows = 2, widths = c(0.5, 0.3, 0.2), heights = c(0.4, 0.6),
8585
margin = 0.005, shareX = TRUE, shareY = TRUE
8686
)
8787

8888
test_that("Row/column height/width", {
8989
l <- expect_traces(s, 3, "width-height")
90-
expect_equivalent(diff(l$layout$xaxis$domain), 0.8 - 0.005)
91-
expect_equivalent(diff(l$layout$xaxis2$domain), 0.2 - 0.005)
92-
expect_equivalent(diff(l$layout$yaxis$domain), 0.2 - 0.005)
93-
expect_equivalent(diff(l$layout$yaxis2$domain), 0.8 - 0.005)
90+
expect_equivalent(diff(l$layout$xaxis$domain), 0.5 - 0.005)
91+
expect_equivalent(diff(l$layout$xaxis2$domain), 0.3 - 0.005)
92+
expect_equivalent(diff(l$layout$xaxis3$domain), 0.2 - 0.005)
93+
expect_equivalent(diff(l$layout$yaxis$domain), 0.4 - 0.005)
94+
expect_equivalent(diff(l$layout$yaxis2$domain), 0.6 - 0.005)
9495
})
9596

9697
test_that("recursive subplots work", {
@@ -170,54 +171,3 @@ test_that("geo+cartesian behaves", {
170171
expect_equivalent(geoDom$y, c(0, 0.68))
171172
})
172173

173-
174-
175-
test_that("May specify legendgroup with through a vector of values", {
176-
177-
# example adapted from https://github.com/ropensci/plotly/issues/817
178-
df <- dplyr::bind_rows(
179-
data.frame(x = rnorm(100,2), Name = "x1"),
180-
data.frame(x = rnorm(100,6), Name = "x2"),
181-
data.frame(x = rnorm(100,4), Name = "x3")
182-
)
183-
df$y <- rnorm(300)
184-
185-
# marker definition...
186-
m <- list(
187-
size = 10,
188-
line = list(
189-
width = 1,
190-
color = "black"
191-
)
192-
)
193-
194-
base <- plot_ly(
195-
df,
196-
marker = m,
197-
color = ~factor(Name),
198-
legendgroup = ~factor(Name)
199-
)
200-
201-
s <- subplot(
202-
add_histogram(base, x = ~x, showlegend = FALSE),
203-
plotly_empty(),
204-
add_markers(base, x = ~x, y = ~y),
205-
add_histogram(base, y = ~y, showlegend = FALSE),
206-
nrows = 2, heights = c(0.2, 0.8), widths = c(0.8, 0.2),
207-
shareX = TRUE, shareY = TRUE, titleX = FALSE, titleY = FALSE
208-
) %>% layout(barmode = "stack")
209-
210-
# one trace for the empty plot
211-
l <- expect_traces(s, 10, "subplot-legendgroup")
212-
213-
# really this means show three legend items (one is blank)
214-
expect_equivalent(
215-
sum(sapply(l$data, function(tr) tr$showlegend %||% TRUE)), 4
216-
)
217-
218-
expect_length(
219-
unlist(lapply(l$data, "[[", "legendgroup")), 9
220-
)
221-
222-
})
223-

0 commit comments

Comments
 (0)