Search code examples
rplotlybordersubplot

How do you add plot borders to Plotly subplots in R?


I'm trying to make a grid of plots with shared axes, and I would like each subplot to have plot borders (it would be acceptable, though not ideal, for the entire plot area instead to have borders). I can't make this work, and the results make me think it may not be possible in Plotly. Below are the three variants I've tried, along with the outcomes.

    library(plotly)
    library(magrittr)

    set.seed(0)
    x <- seq(from=0, to=9, by=1)
    y1 <- rnorm(10)
    y2 <- rnorm(10)
    y3 <- rnorm(10)
    y4 <- rnorm(10)

    # Attempt 1
    p1 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y1)

    p2 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y2)

    p3 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y3)

    p4 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y4)

    p <- subplot(p1, p2, p3, p4,
                 nrows = 2, shareX = TRUE, shareY = TRUE) %>%
      layout(title='Attempt 1', xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    # Attempt 2
    p1 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y1) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p2 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y2) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p3 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y3) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p4 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y4) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p <- subplot(p1, p2, p3, p4,
                 nrows = 2, shareX = TRUE, shareY = TRUE) %>%
      layout(title='Attempt 2')

    # Attempt 3
    p1 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y1) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p2 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y2) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p3 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y3) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p4 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y4) %>%
      layout(xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

    p <- subplot(p1, p2, p3, p4,
                 nrows = 2, shareX = TRUE, shareY = TRUE) %>%
      layout(title='Attempt 3', xaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'),
             yaxis = list(showline = TRUE, mirror = TRUE, linecolor = 'black'))

Attempt 1 Attempt 2 Attempt 3


Solution

  • If you give each plot the same range in your layout attributes, your individual border lines are preserved.

    Here is how I suggest defining your range:

    #find the max and min Y, which you will use as your range values
    your_Ys<-c(y1,y2,y3,y4)
    max_y<-ceiling(max(your_Ys))
    min_y<-floor(min(your_Ys))
    

    Instead of making the list of attributes in each plot, I define x and Y attributes here:

    #These are the layout attributes for Y
    ay <- list(
      showline = TRUE,
      mirror = "ticks",
      linecolor = toRGB("black"),
      linewidth = 2,
      range = c(min_y, max_y)
    )
    
    #These are the layout attributes for X
    ax <- list(
      showline = TRUE,
      mirror = "ticks",
      linecolor = toRGB("black"),
      linewidth = 2,
      range = c(-1, 10)
    )
    

    And now it's time to put it all together.

    p1 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y1)  %>% layout( xaxis = ax, yaxis = ay)
    
    p2 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y2)  %>% layout( xaxis = ax, yaxis = ay)
    
    p3 <- plot_ly(showlegend=FALSE)%>%
      add_markers(x = x, y = y3) %>%layout( xaxis = ax, yaxis = ay)
    
    p4 <- plot_ly(showlegend=FALSE) %>%
      add_markers(x = x, y = y4)%>% layout( xaxis = ax, yaxis = ay)
    
    p <- subplot(p1, p2, p3, p4,
                 nrows = 2, shareX = FALSE, shareY = FALSE) %>%
      layout(title='Tada!')
    p
    

    plotly subplot with border lines