Is it possible to plot a line over a ggplot (including the margin area)

Hi, I'd like to create plots with a line to separate the first 6 from the last 4 items.

Here a minimal reproducible example of what I have so far (using geom_vline()):

library(dplyr)
library(ggplot2)

tibble(
  labels = paste0("Label-", letters[1:10]),
  value  = runif(10, 0, 1)
) %>% 
  ggplot(aes(x = labels, y = value)) +
  geom_point() +
  coord_flip() +
  geom_vline(xintercept = 4.5, col = "#a8a5a5", size = 1.4, alpha = .4) +
  theme_minimal() +
  theme(axis.title = element_blank())

Created on 2019-12-03 by the reprex package (v0.3.0)

In contrast, here what I want (for now, I manually extended the line on the left):

I'd highly appreciate any advice or new ideas to solve this issue.
Thanks a lot in advance!

Geoms plot data and it makes no sense for data to go outside the plot area into the axis labels. It is probably possible to shoe-horn a line in using low-level manipulations.

You don't give a reason for wanting to divide the plot, but I'd like to propose using facets as an alternative to achieve it:

data <- tibble(
  labels = paste0("Label-", letters[1:10]),
  value  = runif(10, 0, 1)
) 

data %>% 
  ggplot(aes(x = labels, y = value)) +
  facet_grid(labels %in% data$labels[1:4] ~ ., scales = "free") +
  geom_point() +
  coord_flip() +
  theme_minimal() +
  theme(axis.title = element_blank(),
        panel.border = element_rect(fill="transparent"),
        strip.background = element_blank(),
        strip.text.y = element_blank())

Of course you can theme the facets to your liking. Here I've removed the strips, but actually you can use the strips to indicate the dividing criterion (works similarly to the x, y aesthetics).
The only downside to this solution is that the facets are equal size, which is a little ugly when the axes are divided unequally between the facets because the scale is compressed/stretched to fit the facet size.

1 Like

Hi @cymon,

thanks for the suggestions! I agree that geoms are not a perfect fit here. However, I also think that there must exist some low-level solution.

The visualisations are for some standard presentations and we discussed relatively long about this issue, so I am also curious about a solution in general.

I also really like your alternative approach. Just as you mention it has other downsides. Since the output was missing, I include it here again.

library(dplyr)
ibrary(ggplot2)

tibble(
  labels = paste0("Label-", letters[1:10]),
  value  = runif(10, 0, 1),
  top = c(rep(1,6), rep(2,4))
) %>% 
  ggplot(aes(x = labels, y = value)) +
  facet_grid(top ~ ., scales = "free") +
  geom_point() +
  coord_flip() +
  theme_minimal() +
  theme(axis.title = element_blank(),
        panel.border = element_rect(fill="transparent"),
        strip.background = element_blank(),
        strip.text.y = element_blank())

Created on 2019-12-03 by the reprex package (v0.3.0)

Your approach also inspired me to another approach via patchwork, which allows to adjust the scales relatively easy.

library(dplyr)
library(ggplot2)
library(patchwork)

data <- tibble(
  labels = paste0("Label-", letters[1:10]),
  value  = runif(10, 0, 1),
  top = c(rep(1,6), rep(2,4))
) 

p1 <- data %>%
  filter(top == 1) %>%
  ggplot(aes(x = labels, y = value)) +
  geom_point() +
  ylim(c(0,1)) +
  coord_flip() +
  theme_minimal() +
  theme(axis.title = element_blank(),
        axis.text.x = element_blank())

p2 <- data %>%
  filter(top == 2) %>%
  ggplot(aes(x = labels, y = value)) +
  geom_point() +
  coord_flip() +
  ylim(c(0,1)) +
  theme_minimal() +
  theme(axis.title = element_blank())

p1 / p2 + plot_layout(heights = c(1, 4/6))

Created on 2019-12-03 by the reprex package (v0.3.0)

2 Likes

You can use the clip argument to coord_flip (and the other coord_*** functions) to turn off clipping and thereby display data drawn outside the plot panel. You'll probably need to play with the y and yend values in geom_segment and possibly the ylim range in coord_flip to get the dividing line endpoints where you want them. For example:

set.seed(2)
tibble(
  labels = paste0("Label-", letters[1:10]),
  value  = runif(10, 0, 1)
) %>% 
  ggplot(aes(x = labels, y = value)) +
    geom_point() +
    annotate(x = 4.5, xend=4.5, y=-0.15, yend=1.05,
             geom="segment",
             colour = "#a8a5a5", size = 1.4, alpha = .4) +
    theme_minimal() +
    theme(axis.title = element_blank()) +
    coord_flip(clip="off", ylim=c(0,1)) 

Rplot03

2 Likes

This is perfect.
THANKS!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.