Search code examples
rggplot2groupingstrip

Make color blocks with text using ggplot2


I have a cowplot like the following, with different ggplot2 plots inside.

plot_list <- list()
plot_list[["P1"]] <- ggplot2::ggplot(mtcars, ggplot2::aes(x = mpg, y = drat)) + ggplot2::geom_point()
plot_list[["P2"]] <- ggplot2::ggplot(mtcars, ggplot2::aes(x = mpg, y = qsec)) + ggplot2::geom_point()
plot_list[["P3"]] <- ggplot2::ggplot(mtcars, ggplot2::aes(x = disp, y = drat)) + ggplot2::geom_point()
plot_list[["P4"]] <- ggplot2::ggplot(mtcars, ggplot2::aes(x = disp, y = qsec)) + ggplot2::geom_point()
P <- cowplot::plot_grid(plotlist=plot_list, ncol=1)

grDevices::pdf(file="test_all.pdf", height=10, width=20)
print(P)
grDevices::dev.off()

which produces:

fig1

Now I want to make a plot with ggplot2 as well that is just color boxes with text, to "group" the plot above. Think face_wrap() strips only (but bigger) with strip.position="left". Like this:

fig2

so that the boxes occupy the same relative vertical space as the main sub-plots:

fig3

My ultimate goal is to place these 2 plots (strips plot and main plot) side by side in a Shiny app, so that the strips are fixed and the main plot is scrollable (x-axis only). That is the reason why I don't want to use facet_wrap.


Solution

  • As your plan is to add your plots to a shiny app one option would be to create your boxes as separate ggplots using rects and texts which could then be positioned in the shiny app in a column layout:

    library(shiny)
    library(ggplot2)
    library(cowplot)
    
    ui <- fluidPage(
      fluidRow(
        column(1, plotOutput("box1")),
        column(1, plotOutput("box2")),
        column(10, plotOutput("plot"))
      ),
      tags$head(
        tags$style(HTML(
          "div.col-sm-1 { padding-right: 5px; padding-left: 0;}"
        ))
      )
    )
    
    server <- function(input, output, session) {
      output$box1 <- renderPlot({
        ggplot() +
          annotate(
            geom = "rect",
            xmin = -Inf, xmax = Inf,
            ymin = -Inf, ymax = Inf,
            fill = "grey65",
            color = "black",
            linewidth = 2
          ) +
          annotate(
            geom = "text",
            label = "mpg", x = 0, y = 0,
            size = 36 / .pt, color = "white"
          ) +
          theme_void()
      })
      output$box2 <- renderPlot({
        labels <- c("drat", "qsec", "drat", "qsec")
        lapply(seq_along(labels), \(x) {
          ggplot() +
            annotate(
              geom = "rect",
              xmin = -Inf, xmax = Inf,
              ymin = -Inf, ymax = Inf,
              fill = if (x %% 2 == 0) "grey85" else "grey95",
              color = "black",
              linewidth = 2
            ) +
            annotate(
              geom = "text",
              label = labels[[x]], x = 0, y = 0,
              angle = 90, size = 24 / .pt, color = "black"
            ) +
            theme_void()
        }) |>
          cowplot::plot_grid(plotlist = _, ncol = 1)
      })
      output$plot <- renderPlot({
        P
      })
    }
    
    shinyApp(ui, server)
    #> 
    #> Listening on http://127.0.0.1:7228