0
votes

I am trying to create a ggplot histogram with a density overlay, where the alpha changes past the number 1. An example can be seen on 538 under the Every outcome in our simulations section. The alpha differs based on the electoral vote count. I am close to getting a similar graph but I cannot figure out how to get the density and histogram to work together.

Code

library(data.table)
library(ggplot2)
dt <- data.table(ratio = rnorm(10000, mean = .5, sd = 1))

dt[, .(ratio,
          al = (ratio >= 1))] %>% 
  ggplot(aes(x = ratio, alpha = al)) +
  geom_histogram(aes(), bins = 100,
                 fill = 'red') +
  geom_density(aes(),size = 1.5,
               color = 'blue') +
  geom_vline(xintercept = 1,
             color = '#0080e2', 
             size = 1.2) +
  scale_alpha_discrete(range = c(.65, .9))

This attempt correctly changes alpha past 1 as desired but the density estimate is not scaled.

dt[, .(ratio,
       al = (ratio >= 1))] %>% 
  ggplot(aes(x = ratio)) +
  geom_histogram(aes(y = ..density.., alpha = al), bins = 100,
                 fill = 'red') +
  geom_density(aes(y = ..scaled..),size = 1.5,
               color = 'blue',) +
  geom_vline(xintercept = 1,
             color = '#0080e2', 
             size = 1.2) +
  scale_alpha_discrete(range = c(.65, .9))

This attempt correctly scales the density curve, but now the geom_histogram is calculated separately for values under 1 and above 1. I want them calculated as one group.

What am I missing?

1
Care to share theme_josh?Allan Cameron
Oops forgot to remove that. It is just grid marks and legend stuff. Not necessary for the questiondrj3122

1 Answers

1
votes

The reason why knowing your theme is important is that there's an easy shortcut to this, which is not using alpha, but just drawing a semitransparent rectangle over the left half of your plot:

library(data.table)
library(ggplot2)
library(dplyr)

data.table(ratio = rnorm(10000, mean = .5, sd = 1)) %>%
  ggplot(aes(x = ratio)) +
  geom_histogram(aes(y = ..density..), bins = 100,
                 fill = 'red') +
  geom_line(aes(), stat = "density", size = 1.5,
               color = 'blue') +
  geom_vline(xintercept = 1,
             color = '#0080e2', 
             size = 1.2) +
  annotate("rect", xmin = -Inf, xmax = 1, ymin = 0, ymax = Inf, fill = "white",
           alpha = 0.5) +
  theme_bw()

enter image description here

Splitting into two groups and using alpha is possible, but it basically requires you to precalculate the histogram and the density curve. That's fine, but it would be an awful lot of extra effort for very little visual gain.

Of course, if theme_josh has a custom background color and zany gridlines, this approach may not be quite so effective. As long as you set the fill color to the panel background you should get a decent result. (the default ggplot panel is "gray90" or "gray95" I think)