3
votes
library(tidyverse)
ggplot(mtcars, aes(cyl, mpg)) + 
  geom_point() + 
  theme_bw() + 
  geom_hline(aes(yintercept = 20), color = "red")

This code above is the nice black and white theme, with a red horizontal line. The code below also is supposed to be the black and white theme, this time with a red vertical line. But the plot lacks any color at all. Why is theme_bw() stripping out all color from my plot below?

library(tidyverse)
library(lubridate)

df <- 
  tibble(
    date = as.Date(41000:42000, origin = "1899-12-30"), 
    value = c(rnorm(500, 5), rnorm(501, 10))
  ) %>% 
  mutate(year = as.factor(year(date)))

ggplot(df, aes(date, value)) + 
  geom_line() + 
  geom_vline(
    xintercept = as.numeric(df$date[yday(df$date) == 1]), color = "red"
  ) + 
  scale_x_date(
    date_labels = "%b", breaks = scales::pretty_breaks(), expand = c(0, 0)
  ) +
  facet_grid(.~ year, space = 'free_x', scales = 'free_x', switch = 'x') +
  labs(x = "") +
  theme_bw(base_size = 14, base_family = 'mono') +
  theme(panel.grid.minor.x = element_blank()) + 
  theme(panel.spacing.x = unit(0, "line")) +
  theme(strip.placement = 'outside', strip.background.x = element_blank()) 

enter image description here

2
You just need to increase size of line (geom_vline(size = 2, ...)), all this happens because you split plot into facets and there edges cover the line (or remove facets).pogibas
@PoGibas thanks that works! but how do I eliminate the facet black lines? What ends up happening now is I get the size=2 red line, with a size=1 black line drawn on top of it. Looks like a racing stripe (which I don't want in this case)stackinator
Remove facets ?pogibas
Here's a related question, where the answer uses theme_classic() and adds lines on top and right.aosmith

2 Answers

1
votes

You could remove the facet panel borders with panel.border = element_blank() inside theme

ggplot(df, aes(date, value)) +
  geom_line() +
  geom_vline(
    xintercept = as.numeric(df$date[yday(df$date) == 1]), color = "red") +
  scale_x_date(
    date_labels = "%b", breaks = scales::pretty_breaks(), expand = c(0, 0)) +
  facet_grid(.~ year, space = 'free_x', scales = 'free_x', switch = 'x') +
  labs(x = "") +
  theme_bw(base_size = 14, base_family = 'mono') +
  theme(
      panel.grid.minor.x = element_blank(),
      panel.spacing.x = unit(0, "line"),
      panel.border = element_blank(),
      strip.placement = 'outside',
      strip.background.x = element_blank())

enter image description here


Update

To use facets and have the red lines not overlap the facet borders here is bit of a "hacky" solution:

First, draw without panel borders

gg <- ggplot(df, aes(date, value)) +
      geom_line() +
      geom_vline(
        xintercept = as.numeric(df$date[yday(df$date) == 1]), color = "red") +
      scale_x_date(
        date_labels = "%b", breaks = scales::pretty_breaks(), expand = c(0, 0)) +
      facet_grid(.~ year, space = 'free_x', scales = 'free_x', switch = 'x') +
      labs(x = "") +
      theme_bw(base_size = 14, base_family = 'mono') +
      theme(
          panel.grid.minor.x = element_blank(),
          panel.spacing.x = unit(0, "line"),
          panel.border = element_blank(),
          strip.placement = 'outside',
          strip.background.x = element_blank())

Then we extract the y-axis range for the panel, and add a geom_rect to manually draw the panel border

ylim <- ggplot_build(gg)$layout$panel_params[[1]]$y.range
gg <- gg +
    geom_rect(
        xmin = min(df$date), xmax = max(df$date),
        ymin = ylim[1], ymax = ylim[2],
        fill = NA, colour = "black")

enter image description here

It's a bit hacky because you need to break up the plotting into two steps in order to be able to extract the y-axis range for the panel.

1
votes

Another hack, if you are willing to dig into the grobs:

gp <- ggplotGrob(p) # where p is the original ggplot object

# for each panel grob, change the order of grobs such that the grob corresponding
# to geom_vline (should have a name like "GRID.segments.XXXX") lies above the grob
# corresponding to the facet outline (should have a name like "panel.border..rect.XXXX")
for(i in grep("panel", gp$layout$name)){
  old.order <- gp$grobs[[i]]$childrenOrder
  new.order <- c(old.order[-grep("segments", old.order)],
                 old.order[grep("segments", old.order)])
  gp$grobs[[i]]$childrenOrder <- new.order
}

grid::grid.draw(gp)

plot