Search code examples
rggplot2plotlyggplotlyggpubr

automatically adding brackets or braces to ggplot and plotly objects


I want to automate adding brackets/braces to a ggplot object and then convert it to plotly using ggplotly.

library(tidyverse)
library(plotly)
#devtools::install_github("NicolasH2/ggbrace")
library(ggbrace)
set.seed(10)
mydata <- data.frame(xx = c(1:10), yy = sample(0:10, 10))
my_bracket_data <- data.frame(start = c(1, 4, 6),
                              end = c(3, 5, 9),
                              info = c("first", "second", "third"),
                              y_bottom = rep(11, 3),
                              y_top = rep(12, 3))

I can do this by using geom_brace but it involves manually typing it out for each brace rather than using the data that is already stored in a data.frame:

plot_geom_brace <- ggplot(data = mydata, aes(xx, yy)) + 
  geom_line(size = 1.5) +
  geom_brace(aes(x = c(1, 3), y = c(11, 12), label = "first"), inherit.data = F, labelsize = 5) +
  geom_brace(aes(x = c(4, 5), y = c(11, 12), label = "second"), inherit.data = F, labelsize = 5) +
  geom_brace(aes(x = c(6, 9), y = c(11, 12), label = "third"), inherit.data = F, labelsize = 5) 
plot_geom_brace
ggplotly(plot_geom_brace)

enter image description here

Is there a way that I can do this without repeatedly writing geom_brace layers for each brace (and instead access the data from my_bracket_data directly)?

As an aside this can be automated using geom_bracket but this is not supported by plotly yet.

library(ggpubr)
plot_geom_bracket <- ggplot(data = mydata, aes(xx, yy)) + 
      geom_line(size = 1.5) +
      geom_bracket(xmin = my_bracket_data$start, 
                   xmax = my_bracket_data$end, 
                   y.position = rep(11, 3), 
                   label = my_bracket_data$info,
                   inherit.aes = FALSE)
plot_geom_bracket
ggplotly(plot_geom_bracket)
# Warning message:
# In geom2trace.default(dots[[1L]][[1L]], dots[[2L]][[1L]], dots[[3L]][[1L]]) :
#   geom_GeomBracket() has yet to be implemented in plotly.
#   If you'd like to see this geom implemented,
#   Please open an issue with your example code at
#   https://github.com/ropensci/plotly/issues 

Any suggestions?

Thanks


Solution

  • An option could be by creating two dataframes of your bracket data. One dataframe for the geom_braces by converting the data to a longer format with pivot_longer to create three geom braces through the aes. To get the labels you can create a small summarise table with the x and y positions per group of info. Here is some reproducible code:

    library(tidyverse)
    library(plotly)
    #devtools::install_github("NicolasH2/ggbrace")
    library(ggbrace)
    set.seed(10)
    mydata <- data.frame(xx = c(1:10), yy = sample(0:10, 10))
    my_bracket_data <- data.frame(start = c(1, 4, 6),
                                  end = c(3, 5, 9),
                                  info = c("first", "second", "third"),
                                  y_bottom = rep(11, 3),
                                  y_top = rep(12, 3))
    
    # Data for geom_brace
    my_bracket_data_long <- my_bracket_data %>%
      pivot_longer(cols = c(start, end), values_to = "x_value", names_to = "x_names") %>%
      pivot_longer(cols = c(y_bottom, y_top), values_to = "y_value", names_to = "y_names") 
    
    # data for labels braces
    my_bracket_data_labels <- my_bracket_data_long %>%
      group_by(info) %>%
      summarise(x_pos = mean(x_value), 
                y_pos = mean(y_value) + 1)
    
    # plot
    plot_geom_brace <- ggplot(data = mydata, aes(xx, yy)) + 
      geom_line(size = 1.5) +
      geom_brace(data = my_bracket_data_long, aes(x = x_value, y = y_value, group = info)) +
      geom_text(data = my_bracket_data_labels, aes(x = x_pos, y = y_pos, group = info, label = info))
    

    ggplotly(plot_geom_brace)
    

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