Home > other >  Is there a way to add a shared axis title on a subplot?
Is there a way to add a shared axis title on a subplot?

Time:01-24

I'm trying to create a 2x2 subplot, with both plots in each column having the same y-axis title, like this :

Dummy plot with same yaxis titles

i.e. one 'title' (here called annotations, cf. later) for the left column (blue green) and one for the right column (yellow red).

I can easily have a yaxis title for each plot but I'm stumped as to making shared ones. I tried using annotations, like this (this is the code used to render the plot shown above) :

if (!require("plotly")) install.packages("plotly")
library(plotly)

group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>% 
  plot_ly() %>% 
  add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>% 
  layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))
plot

subdf1 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf2 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf <- subplot(subdf1, subdf2, nrows = 2, margin = 0.06) %>% 
  layout(annotations = list(list(x = -0.1, y = 0.5, text = "<b>First annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16)), 
list(x = 0.48, y = 0.5, text = "<b>Second annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16))))
subdf

My main gripe with this method is that when the plot is resized, the annotations (mainly the first one, in the negative range for x-axis placement) move around the x-axis.

Same plot but wider : enter image description here

I used xref = "paper" as I thought it meant the whole plot area i.e. the whole white background, but in such case, my annotation wouldn't disappear (and wouldn't be in negatives, but I'm possibly not thinking about this the right way). I did try using xref = x but it won't go into negatives and instead just push the data to the right.

So all in all, two questions :

  • Is there a native way to have a shared axis title for subplots?
  • If not, is there a way to make sure that my annotations stay in the same relative place as the plots and axes when resizing the subplot?

CodePudding user response:

If you aren't tied to using plotly, this can be done in a straightforward way using faceting in ggplot. It may require some rearranging of your data into tidy format but gives some serious flexibility while plotting!

library(ggplot2)

group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)

df <- data.frame(group = rep(c('a','b','c'), 4),
                 values = rep(c(0,5,10), 4),
                 facet = rep(c('W','X','Y','Z'), each = 3))

ggplot(df, aes(x = group, y = values, colour = facet, group = 1))  
  geom_line(size = 1.1)  
  geom_point(size = 2)  
  facet_wrap(~facet)  
  theme_bw()  
  labs(x = 'Shared X axis title', y = 'Shared Y axis title', colour = 'Traces')   
  theme(
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )

enter image description here

CodePudding user response:

You could create a separate title in each layout of both subplots and combine them using titleY like this:

library(plotly)
library(dplyr)

group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>% 
  plot_ly() %>% 
  add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>% 
  layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))

subdf1 <- subplot(plot, plot, nrows = 1) %>%
  layout(yaxis = list(title = "First annotation"))
subdf2 <- subplot(plot, plot, nrows = 1) %>%
  layout(yaxis = list(title = "Second annotation"))
subdf <- subplot(subdf1, subdf2, nrows = 2, titleY = TRUE)  
subdf

Created on 2023-01-23 with reprex v2.0.2


Edit

Change margin in layout:

library(plotly)
library(dplyr)

group <- c("a", "b", "c")
values <- c(0, 5, 10)
df <- data.frame(group, values)
plot <- df %>% 
  plot_ly() %>% 
  add_trace(x = ~group, y = ~values, type = "scatter", mode = "line") %>% 
  layout(yaxis = list(ticks = "outside"), xaxis = list(showline = TRUE))

subdf1 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf2 <- subplot(plot, plot, nrows = 1, margin = 0.06)
subdf <- subplot(subdf1, subdf2, nrows = 2, margin = 0.06) %>% 
  layout(margin = 0.01,
         annotations = list(list(x = -0.1, y = 0.5, text = "<b>First annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16)), 
                            list(x = 0.48, y = 0.5, text = "<b>Second annotation</b>", xref = "paper", yref = "paper", xanchor = "center", yanchor = "center", showarrow = FALSE, textangle = -90, font = list(color = "black", size = 16))))
subdf

Created on 2023-01-23 with reprex v2.0.2

  • Related