R Plotly inconsistent subplot size

I'm trying to plot an array of box plots however subplot produces plots of different sizes. I really need all the plots to be the same size.

Here is some example code which I'll explain a bit below:

library(plotly)

df1 <- data.frame(label = sample(c("a", "b", "c","d", "e", "f"), 1000, replace = TRUE),
                 value = rnorm(1000,1))

df2 <- data.frame(label = sample(c("a", "b", "c", "d", "e", "f"), 1000, replace = TRUE),
                  value = rnorm(1000,2))


create_plot <- function(showlegend = F) {
  plot_ly( type = "box",
           showlegend = showlegend
           ) %>%
  add_trace(data = df1,
            x = ~label,
            y = ~value,
            offsetgroup = 0,
            legendgroup = 0,
            name = "Type 1") %>%
  add_trace(data = df2,
            x = ~label,
            y = ~value,
            offsetgroup = 1,
            legendgroup = 1,
            name = "Type 2") %>%
  layout(plot,
         boxmode = "group",
         annotations = list(
           x = 0.5,
           y = 1.05,
           text = "Plot Title",
           xref = "paper",
           yref = "paper",
           xanchor = "center",  # center of text
           yanchor = "center",  # center of text
          showarrow = FALSE
         )
  )
}

fig1 <- create_plot(showlegend = T)
fig2 <- create_plot()
    
#subplot(fig, fig1, fig1, fig1, fig1,
subplot(fig1, fig2, fig2, fig2, fig2, fig2, fig2, fig2,
        nrows = 4,
        # heights = c(0.2, 0.3, 0.3, 0.2),
        margin = c(0.07, 0.0, 0.05, 0.1) # c(left, right, top, bottom )
        ) %>%
  layout(
    bargroupgap = 0.01,
    plot_bgcolor='#e5ecf6'
    
  )

Code explanation:

  • df1 and df2 is just the data
  • The create_plot() function just allows me to create the same demo plot but turn off the legend on all the but the first plot I create
  • fig1 and fig2 are created using the create_plot() function. fig1 has the legend shown, fig2 does not
  • subplot just plots the same plot over and over to demonstrate that even though the plots are identical, they end up different sizes

This code produces the following output for me:

The subplot

As you can see the middle two rows of plots have the lowest height and the last row plots are larger than any of the other rows. You will also see that the plot titles end up in different locations depending on the row. When plotted individually, the plot turns out perfectly.

I have tried all sorts of settings in subplot like the margin settings and height settings but they all seem to be very plot size and number specific where as I would like my subplot to be more independent of the size and shape of the rendered output.

Any thoughts?


Solution 1:

I'm having exactly the same issue with the margins, not the titles (see modified code which fixes them, by setting yanchor = "bottom").

I too have played around with the margins (not so much the heights) and find that the top and bottom row of plots look taller than the centre rows (I have 5 in my code). Is it because the margins are added together for the 'middle' rows and so the plots have less space to occupy?

I've tried balancing the margins in your code but it doesn't fix the problem.

Leaving the margins as the default doesn't work well because the titles then seem to be too close to the plot above. I'm having to settle for the 'least worst' display option, which isn't great.

library(plotly)

df1 <- data.frame(label = sample(c("a", "b", "c","d", "e", "f"), 1000, replace = TRUE),
                  value = rnorm(1000,1))

df2 <- data.frame(label = sample(c("a", "b", "c", "d", "e", "f"), 1000, replace = TRUE),
                  value = rnorm(1000,2))    

create_plot <- function(showlegend = F) {
  plot_ly( type = "box",
           showlegend = showlegend
  ) %>%
    add_trace(data = df1,
              x = ~label,
              y = ~value,
              offsetgroup = 0,
              legendgroup = 0,
              name = "Type 1") %>%
    add_trace(data = df2,
              x = ~label,
              y = ~value,
              offsetgroup = 1,
              legendgroup = 1,
              name = "Type 2") %>% 
    layout(boxmode = "group",
           bargroupgap = 0.01,
           plot_bgcolor='#e5ecf6',
           annotations = list(
             x = 0.5,
             y = 1.05,
             text = "Plot Title",
             xref = "paper",
             yref = "paper",
             xanchor = "center",  # center of text
             yanchor = "bottom",  # bottom of text
             showarrow = FALSE
           )
    )
}    

fig1 <- create_plot(showlegend = T)
fig2 <- create_plot()

#subplot(fig, fig1, fig1, fig1, fig1,
subplot(fig1, fig2, fig2, fig2, fig2, fig2, fig2, fig2,
        nrows = 4,
        # heights = c(0.2, 0.3, 0.3, 0.2),
        margin = c(0.07, 0.0, 0.05, 0.01) # c(left, right, top, bottom ) least worst option?
)