Alvaro Morales
Alvaro Morales

Reputation: 1925

How to add vertical lines between facet strips in ggplot?

reprex:

library(tidyverse)

df <- tibble::tibble(
  epoca = factor(c("H", "S", "S", "H", "S", "H", "S"), levels = c("S", "H")),
  ano = c("2019", "2018", "2019", "2021", "2022", "2022", "2021"),
  n = rep(3:1, c(3L, 2L, 2L)),
  etiqueta = rep(c("3", "2", "1"), c(3L, 2L, 2L)),
  ffvv = c(rep("a", 3), rep("b", 4))
)

df %>% 
  ggplot(aes(x = epoca, y = n, fill = epoca)) +
  geom_col(width = 0.8, position = position_dodge(0.8)) +
  geom_text(aes(x = epoca, label = etiqueta),
            position = position_dodge(0.9), vjust = 0, size = 8) +
  ggh4x::facet_nested(cols = vars(ffvv, ano),
                      switch = "x",
                      scales = "free_x",
                      space = "free_x") +
theme(strip.background = element_rect(fill = "white"),
      strip.text = element_text(size = 25, lineheight = 0.6),
      strip.placement = "outside",
      axis.text.x = element_text(angle = 0, size = 27, lineheight = unit(.8, "lines")))

Output: enter image description here

Desired output: (check red lines) enter image description here

Upvotes: 2

Views: 670

Answers (3)

TarJae
TarJae

Reputation: 79164

An alternative is using geom_segment():

library(tidyverse)

df %>% 
  ggplot(aes(x = epoca, y = n, fill = epoca)) +
  geom_col(width = 0.8, position = position_dodge(0.8)) +
  geom_text(aes(x = epoca, label = etiqueta),
            position = position_dodge(0.9), vjust = 0, size = 8) +
  ggh4x::facet_nested(cols = vars(ffvv, ano),
                      switch = "x",
                      scales = "free_x",
                      space = "free_x") +
  theme(strip.background = element_rect(fill = "white"),
        strip.text = element_text(size = 25, lineheight = 0.6),
        strip.placement = "outside",
        axis.text.x = element_text(angle = 0, size = 27, lineheight = unit(.8, "lines")))+
  theme(axis.title.x = element_text(margin=margin(50,0,0,0))) +
  coord_cartesian(clip = "off", ylim = c(0, 3)) +
  geom_segment(aes(x = 3, y = 0, xend = 3, yend = -0.5), color = "red")

enter image description here

Upvotes: 0

nrennie
nrennie

Reputation: 2549

Another (manual) solution is using {cowplot}:

library(cowplot)
ggdraw() + 
  draw_plot(g) +
  draw_line(x = c(0.42, 0.42),
            y = c(0.08, 0.21),
            lwd = 1.5,
            colour = "red")

where g is the plot you already have, saved as a variable. It's not a perfect solution, since it usually requires a bit-of-trial and error to get the coordinates right. It uses geom_path() under the hood, but means you don't have to mess with clipping and coordinates of existing plots.

bar chart

If it's more about separating the different facets, then adding colour = "red" to your strip.background element in the theme is an alternative approach:

enter image description here

Upvotes: 2

Allan Cameron
Allan Cameron

Reputation: 174278

There are no theme elements that match with the lines you want, so you will need to get creative. I prefer a ggplot to be self-contained, so rather than drawing the lines over the plot separately, I would probably draw these in as geom_path elements. This requires using coord_cartesian with clipping off and a fixed y axis limit:

df %>% 
  ggplot(aes(x = epoca, y = n, fill = epoca)) +
  geom_col(width = 0.8, position = position_dodge(0.8)) +
  geom_text(aes(x = epoca, label = etiqueta),
            position = position_dodge(0.9), vjust = 0, size = 8) +
  ggh4x::facet_nested(cols = vars(ffvv, ano),
                      switch = "x",
                      scales = "free_x",
                      space = "free_x") +
  coord_cartesian(clip = "off", ylim = c(0, 3)) +
  geom_path(data = data.frame(epoca = rep("S", 6),
                              n = rep(c(-0.55, -0.15), 3),
                              ffvv = c("a", "a", rep("b", 4)),
                              ano = rep(c("2019", "2021", "2022"), each = 2)),
            position = position_nudge(x = -0.6)) +
  theme(strip.background = element_rect(fill = NA),
        strip.text = element_text(size = 25, lineheight = 0.6),
        strip.placement = "outside",
        axis.text.x = element_text(angle = 0, size = 27, 
                                   lineheight = unit(.8, "lines")))

enter image description here

Upvotes: 2

Related Questions