Search code examples
rplotly

Setting margin of multiple pie charts using plotly in R


I'm trying to set the margins between the pie charts, but now margin doesn't work and the pictures overlap each other.

labels <- rep(LETTERS[seq(from = 1, to = 11)],12)
values <- runif(length(labels), min=0, max=1)
group <- letters[seq(from = 1, to = 12)]
row=rep(seq(0,3), each=3)
col=rep(seq(0,2), time=4)
d1 <- data.frame(labels, values, group)

library(plotly)
p <- plot_ly() 
for (i in 1:12) {
  var = group[i] 
  d <- d1 %>% filter(group==var) 
  p <- p %>%  add_pie(data=d, labels = ~labels, values = ~values, type = 'pie',
                      textposition = "outside", textinfo = 'label+percent',
                      marker = list(colors = ~colors),
                      sort = F,
                      domain = list(row = row[i], column = col[i]),
                      margin = list(b=180, l=180, r=180, t=180) **#doesn't work**
  )
}

p <- p %>% layout(title = NULL, showlegend = F,
                  grid=list(rows=max(row)+1, columns=max(col)+1),
                  margin = list(b=80, l=80, r=80, t=80), **#doesn't work**
                  xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
                  yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

p

orca(p, "pie_chart.pdf", scale = 1, width = 1200, height = 1600)

enter image description here

I've also tried setting up to use the subplot function, but none of that works. Also I've tried drawing with ggplot2 but can't set up labels like plotly. I would like to use plotly to draw the labels without overlapping or ggplot2 to draw the labels like the above illustration. Thank you in advance for answers.


Solution

  • I see that you used domain to set the row and column, but if you want a buffer between rows and columns, use domain to set the real estate in 'plot space'. By default the range is 0 to 1.

    So for horizontal placement, plot space plot space plot - or 3/10 + 1/2 + 3/10 + 1/2 + 3/10. You can, of course, use different spacing - the goal is that whatever sizes you use, that the total amounts to 1.

    For vertical placement, there's 4 plots and 3 spaces. Here I used .225 for each plot and .1/3 (1/3 of .1 remaining after .225 * 4 = 0.9).

    One other element I changed was the font size of the labels. In layout, I added font = list(size = 6)

    I create 3 new constants.

    buff = .05; rw = 4; cl = 3
    

    Then I updated the documentation of the domains in your for loop using discrete math.

    for (i in 1:12) {
      var = group[i] 
      d <- d1 %>% filter(group == var) 
      p <- p %>%  add_pie(
        data = d, labels = ~labels, values = ~values, type = 'pie',
        textposition = "outside", textinfo = 'label+percent',
        marker = list(colors = ~colors),
        sort = F,
        domain = list( # if it's a plot on the edges or not
          x = c(ifelse(col[i] == 0, 0, col[i] * 3/10 + buff * col[i]),    # horizontal
                ifelse(col[i] == 2, 1, (col[i] + 1) * 3/10 + buff * col[i])),  
          y = c(ifelse(row[i] == 0, 0, (1/rw - buff/2 + .1/3) * row[i]),  # vertical 
                ifelse(row[i] == 3, 1, (1/rw - buff/2) * (row[i] + 1) + (.1/3 * row[i]))))
      )
    }
    

    This equates to the following domains for the four plots (if you were to manually write it).

    x0 = 0    x1 = 0.3  y0 = 0      y1 = 0.225
    x0 = 0.35 x1 = 0.65 y0 = 0      y1 = 0.225
    x0 = 0.7  x1 = 1    y0 = 0      y1 = 0.225
    x0 = 0    x1 = 0.3  y0 = 0.2583 y1 = 0.483
    x0 = 0.35 x1 = 0.65 y0 = 0.2583 y1 = 0.483
    x0 = 0.7  x1 = 1    y0 = 0.2583 y1 = 0.483
    x0 = 0    x1 = 0.3  y0 = 0.516  y1 = 0.7416
    x0 = 0.35 x1 = 0.65 y0 = 0.516  y1 = 0.7416
    x0 = 0.7  x1 = 1    y0 = 0.516  y1 = 0.7416
    x0 = 0    x1 = 0.3  y0 = 0.775  y1 = 1
    x0 = 0.35 x1 = 0.65 y0 = 0.775  y1 = 1
    x0 = 0.7  x1 = 1    y0 = 0.775  y1 = 1
    

    With the updates I've made, here's the plot.

    updated plot

    If you were to change the vertical alignment to .2 for plots and .2/3 for spacing, this is what you would get. (Change the buff/2 to buff and the.1/3 to .2/3 for y domain)

    more space vertically