Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend geom_vline outside of plot

I am trying to expand the geom_vline lines in my ggplot plot to go outside of the plot space and into the axis area. The goal of this is to have these lines separating the axis labels so it can line up with another plot that goes next to it (see below).

Some short example code (I have many more rows, and therefore need the horizontal lines to keep things straight):

library(ggplot2)
library(cowplot)
library(dplyr)

#play data set
cars.data <- mtcars %>%
      mutate(car_name = rownames(mtcars)) %>%
      slice(1:6)

#I would like vlines to be extend in this plot
p1 <- ggplot(cars.data, aes(x = car_name, y = hp)) +
    geom_point() +
    scale_x_discrete(position = "top") +
    coord_flip() +
    geom_vline(aes(xintercept = seq(1.5, 6.5, 1)), color = "gray60") +
    xlab("")


p2 <- ggplot(cars.data, aes(y = car_name, x = 1)) +
  geom_text(aes(label = disp)) +
  xlab("disp") +
  geom_hline(aes(yintercept = seq(1.5, 6.5, 1)), color = "gray60")+
  theme(axis.title.y = element_blank(),
        axis.title.x = element_text(vjust = 0.5, angle = 30),
        axis.text = element_blank(),
        axis.line = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_rect(fill = "gray90"))

plot_grid(p1, p2, rel_widths = c(1,0.2))

This results in the following figure: enter image description here

What I am looking for is to extend the lines from p1 so that they continue between the plots, almost like a plot-table hybrid. I've tried clip = "off" but it doesn't seem to do the trick.

like image 259
m.evans Avatar asked Dec 02 '19 16:12

m.evans


Video Answer


2 Answers

You'll have to draw the lines yourself to make sure they can extend past the plot boundary when you set clip = "off". I'm using geom_segment() here and manually set the limits in the coord.

You also need to align the two plots in plot_grid() to make sure everything works properly.

library(ggplot2)
library(cowplot)
library(dplyr)

#play data set
cars.data <- mtcars %>%
  mutate(car_name = rownames(mtcars)) %>%
  slice(1:6)

p1 <- ggplot(cars.data, aes(x = car_name, y = hp)) +
  geom_point() +
  scale_x_discrete(
    name = NULL,
    position = "top"
  ) +
  scale_y_continuous(expand = c(0, 0)) +
  coord_flip(clip = "off", ylim = c(80, 180)) +
  geom_segment(
    data = data.frame(x = seq(1.5, 6.5, 1), ymin = 80, ymax = 240),
    aes(x = x, xend = x, y = ymin, yend = ymax),
    inherit.aes = FALSE,
    color = "gray60"
  ) +
  xlab(NULL) +
  theme_cowplot()


p2 <- ggplot(cars.data, aes(y = car_name, x = 1)) +
  geom_text(aes(label = disp)) +
  xlab("disp") +
  geom_hline(aes(yintercept = seq(1.5, 6.5, 1)), color = "gray60") +
  theme_cowplot() +
  theme(
    axis.title.y = element_blank(),
    axis.title.x = element_text(vjust = 0.5, angle = 30),
    axis.text = element_blank(),
    axis.line = element_blank(),
    axis.ticks = element_blank(),
    panel.background = element_rect(fill = "gray90"),
    plot.margin = margin(7, 7, 7, 0)
  )

plot_grid(p1, p2, rel_widths = c(1,0.2), align = "h", axis = "bt")

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

like image 83
Claus Wilke Avatar answered Oct 18 '22 17:10

Claus Wilke


Here's a way to get started that instead of relying on ggplot's axis labelling to get what you want, treats labels as data and builds your own. There was a question where we used similar approaches here: Bar charts connected by lines / How to connect two graphs arranged with grid.arrange in R / ggplot2

A few hacks make this work:

  • Replace axis labels with left-aligned geom_text and scale expansion to place it properly
  • Make all geoms use the same x-axis variable so cowplot can align along that axis
  • Set negative margins on the sides that join so panels will run one right into the next and look like a continuous plot
library(ggplot2)
library(cowplot)
library(dplyr)

theme_set(theme_cowplot()) # I'm using cowplot v1.0.0 which no longer does this by default

p_left <- ggplot(cars.data, aes(x = car_name, y = hp)) +
  geom_vline(aes(xintercept = seq(1.5, 6.5, 1)), color = "gray60") +
  geom_point() +
  scale_x_discrete(breaks = NULL) +
  coord_flip() +
  xlab(NULL) +
  theme(axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        axis.line = element_blank(),
        plot.margin = margin(5, -5, 5, 5, "pt"),
        panel.border = element_blank())

p_middle <- ggplot(cars.data, aes(x = car_name, y = 1)) +
  geom_vline(aes(xintercept = seq(1.5, 6.5, 1)), color = "gray60") +
  geom_text(aes(label = car_name), hjust = 0) +
  scale_x_discrete() +
  scale_y_continuous(expand = expansion(add = c(0.05, 0.5))) +
  coord_flip() +
  labs(x = NULL, y = "") +
  theme(axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank(),
        panel.grid = element_blank(),
        plot.margin = margin(5, -5, 5, -5, "pt"),
        panel.border = element_blank())

p_right <- ggplot(cars.data, aes(x = car_name, y = 1)) +
  geom_vline(aes(xintercept = seq(1.5, 6.5, 1)), color = "gray60") +
  geom_text(aes(label = disp)) +
  scale_x_discrete() +
  coord_flip() +
  labs(x = NULL, y = "disp") +
  theme(axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank(),
        panel.grid = element_blank(),
        plot.margin = margin(5, 5, 5, -5, "pt"),
        panel.border = element_blank())


plot_grid(p_left, p_middle, p_right,
  nrow = 1, rel_widths = c(1, 0.4, 0.2),
  align = "h"
)

I only copied over the essential theme changes—you'll probably want to adjust things to fit your purposes. I'd recommend also digging into each of the individual plots to adjust them one by one.

like image 3
camille Avatar answered Oct 18 '22 17:10

camille