2

I'm trying to create a Venn diagram where each circle has a unique colour, and the intersections blend those colours.

I can make the circles with the ggforce package. And I can blend the colours by setting the alpha values to, say, 0.75:

library(ggplot2)
library(ggforce)

propositions <- data.frame(
  cirx = c(-.75   , .75),
  ciry = c(0      , 0),
  r    = c(1.5    , 1.5),
  labx = c(-2.25  , 2.25),
  laby = c(1      , 1),
  labl = c("A", "B")
)

ggplot(propositions) + 
  theme_void() + coord_fixed() +
  xlim(-3,3) + ylim(-2,2) +
  theme(panel.border = element_rect(colour = "black", fill = NA, size = 1)) +
  geom_circle(aes(x0 = cirx, y0 = ciry, r = r), fill = "red", alpha = .6, data = propositions[1,]) +
  geom_circle(aes(x0 = cirx, y0 = ciry, r = r), fill = "blue", alpha = .6, data = propositions[2,]) +
  geom_text(aes(x = labx, y = laby, label = labl), 
            fontface = "italic", size = 10, family = "serif")

But the results are pretty poor:

enter image description here

The colours are washed out, and the intersection's colour isn't as distinct from the right-side circle's as I'd like. I want something closer to this (photoshopped) result:

enter image description here

I could do this if there was some way to designate and fill the intersection. In principle, this could be done with geom_ribbon(), I think. But that seems painful, and hacky. So I'm hoping for a more elegant solution.

Jonathan
  • 1,075
  • 2
  • 10
  • 18
  • 1
    If you're not married to using `ggforce`: there are many packages that implement Venn or Euler diagrams. Here is [a (possibly incomplete) list](https://stackoverflow.com/a/14895967/1664024). If you are married to using `ggforce`: you can see how color blending of overlap regions is handled in the [Eulerr package](https://jolars.github.io/eulerr/) by [examining the source code](https://github.com/jolars/eulerr/blob/master/R/utils.R#L247-L259). If you really just wanted to know how to draw a circle overlap using `geom_ribbon`, then you have @jonathan's answer. – drammock Jul 22 '18 at 20:46
  • Thanks, this is very helpful. I'm not wedded to `ggforce`, but I would like to stay within the `ggplot2` framework if at all possible. But in case not, I'll explore alternatives like `eulerr`. – Jonathan Jul 23 '18 at 16:03

1 Answers1

0

Here's the workaround using geom_ribbon(). It's not a proper solution though, since it won't generalize to other shapes and intersections without manually redefining the boundaries of the ribbon, which can get real hairy fast.

There's gotta be a way to get ggplot2 to automatically do the work of blending colours across layers, right?

library(ggplot2)
library(ggforce)

x <- seq(-.75, .75, 0.01)

upper <- function(x) {
    a <- sqrt(1.5^2 - (x[x < 0] - .75)^2)
    b <- sqrt(1.5^2 - (x[x >= 0] + .75)^2)
    c(a,b)
}

lower <- function(x) {
    -upper(x)
}

ggplot() + 
    coord_fixed() + theme_void() +
    xlim(-3,3) + ylim(-2,2) +
    geom_circle(aes(x0 = -.75, y0 = 0, r = 1.5), fill = "red") +  
    geom_circle(aes(x0 = .75, y0 = 0, r = 1.5), fill = "blue") +  
    geom_ribbon(aes(x = x, ymin = upper(x), ymax = lower(x)), fill = "purple", colour = "black") +
    theme(panel.border = element_rect(colour = "black", fill = NA, size = 1)) +
    geom_text(aes(x = c(-2.25, 2.25), y = c(1, 1), label = c("A", "B")), 
              fontface = "italic", size = 10, family = "serif")

enter image description here

Jonathan
  • 1,075
  • 2
  • 10
  • 18
  • 1
    Just curious, if you do it with yellow and blue do you get green? I noticed that didn't work using your original code and swapping out the colors – Hack-R Jul 20 '18 at 02:05
  • 1
    No, if I use the original code with yellow and blue I don't get green. Something much closer to violet instead. I don't think using alpha/transparency blends colours in the usual way. It doesn't seem to yield a point midway on the colour wheel. – Jonathan Jul 20 '18 at 13:45