rggplot2aestheticsgeom-vline

Set geom_vline line types and sizes with aes mapping in ggplot2


I'm trying to create a histogram with vertical lines overlaid on top of it. One of the vertical lines shows a target, the rest show percentiles. I would like the line representing the target to be different than the other lines.

I have the data for the lines in a dataframe:

lines
   qntls        lbs heights    lts lsz
1  29.00      p5=29 32.2400 dashed 0.1
2  45.25     p25=45 33.5296 dashed 0.1
3  79.00     p50=79 30.9504 dashed 0.1
4 128.00    p75=128 32.2400 dashed 0.1
5 249.25    p95=249 33.5296 dashed 0.1
6 120.00 Target=120 30.9504  solid 0.2

I then use the lines dataframe to create the geom_vline and geom_label objects:

ggplot() +
  geom_histogram(
    data = h,
    mapping = aes(
      x = DAYSTODECISION
    ),
    breaks = brks,
    color = clr,
    fill = f
  ) +
  geom_vline(
    data = lines,
    mapping = aes(
      xintercept = qntls,
      color = lbs,
      linetype = lts,
      size = lsz
    ),
    show.legend = FALSE
  ) +
  geom_label(
    data = lines,
    mapping = aes(
      x = qntls,
      y = heights,
      label = lbs,
      hjust = 0 # Label starts on line and extends right
    )
  ) +
  ggtitle(title) +
  labs(
    x = xlab,
    y = ylab
  ) +
  theme_classic()

I get this result:

enter image description here

I want the line for the target to be solid and all other lines to be dashed. For some reason this is reversed in the chart compared to the lines dataframe. Additionally, I would expect the target line to be twice as thick as the other lines, but this is not the case.

Any help would be much appreciated!


Solution

  •   # your plot code ... +
      scale_linetype_identity() +
      scale_size_identity()
    

    It's unusual in a ggplot to put the actual colors/sizes/linetypes you want in the data frame (instead of meaningful labels you might want on a legend, like you do for lbs), but if you do the identity scales are your friend.

    A more standard approach would have your data set up perhaps like this:

       qntls        lbs heights is_target 
    1  29.00      p5=29 32.2400        no
    2  45.25     p25=45 33.5296        no
    3  79.00     p50=79 30.9504        no
    4 128.00    p75=128 32.2400        no
    5 249.25    p95=249 33.5296        no
    6 120.00 Target=120 30.9504       yes
    

    Then map linetype = is_target, size = is_target inside aes(), and use manual scales like this:

    ... + 
    scale_size_manual(values = c("no" = 0.1, "yes" = 0.2)) +
    scale_linetype_manual(values = c("no" = "dashed", "yes" = "solid"))
    

    This set-up makes it easy to adjust your graph without changing your data.