Получить список элементов на диаграмме Венна

Диаграмму Венна легко нарисовать с помощью следующего кода:

library(VennDiagram)

set.seed(1) # For reproducibility of results
xx.1 <- list(A = sample(LETTERS, 15), B = sample(LETTERS, 15), 
             C = sample(LETTERS, 15), D = sample(LETTERS, 15))

venn.diagram(xx.1, filename ="1.tiff", height = 1000, width = 1000)

Диаграмма Венна с четырьмя наборами

Но как мне определить элементы в каждом поле? Например, я хотел бы знать, какие две буквы встречаются только в A?

ИЗМЕНИТЬ:

Вот мое решение, оно не идеально, но может дать все пересечения.

library(reshape)
library(R.utils)

## data
A <- data.frame(names = sample(LETTERS, 15), A = 1)
B <- data.frame(names = sample(LETTERS, 15), B = 1)
C <- data.frame(names = sample(LETTERS, 15), C = 1)
D <- data.frame(names = sample(LETTERS, 15), D = 1)

## a merged data frame.
xx.1 <- list(A = A, B= B, C= C, D = D)
xx.2 <- merge_recurse(xx.1)

## function
ff.vennFourItems <- function(X)
{
    ## get the items from venn diagram; for four sets, there are 15 fields;

    vennItems <- list()
    cate.n <- names(X)[2:5]

    for (i in 1:15)
    {
        xx.b <- intToBin(i)
        ## make it four bits;
        if (nchar(xx.b) != 4)
        {
            xx.b <- paste(paste(rep("0", 4 - nchar(xx.b)), collapse = ""), xx.b, sep ="") 
        }

        xx.b.1 <- unlist(strsplit(xx.b, ""))

        xx.1 <- X

        if(xx.b.1[1] == "0") { xx.1 <- xx.1[is.na(xx.1[, 2]), ] }
        else { xx.1 <-  xx.1[!is.na(xx.1[, 2]), ] }

        if(xx.b.1[2] == "0") { xx.1 <- xx.1[is.na(xx.1[, 3]), ] }
        else { xx.1 <-  xx.1[!is.na(xx.1[, 3]), ] }

        if(xx.b.1[3] == "0") { xx.1 <- xx.1[is.na(xx.1[, 4]), ] }
        else { xx.1 <-  xx.1[!is.na(xx.1[, 4]), ] }

        if(xx.b.1[4] == "0") { xx.1 <- xx.1[is.na(xx.1[, 5]), ] }
        else { xx.1 <-  xx.1[!is.na(xx.1[, 5]), ] }

        chipC <-  paste(paste(cate.n, collapse = "#"), xx.b, sep = "***")

        if (dim(xx.1)[1] == 0) 
        {
            xx.2 <- list(genes = dim(xx.1)[1], chipC = chipC, chipCN = i, detailChipS = xx.1, shortL = data.frame(genes = "noInteraction", cl = i, fullCl = chipC))
        }
        else
        {
            xx.2 <- list(genes = dim(xx.1)[1], chipC = chipC, chipCN = i, detailChipS = xx.1, shortL = data.frame(genes = as.character(xx.1[, 1]), cl = i, fullCl = chipC))
        }
        vennItems <- c(vennItems, list(xx.2))
    }

    vennItems
}

xx.3 <- ff.vennFourItems(xx.2)
str(xx.3)
List of 15
 $ :List of 5
  ..$ genes      : int 1
  ..$ chipC      : chr "A#B#C#D***0001"
  ..$ chipCN     : int 1
  ..$ detailChipS:'data.frame': 1 obs. of  5 variables:
  .. ..$ names: Factor w/ 25 levels "A","B","E","F",..: 25
  .. ..$ A    : num NA
  .. ..$ B    : num NA
  .. ..$ C    : num NA
  .. ..$ D    : num 1
  ..$ shortL     :'data.frame': 1 obs. of  3 variables:
  .. ..$ genes : Factor w/ 1 level "Z": 1
  .. ..$ cl    : int 1
  .. ..$ fullCl: Factor w/ 1 level "A#B#C#D***0001": 1
 $ :List of 5
  ..$ genes      : int 0
  ..$ chipC      : chr "A#B#C#D***0010"
  ..$ chipCN     : int 2

person ccshao    schedule 09.05.2014    source источник


Ответы (3)


Взгляните на функции ?intersect, ?union и ?setdiff для извлечения различных полей диаграммы Венна.

Я создал несколько list версий этих двух функций, чтобы лучше разместить элементы в разных отсеках:

Intersect <- function (x) {  
  # Multiple set version of intersect
  # x is a list
  if (length(x) == 1) {
    unlist(x)
  } else if (length(x) == 2) {
    intersect(x[[1]], x[[2]])
  } else if (length(x) > 2){
    intersect(x[[1]], Intersect(x[-1]))
  }
}

Union <- function (x) {  
  # Multiple set version of union
  # x is a list
  if (length(x) == 1) {
    unlist(x)
  } else if (length(x) == 2) {
    union(x[[1]], x[[2]])
  } else if (length(x) > 2) {
    union(x[[1]], Union(x[-1]))
  }
}

Setdiff <- function (x, y) {
  # Remove the union of the y's from the common x's. 
  # x and y are lists of characters.
  xx <- Intersect(x)
  yy <- Union(y)
  setdiff(xx, yy)
}

Итак, если мы хотим увидеть общие элементы (то есть объединение A, B, C и D) или элементы в C и D, но не в A и B в вашем примере, мы делаем что-то вроде следующего.

set.seed(1)
xx.1 <- list(A = sample(LETTERS, 15), 
             B = sample(LETTERS, 15), 
             C = sample(LETTERS, 15), 
             D = sample(LETTERS, 15))
Intersect(xx.1)
#[1] "E" "L"
Setdiff(xx.1[c("C", "D")], xx.1[c("A", "B")])
#[1] "O" "P" "K" "H"

Надеюсь это поможет!

Изменить: систематически получать все компоненты

Некоторым (как мне кажется) умным использованием функции combn, индексации и хорошему пониманию lapply мы можем все элементы систематически:

# Create a list of all the combinations
combs <- 
  unlist(lapply(1:length(xx.1), 
                function(j) combn(names(xx.1), j, simplify = FALSE)),
         recursive = FALSE)
names(combs) <- sapply(combs, function(i) paste0(i, collapse = ""))
str(combs)
#List of 15
# $ A   : chr "A"
# $ B   : chr "B"
# $ C   : chr "C"
# $ D   : chr "D"
# $ AB  : chr [1:2] "A" "B"
# $ AC  : chr [1:2] "A" "C"
# $ AD  : chr [1:2] "A" "D"
# $ BC  : chr [1:2] "B" "C"
# $ BD  : chr [1:2] "B" "D"
# $ CD  : chr [1:2] "C" "D"
# $ ABC : chr [1:3] "A" "B" "C"
# $ ABD : chr [1:3] "A" "B" "D"
# $ ACD : chr [1:3] "A" "C" "D"
# $ BCD : chr [1:3] "B" "C" "D"
# $ ABCD: chr [1:4] "A" "B" "C" "D"

# "A" means "everything in A minus all others"
# "A", "B" means "everything in "A" and "B" minus all others" and so on
elements <- 
  lapply(combs, function(i) Setdiff(xx.1[i], xx.1[setdiff(names(xx.1), i)]))

n.elements <- sapply(elements, length)
print(n.elements)
#   A    B    C    D   AB   AC   AD   BC   BD   CD  ABC  ABD  ACD  BCD ABCD 
#   2    2    0    0    1    2    2    0    3    4    4    1    1    2    2 
person Anders Ellern Bilgrau    schedule 09.05.2014
comment
Было бы здорово добавить результат Союза! (Просто чтобы получить полный пример) Я сделал более или менее то же самое с более сложным процессом, но ваше решение простое и блестящее !! - person llrs; 09.05.2014
comment
@AEBilgrau, спасибо. Есть ли способ получить все 15 полей систематически? - person ccshao; 09.05.2014
comment
@AEBilgrau, действительно молодец !. - person ccshao; 09.05.2014
comment
@Llopis Я также добавил рекурсивный Union. Хорошее предложение, спасибо. - person Anders Ellern Bilgrau; 09.05.2014
comment
Ответ от @ al-ash кажется более простым в использовании. - person FBB; 18.06.2017
comment
@FBB Действительно, есть. Эта виньетка из пакета gplots хорошо объясняет функциональность . Однако я не думаю, что эти функции существовали более 3 лет назад, когда я ответил на вопрос. - person Anders Ellern Bilgrau; 19.06.2017

Вы также можете использовать venn в gplots пакете, чтобы получить список элементов в каждом разделе диаграммы Венна («ItemsList»). Учитывая ваш список xx.1, он должен быть:

ItemsList <- venn(xx.1, show.plot = FALSE)

ItemsList содержит:

  1. матрица всех разделов диаграммы и количество элементов в этих разделах и
  2. список элементов в каждом разделе диаграммы Венна.

чтобы получить подсчеты:

lengths(attributes(ItemsList)$intersections)
# A       B     A:B     A:C     A:D     B:D     C:D   A:B:C   A:B:D   A:C:D   B:C:D A:B:C:D 
# 2       2       1       2       2       3       4       4       1       1       2       2
person al-ash    schedule 16.01.2017

В пакете VennDiagram есть функция под названием «calculate.overlap».

overlap <- calculate.overlap(xx.1)

И перекрытие - это то, что вам нужно:

$a6
[1] "C"

$a12
[1] "Z" "D" "R"

$a11
[1] "Y" "O" "V"

$a5
[1] "X" "B"

$a7
[1] "H" "F" "P" "S"

$a15
[1] "I"

$a4
[1] "L" "K" "G"

$a10
[1] "W" "J"

$a13
[1] "U"

$a8
character(0)

$a2
character(0)

$a9
character(0)

$a14
[1] "N" "M"

$a1
[1] "E"

$a3
[1] "Q" "A" "T"
person Sheng Qin    schedule 09.05.2017
comment
получить названия перекрестков, т.е. что означает a1, не представляется возможным. - person ccshao; 20.12.2017