33# ' @param ... any number of plotly objects
44# ' @param nrows number of rows for laying out plots in a grid-like structure.
55# ' Only used if no domain is already specified.
6+ # ' @param widths relative width of each column on a 0-1 scale. By default all
7+ # ' columns have an equal relative width.
8+ # ' @param heights relative height of each row on a 0-1 scale. By default all
9+ # ' rows have an equal relative height.
10+ # ' @param share determines whether x/y/both axes are shared.
611# ' @param which_layout adopt the layout of which plot? If the default value of
712# ' "merge" is used, all plot level layout options will be included in the final
813# ' layout. This argument also accepts a numeric vector which will restric
2025# ' subplot(p1, p2, p1, p2, nrows = 2)
2126# ' }
2227
23- subplot <- function (... , nrows = 1 , which_layout = " merge" , margin = 0.02 ) {
28+ subplot <- function (... , nrows = 1 , widths = NULL , heights = NULL , share = NULL ,
29+ which_layout = " merge" , margin = 0.02 ) {
2430 # build each plot and collect relevant info
2531 plots <- lapply(list (... ), plotly_build )
2632 traces <- lapply(plots , " [[" , " data" )
@@ -58,7 +64,9 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
5864 yAxisMap <- split(yAxisMap , rep(seq_along(plots ), yAxisN ))
5965 # domains of each subplot
6066 # TODO: allow control of column width and row height!
61- domainInfo <- get_domains(length(plots ), nrows , margin )
67+ domainInfo <- get_domains(
68+ length(plots ), nrows , margin , widths = widths , heights = heights
69+ )
6270 # reposition shapes and annotations
6371 annotations <- Map(reposition , annotations , split(domainInfo , seq_along(plots )))
6472 shapes <- Map(reposition , shapes , split(domainInfo , seq_along(plots )))
@@ -122,16 +130,40 @@ subplot <- function(..., nrows = 1, which_layout = "merge", margin = 0.02) {
122130}
123131
124132
125- get_domains <- function (nplots = 1 , nrows = 1 , margins = 0.01 ) {
133+ get_domains <- function (nplots = 1 , nrows = 1 , margins = 0.01 ,
134+ widths = NULL , heights = NULL ) {
126135 if (length(margins ) == 1 ) margins <- rep(margins , 4 )
127136 if (length(margins ) != 4 ) stop(" margins must be length 1 or 4" , call. = FALSE )
128137 ncols <- ceiling(nplots / nrows )
138+ widths <- widths %|| % rep(1 / ncols , ncols )
139+ heights <- heights %|| % rep(1 / nrows , nrows )
140+ if (length(widths ) != ncols ) {
141+ stop(" The length of the widths argument must be equal " ,
142+ " to the number of columns" , call. = FALSE )
143+ }
144+ if (length(heights ) != nrows ) {
145+ stop(" The length of the heights argument must be equal " ,
146+ " to the number of rows" , call. = FALSE )
147+ }
148+ if (any(widths < 0 | heights < 0 )) {
149+ stop(" The widths and heights arguments must contain positive values" )
150+ }
151+ if (sum(widths ) > 1 | sum(heights ) > 1 ) {
152+ stop(" The sum of the widths and heights arguments must be less than 1" )
153+ }
154+
155+ widths <- cumsum(c(0 , widths ))
156+ heights <- cumsum(c(0 , heights ))
157+ # 'center' these values if there is still room left
158+ widths <- widths + (1 - max(widths )) / 2
159+ heights <- heights + (1 - max(heights )) / 2
160+
129161
130162 xs <- vector(" list" , ncols )
131163 for (i in seq_len(ncols )) {
132164 xs [[i ]] <- c(
133- xstart = (( i - 1 ) / ncols ) + ifelse (i == 1 , 0 , margins [1 ]) ,
134- xend = ( i / ncols ) - ifelse (i == ncols , 0 , margins [2 ])
165+ xstart = widths [ i ] + if (i == 1 ) 0 else margins [1 ],
166+ xend = widths [ i + 1 ] - if (i == ncols ) 0 else margins [2 ]
135167 )
136168 }
137169 xz <- rep_len(xs , nplots )
@@ -140,8 +172,8 @@ get_domains <- function(nplots = 1, nrows = 1, margins = 0.01) {
140172 for (i in seq_len(nplots )) {
141173 j <- ceiling(i / ncols )
142174 ys [[i ]] <- c(
143- ystart = 1 - (( j - 1 ) / nrows ) - ifelse (j == 1 , 0 , margins [3 ]) ,
144- yend = 1 - (j / nrows ) + ifelse (j == nrows , 0 , margins [4 ])
175+ ystart = 1 - (heights [ j ]) - if (j == 1 ) 0 else margins [3 ],
176+ yend = 1 - (heights [ j + 1 ] ) + if (j == nrows ) 0 else margins [4 ]
145177 )
146178 }
147179 list2df(Map(c , xz , ys ))
0 commit comments