Create 5 way Venn Diagram from CSV file in R

Viewed 5010

I have results from a survey where people answered 5 questions, 1 = yes 0=no, to how they described themselves, CRAFTSPERSON DESIGNER FABRICATOR FINE ARTIST OTHER.

I am trying to see how people over lap in identifications. I want to get the information in a venn diagram. Most of what I have found to do this shows me how to get each section, ex. n1,n2, ...n12345, then drawing the diagram with the draw.quintuplet.venn since there would be 20 some sections I was trying to see if there is an easier way to do this, without having to replicate codes 20 times with slight tweaks.

I have installed the venndiagram package but am struggling how to use it with 5 sections. Working with venn.diagram but not sure what to enter in the parenthesis.

The data looks like going down about 300 lines ( the alignment is a little off but each headers goes with a column)

CRAFTSPERSON DESIGNER FABRICATOR FINE ARTIST OTHER

 0         1            0      0    1       1
 1         1            0      0    0       1     
 0         0            0      0    0       1
 0         0            0      0    1       1

Thanks

2 Answers

With VennDiagram library each intersection of sets needs to be defined. This can be cumbersome I agree. I recently came upon library eulerr. Apart from that this package attempts to make the set/intersection area proportional to the count.

Here is an example with 4 sets:

first some data:

set.seed(2)
df = data.frame(A = sample(c(0, 1), 100, replace = T),
                B = sample(c(0, 1), 100, replace = T),
                C = sample(c(0, 1), 100, replace = T),
                D = sample(c(0, 1), 100, replace = T))


library("eulerr")
set.seed(10) #this seed changes the orientation of the sets         
plot(euler(df), counts = T, fontface = 1)    

enter image description here

You can do it the venn diagram way too:

set.seed(10)
sp_euler = with(df,
                euler(c("A" = sum(A),
                        "B" = sum(B),
                        "C" = sum(C),
                        "D" = sum(D),
                        "A&B" = sum(A == 1 & B == 1),
                        "A&C" = sum(A == 1 & C == 1),
                        "A&D" = sum(A == 1 & D == 1),
                        "B&C" = sum(B == 1 & C == 1),
                        "B&D" = sum(B == 1 & D == 1),
                        "C&D" = sum(C == 1 & D == 1),
                        "A&B&C" = sum(A == 1 & B == 1 & C == 1),
                        "A&B&D" = sum(A == 1 & B == 1 & D == 1),
                        "A&C&D" = sum(A == 1 & C == 1 & D == 1),
                        "B&C&D" = sum(B == 1 & C == 1 & D == 1),
                        "A&B&C&D" = sum(A == 1 & B == 1 & C == 1 & D == 1)), input = "union"))

plot(sp_euler,  counts = T, fontface = 1)

With 5 sets:

set.seed(2)
df = data.frame(A = sample(c(0, 1), 100, replace = T),
                B = sample(c(0, 1), 100, replace = T),
                C = sample(c(0, 1), 100, replace = T),
                D = sample(c(0, 1), 100, replace = T),
                E = sample(c(0, 1), 100, replace = T))

set.seed(10)
plot(euler(df), counts = T, fontface = 1)

enter image description here

However this might not be suitable for all sets, since if the euler model can not describe all intersections the count will not be ploted. For instance in the 4 set example the intersection of B and D is 5 and not 0 like one could conclude from the plot:

set.seed(2)
df = data.frame(A = sample(c(0, 1), 100, replace = T),
                B = sample(c(0, 1), 100, replace = T),
                C = sample(c(0, 1), 100, replace = T),
                D = sample(c(0, 1), 100, replace = T))
eu_model = euler(df) 
eu_model
#output:

        original fitted residuals region_error
A              5  5.022    -0.022        0.023
B              5  5.000     0.000        0.023
C              8  8.004    -0.004        0.037
D              7  7.012    -0.012        0.033
A&B            6  0.000     6.000        0.065
A&C            5  4.985     0.015        0.023
A&D            9  8.978     0.022        0.041
B&C           11 11.004    -0.004        0.051
B&D            5  0.000     5.000        0.054
C&D            6  0.000     6.000        0.065
A&B&C          8  7.985     0.015        0.037
A&B&D          4  0.000     4.000        0.043
A&C&D          7  7.018    -0.018        0.033
B&C&D          6  0.000     6.000        0.065
A&B&C&D        1  0.000     1.000        0.011

diag_error:  0.065 
stress:      0.23 

Another option is limma

library(limma) # part of bioconductor

to install:

source("http://www.bioconductor.org/biocLite.R")    
biocLite("limma")
library(limma)

To plot:

vennDiagram(vennCounts(df), circle.col = 1:5)

enter image description here

While not the most straightforward, my nVennR package might be helpful:

library(nVennR)
df = data.frame(A = sample(c(0, 1), 100, replace = T),
            B = sample(c(0, 1), 100, replace = T),
            C = sample(c(0, 1), 100, replace = T),
            D = sample(c(0, 1), 100, replace = T),
            E = sample(c(0, 1), 100, replace = T))
    fromBin <- function(binList){
  result <- 0
  for (b in binList){
    result <- bitwShiftL(result, 1)
    result <- result + b
  }
  return(result)
}

interpretBin <- function(dff){
  nels <- bitwShiftL(1, ncol(dff))
  result <- vector(mode='numeric', length=nels)
  for (r in rownames(dff)){
    n <- fromBin(dff[r,]) + 1
    result[n] <- result[n] + 1
  }
  return(result)
}
regs <- interpretBin(df)
myV <- createVennObj(nSets = ncol(df), sNames = colnames(df), sSizes = regs)
myV <- plotVenn(nVennObj = myV)
myV <- plotVenn(nVennObj = myV)

In this case, it is important to run the last command twice, as shown. The result of the first run is not compacted. After the second run,

Venn diagram from binary

The idea here is that the binary chain is the same strategy the package uses internally, as you can see in the vignette.

Related