upset-plot
UpSet與傳統(tǒng)方法(即維恩圖)相比,UpSet 圖提供了一種可視化多個(gè)集合的交集的有效方法。通過R中的UpSetR 包中實(shí)現(xiàn)。在這里,我們使用ComplexHeatmap 包重新實(shí)現(xiàn)了 UpSet 圖,并進(jìn)行了一些改進(jìn)。
8.1 輸入數(shù)據(jù)
為了表示多個(gè)集合,變量可以表示為:
- 一個(gè)集合列表,其中每個(gè)集合都是一個(gè)向量,例如:
list(set1 = c("a", "b", "c"),
set2 = c("b", "c", "d", "e"),
...)
- 一個(gè)二進(jìn)制矩陣/數(shù)據(jù)框,其中行是元素,列是集合,例如:
set1 set2 set3
h 1 1 1
t 1 0 1
j 1 0 0
u 1 0 1
w 1 0 0
...
例如,在矩陣中的t行表示:t在集合set1 中,不在集合set2 中,在集合set3 中。(只有在該矩陣是邏輯矩陣時(shí)才有效)
如果變量是數(shù)據(jù)框,則只使用二進(jìn)制列(僅包含 0 和 1)和邏輯列。
兩種格式都可以用于制作 UpSet 圖,用戶仍然可以使用 list_to_matrix()從列表到二進(jìn)制矩陣的轉(zhuǎn)換。
lt = list(set1 = c("a", "b", "c"),
set2 = c("b", "c", "d", "e"))
list_to_matrix(lt)
## set1 set2
## a 1 0
## b 1 1
## c 1 1
## d 0 1
## e 0 1
您還可以在list_to_matrix()下位置設(shè)置通用集:
list_to_matrix(lt, universal = letters[1:10])
## set1 set2
## a 1 0
## b 1 1
## c 1 1
## d 0 1
## e 0 1
## f 0 0
## g 0 0
## h 0 0
## i 0 0
## j 0 0
如果全集沒有完全覆蓋輸入集,那些不在全集中的元素將被刪除:
list_to_matrix(lt, universal = letters[1:4])
## set1 set2
## a 1 0
## b 1 1
## c 1 1
## d 0 1
- 該集合可以是基因組區(qū)間,那么它只能表示為
GRanges/IRanges對(duì)象的列表。
list(set1 = GRanges(...),
set2 = GRanges(...),
...)
8.2 upset模式
例如,對(duì)于三個(gè)集合(A,B,C),選擇在或不在集合中的元素的所有組合編碼如下:
A B C
1 1 1
1 1 0
1 0 1
0 1 1
1 0 0
0 1 0
0 0 1
1 表示選擇該集合,0 表示不選擇該集合。例如,1 1 0意味著選擇集合 A、B 而不選擇集合 C。注意沒有0 0 0,因?yàn)檫@里的背景集合不感興趣。在本節(jié)的以下部分,我們將A、B和C稱為集合,將每個(gè)組合稱為組合集。整個(gè)二元矩陣稱為組合矩陣。
UpSet 圖將每個(gè)組合集的大小可視化。有了每個(gè)組合集的二進(jìn)制代碼,接下來我們需要定義如何計(jì)算該組合集的大小。共有三種模式:
distinct模式: 1 表示在該集合中,0 表示不在該集合中,然后1 1 0表示A和B是集合元素,而C不是集合中的元素(setdiff(intersect(A, B), C)) 。在這種模式下,七個(gè)組合集就可以看成維恩圖中的七個(gè)分區(qū),它們是相互排斥的。intersect模式: 1 表示在該集合中,不考慮0,然后1 1 0表示A和B是集合元素,它們也可以在或不在C中(intersect(A, B))。在此模式下,七個(gè)組合集可以重疊。union模式: 1 表示在該集合中,不考慮0。當(dāng)有多個(gè)1時(shí),關(guān)系為OR。然后,1 1 0表示A或B集合中的元素,它們也可以在或不在 C (union(A, B)) 中。在此模式下,七個(gè)組合集可以重疊。
三種模式如下圖所示:

8.3 生成組合矩陣
該make_comb_mat()函數(shù)生成組合矩陣并計(jì)算集合和組合集合的大小。輸入可以是單個(gè)變量或名稱-值對(duì):
set.seed(123)
lt = list(a = sample(letters, 5),
b = sample(letters, 10),
c = sample(letters, 15))
m1 = make_comb_mat(lt)
m1
## A combination matrix with 3 sets and 7 combinations.
## ranges of combination set size: c(1, 8).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
## x 100 1
## x 010 3
## x 001 8
##
## Sets are:
## set size
## a 5
## b 10
## c 15
m2 = make_comb_mat(a = lt$a, b = lt$b, c = lt$c)
m3 = make_comb_mat(list_to_matrix(lt))
m1,m2和m3結(jié)果是相同的。
模式由mode參數(shù)控制:
m1 = make_comb_mat(lt) # the default mode is `distinct`
m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
不同模式下的 UpSet 圖將在后面演示。
當(dāng)集合過多時(shí),可以通過集合大小對(duì)集合進(jìn)行預(yù)過濾(min_set_size和top_n_sets)。min_set_size 控制集合的最小大小,top_n_sets控制具有最大大小的頂部集合的數(shù)量。
m1 = make_comb_mat(lt, min_set_size = 6)
m2 = make_comb_mat(lt, top_n_sets = 2)
集合的子集會(huì)影響組合集大小的計(jì)算,這就是為什么需要在組合矩陣生成步驟對(duì)其進(jìn)行控制。組合集的子集可以直接通過對(duì)矩陣進(jìn)行子集來進(jìn)行:
m = make_comb_mat(lt)
m[1:4]
## A combination matrix with 3 sets and 4 combinations.
## ranges of combination set size: c(1, 4).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
##
## Sets are:
## set size
## a 5
## b 10
## c 15
make_comb_mat() 還允許指定全集,以便還考慮包含不屬于任何集合的元素的補(bǔ)集。
m = make_comb_mat(lt, universal_set = letters)
m
## A combination matrix with 3 sets and 8 combinations.
## ranges of combination set size: c(1, 8).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
## x 100 1
## x 010 3
## x 001 8
## 000 6
##
## Sets are:
## set size
## a 5
## b 10
## c 15
## complement 6
全集可以小于所有集合的并集,那么對(duì)于每個(gè)集合,只考慮與全集的交集。
m = make_comb_mat(lt, universal_set = letters[1:10])
m
## A combination matrix with 3 sets and 5 combinations.
## ranges of combination set size: c(1, 3).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x 110 1
## x x 101 1
## x x 011 2
## x 001 3
## 000 3
##
## Sets are:
## set size
## a 2
## b 3
## c 6
## complement 3
如果您已經(jīng)知道補(bǔ)碼的大小,則可以直接設(shè)置 complement_size參數(shù)。
m = make_comb_mat(lt, complement_size = 5)
m
## A combination matrix with 3 sets and 8 combinations.
## ranges of combination set size: c(1, 8).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
## x 100 1
## x 010 3
## x 001 8
## 000 5
##
## Sets are:
## set size
## a 5
## b 10
## c 15
## complement 5
當(dāng)輸入的矩陣不屬于任何集合的元素時(shí),這些元素被視為補(bǔ)集。
x = list_to_matrix(lt, universal_set = letters)
m = make_comb_mat(x)
m
## A combination matrix with 3 sets and 8 combinations.
## ranges of combination set size: c(1, 8).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
## x 100 1
## x 010 3
## x 001 8
## 000 6
##
## Sets are:
## set size
## a 5
## b 10
## c 15
## complement 6
接下來我們演示第二個(gè)示例,其中集合是基因組區(qū)域。 當(dāng)集合是基因組區(qū)域時(shí),大小計(jì)算為每個(gè)集合中區(qū)域?qū)挾鹊目偤停ㄒ簿褪侵笁A基對(duì)的總數(shù))。
library(circlize)
library(GenomicRanges)
lt2 = lapply(1:4, function(i) generateRandomBed())
lt2 = lapply(lt2, function(df) GRanges(seqnames = df[, 1],
ranges = IRanges(df[, 2], df[, 3])))
names(lt2) = letters[1:4]
m2 = make_comb_mat(lt2)
m2
## A combination matrix with 4 sets and 15 combinations.
## ranges of combination set size: c(184941701, 199900416).
## mode for the combination size: distinct.
## sets are on rows.
##
## Top 8 combination sets are:
## a b c d code size
## x x 0011 199900416
## x 1000 199756519
## x x x 1011 198735008
## x x x x 1111 197341532
## x x x 1110 197137160
## x x x 1101 194569926
## x x 1001 194462988
## x x 1010 192670258
##
## Sets are:
## set size
## a 1566783009
## b 1535968265
## c 1560549760
## d 1552480645
我們不建議將兩組基因組區(qū)域的交集用于區(qū)域數(shù)。有兩個(gè)原因:
1. 取值不對(duì)稱,即set1中測(cè)得的相交區(qū)域數(shù)并不總是與set2中測(cè)得的相交區(qū)域數(shù)相同,因此很難為set1和 set2之間的交集賦值;
2. 如果 set1 中的一個(gè)長區(qū)域與 set2 中的另一個(gè)長區(qū)域重疊,但只有幾個(gè)堿基對(duì),那么說這兩個(gè)區(qū)域在兩組中是常見的是否有意義?
通用集也適用于作為基因組區(qū)域的集合。
8.4 upset實(shí)用功能
make_comb_mat()返回一個(gè)矩陣,也在comb_mat類中。有一些實(shí)用函數(shù)可以應(yīng)用于這個(gè)comb_mat對(duì)象:
-
set_name(): 集合名稱。 -
comb_name(): 組合集名稱。組合集的名稱被格式化為一串二進(jìn)制位。例如對(duì)于三組A , B , C,名稱為“101”的組合集合對(duì)應(yīng)于選擇集合 A,不選擇集合B和選擇集合C。 -
set_size(): 設(shè)置的大小。 -
comb_size():組合套裝尺寸。 -
comb_degree():組合集的度數(shù)是選擇的集數(shù)。 -
t():轉(zhuǎn)置組合矩陣。默認(rèn)情況下make_comb_mat()生成一個(gè)矩陣,其中集合在行上,組合集在列上,它們?cè)?UpSet 圖上也是如此。通過對(duì)組合矩陣進(jìn)行轉(zhuǎn)置,可以在 UpSet 圖上切換集合和組合集合的位置。 -
extract_comb():提取指定組合集中的元素。用法將在后面解釋。 - 用于對(duì)矩陣進(jìn)行子集化的函數(shù)。
快速示例是:
m = make_comb_mat(lt)
set_name(m)
## [1] "a" "b" "c"
comb_name(m)
## [1] "111" "110" "101" "011" "100" "010" "001"
set_size(m)
## a b c
## 5 10 15
comb_size(m)
## 111 110 101 011 100 010 001
## 2 1 1 4 1 3 8
comb_degree(m)
## 111 110 101 011 100 010 001
## 3 2 2 2 1 1 1
t(m)
## A combination matrix with 3 sets and 7 combinations.
## ranges of combination set size: c(1, 8).
## mode for the combination size: distinct.
## sets are on columns
##
## Combination sets are:
## a b c code size
## x x x 111 2
## x x 110 1
## x x 101 1
## x x 011 4
## x 100 1
## x 010 3
## x 001 8
##
## Sets are:
## set size
## a 5
## b 10
## c 15
對(duì)于extract_comb()的使用,有效的組合集名稱應(yīng)該是comb_name()。請(qǐng)注意,組合集中的元素取決于 make_comb_mat()中設(shè)置的“mode”。
extract_comb(m, "101")
## [1] "j"
以及作為基因組區(qū)域的集合的示例:
# `lt2` was generated in the previous section
m2 = make_comb_mat(lt2)
set_size(m2)
## a b c d
## 1566783009 1535968265 1560549760 1552480645
comb_size(m2)
## 1111 1110 1101 1011 0111 1100 1010 1001
## 197341532 197137160 194569926 198735008 191312455 192109618 192670258 194462988
## 0110 0101 0011 1000 0100 0010 0001
## 191359036 184941701 199900416 199756519 187196837 192093895 191216619
現(xiàn)在extract_comb()返回相應(yīng)組合集中的基因組區(qū)域。
extract_comb(m2, "1010")
## GRanges object with 5063 ranges and 0 metadata columns:
## seqnames ranges strand
## <Rle> <IRanges> <Rle>
## [1] chr1 255644-258083 *
## [2] chr1 306114-308971 *
## [3] chr1 1267493-1360170 *
## [4] chr1 2661311-2665736 *
## [5] chr1 3020553-3030645 *
## ... ... ... ...
## [5059] chrY 56286079-56286864 *
## [5060] chrY 57049541-57078332 *
## [5061] chrY 58691055-58699756 *
## [5062] chrY 58705675-58716954 *
## [5063] chrY 58765097-58776696 *
## -------
## seqinfo: 24 sequences from an unspecified genome; no seqlengths
使用comb_size()和comb_degree(),我們可以將組合矩陣過濾為:
m = make_comb_mat(lt)
# combination set size >= 4
m[comb_size(m) >= 4]
## A combination matrix with 3 sets and 2 combinations.
## ranges of combination set size: c(4, 8).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x 011 4
## x 001 8
##
## Sets are:
## set size
## a 5
## b 10
## c 15
# combination set degree == 2
m[comb_degree(m) == 2]
## A combination matrix with 3 sets and 3 combinations.
## ranges of combination set size: c(1, 4).
## mode for the combination size: distinct.
## sets are on rows.
##
## Combination sets are:
## a b c code size
## x x 110 1
## x x 101 1
## x x 011 4
##
## Sets are:
## set size
## a 5
## b 10
## c 15
對(duì)于補(bǔ)集,這個(gè)特殊組合集的名稱僅由零組成。
m2 = make_comb_mat(lt, universal_set = letters)
comb_name(m2) # see the first element
## [1] "111" "110" "101" "011" "100" "010" "001" "000"
comb_degree(m2)
## 111 110 101 011 100 010 001 000
## 3 2 2 2 1 1 1 0
如果在make_comb_mat()中設(shè)置universal_set,extract_comb()則可以應(yīng)用于補(bǔ)集。
m2 = make_comb_mat(lt, universal_set = letters)
extract_comb(m2, "000")
## [1] "a" "b" "f" "p" "u" "z"
m2 = make_comb_mat(lt, universal_set = letters[1:10])
extract_comb(m2, "000")
## [1] "a" "b" "f"
當(dāng)設(shè)置universal_set,extract_comb()也適用于基因組區(qū)域集。
在前面的例子中,我們演示了使用“一維索引”,例如:
m[comb_degree(m) == 2]
由于組合矩陣本質(zhì)上是一個(gè)矩陣,因此索引也可以應(yīng)用于兩個(gè)維度。在默認(rèn)設(shè)置中,集合在行上,組合集在列上,因此,矩陣第一維上的索引對(duì)應(yīng)于集合,第二維上的索引對(duì)應(yīng)于組合集:
# by set names
m[c("a", "b", "c"), ]
# by nummeric indicies
m[3:1, ]
可以通過以下方式將新的空集添加到組合矩陣中:
# `d` is the new empty set
m[c("a", "b", "c", "d"), ]
注意當(dāng)指定的索引沒有覆蓋原始組合矩陣中的所有非空集合時(shí),會(huì)重新計(jì)算組合矩陣,因?yàn)樗鼤?huì)影響組合集合中的值:
# if `c` is a non-empty set
m[c("a", "b"),]
與組合集對(duì)應(yīng)的第二維上的子集類似:
# reorder
m[, 5:1]
# take a subset
m[, 1:3]
# by charater indices
m[, c("110", "101", "011")]
也可以通過設(shè)置字符索引來添加新的空組合集:
m[m, c(comb_name(m), "100")]
只有當(dāng)集合索引覆蓋所有非空集合時(shí),才能同時(shí)在兩個(gè)維度上設(shè)置索引:
m[3:1, 5:1]
# this will throw an error because `c` is a non-empty set
m[c("a", "b"), 5:1]
如果組合矩陣進(jìn)行了轉(zhuǎn)置,則需要切換矩陣的集索引和組合集索引的邊距。
tm = t(m)
tm[reverse(comb_name(tm)), reverse(set_name(tm))]
如果僅將組合集的索引設(shè)置為一維,則它會(huì)自動(dòng)適用于轉(zhuǎn)置或未轉(zhuǎn)置的兩個(gè)矩陣:
m[1:5]
tm[1:5]
8.5 生成upset圖
生成 UpSet 圖非常簡(jiǎn)單,用戶只需將組合矩陣發(fā)送到UpSet()函數(shù)即可:
m = make_comb_mat(lt)
UpSet(m)

默認(rèn)情況下,集合按大小排序,組合集合按度數(shù)(選擇的集合數(shù))排序。
訂單由set_order和控制comb_order:
UpSet(m, set_order = c("a", "b", "c"), comb_order = order(comb_size(m)))

點(diǎn)的顏色、點(diǎn)的大小和線段的線寬由pt_size、comb_col和控制 lwd。comb_col是組合集對(duì)應(yīng)的向量。在下面的代碼中,由于comb_degree(m)返回一個(gè)整數(shù)向量,我們只將它用作顏色向量的索引。
UpSet(m, pt_size = unit(5, "mm"), lwd = 3,
comb_col = c("red", "blue", "black")[comb_degree(m)])

背景顏色(代表集合的矩形和圓點(diǎn)沒有被選中)由bg_col、bg_pt_col控制。bg_col 的長度可以是1或2。
UpSet(m, comb_col = "#0000FF", bg_col = "#F0F0FF", bg_pt_col = "#CCCCFF")

UpSet(m, comb_col = "#0000FF", bg_col = c("#F0F0FF", "#FFF0F0"), bg_pt_col = "#CCCCFF")

組合矩陣轉(zhuǎn)置將集合切換為列,將組合集合切換為行。
UpSet(t(m))

正如我們所介紹的,如果對(duì)組合集進(jìn)行子集化,也可以將矩陣的子集可視化:
UpSet(m[comb_size(m) >= 4])
UpSet(m[comb_degree(m) == 2])

以下比較了make_comb_mat()中的不同模式:
m1 = make_comb_mat(lt) # the default mode is `distinct`
m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
UpSet(m1)
UpSet(m2)
UpSet(m3)

對(duì)于包含補(bǔ)集的圖,有一個(gè)額外的列顯示此補(bǔ)集不與任何集重疊(所有點(diǎn)均為灰色)。
m2 = make_comb_mat(lt, universal_set = letters)
UpSet(m2)

請(qǐng)記住,如果您已經(jīng)知道補(bǔ)集的大小,則可以直接通過make_comb_mat()中的complement_size參數(shù)分配它。
m2 = make_comb_mat(lt, complement_size = 10)
UpSet(m2)

對(duì)于全集小于所有集合的并集的情況:
m2 = make_comb_mat(lt, universal_set = letters[1:10])
UpSet(m2)

在某些情況下,您可能有補(bǔ)集但不想顯示它,尤其是當(dāng)輸入為make_comb_mat()已包含補(bǔ)集的矩陣時(shí),您可以按組合度進(jìn)行過濾。
x = list_to_matrix(lt, universal_set = letters)
m2 = make_comb_mat(x)
m2 = m2[comb_degree(m2) > 0]
UpSet(m2)

8.6 UpSet 圖作為熱圖
在 UpSet 圖中,主要成分是組合矩陣,兩側(cè)是表示集合大小和組合集合的條形圖,因此,將其實(shí)現(xiàn)為“熱圖”是非常簡(jiǎn)單的,其中熱圖是用點(diǎn)和段定義,兩個(gè)條形圖是由anno_barplot().
默認(rèn)的頂部注釋是:
HeatmapAnnotation("Intersection\nsize" = anno_barplot(comb_size(m),
border = FALSE, gp = gpar(fill = "black"), height = unit(3, "cm")),
annotation_name_side = "left", annotation_name_rot = 0)
此頂部注釋被包裹在upset_top_annotation()中,其中僅包含翻轉(zhuǎn)頂部條形圖注釋。大多數(shù)參數(shù) upset_top_annotation()直接轉(zhuǎn)到anno_barplot(),例如設(shè)置條形的顏色:
UpSet(m, top_annotation = upset_top_annotation(m,
gp = gpar(col = comb_degree(m))))

控制數(shù)據(jù)范圍和軸:
UpSet(m, top_annotation = upset_top_annotation(m,
ylim = c(0, 15),
bar_width = 1,
axis_param = list(side = "right", at = c(0, 5, 10, 15),
labels = c("zero", "five", "ten", "fifteen"))))

控制注釋名稱:
UpSet(m, top_annotation = upset_top_annotation(m,
annotation_name_rot = 90,
annotation_name_side = "right",
axis_param = list(side = "right")))

右注釋的設(shè)置非常相似:
UpSet(m, right_annotation = upset_right_annotation(m,
ylim = c(0, 30),
gp = gpar(fill = "green"),
annotation_name_side = "top",
axis_param = list(side = "top")))

upset_top_annotation()和upset_right_annotation()可以自動(dòng)識(shí)別集合是在行上還是列上。
upset_top_annotation()和upset_right_annotation()只包含一個(gè)條形圖注釋。如果用戶想要添加更多的注釋,則需要手動(dòng)構(gòu)造一個(gè)HeatmapAnnotation具有多個(gè)注釋的對(duì)象。
要在頂部添加更多注釋:
UpSet(m, top_annotation = HeatmapAnnotation(
degree = as.character(comb_degree(m)),
"Intersection\nsize" = anno_barplot(comb_size(m),
border = FALSE,
gp = gpar(fill = "black"),
height = unit(2, "cm")
),
annotation_name_side = "left",
annotation_name_rot = 0))

要在右側(cè)添加更多注釋:
UpSet(m, right_annotation = rowAnnotation(
"Set size" = anno_barplot(set_size(m),
border = FALSE,
gp = gpar(fill = "black"),
width = unit(2, "cm")
),
group = c("group1", "group1", "group2")))

將右側(cè)注釋移動(dòng)到組合矩陣的左側(cè),請(qǐng)使用upset_left_annotation():
UpSet(m, left_annotation = upset_left_annotation(m))

在條形頂部添加數(shù)字:
UpSet(m, top_annotation = upset_top_annotation(m, add_numbers = TRUE),
right_annotation = upset_right_annotation(m, add_numbers = TRUE))

返回的對(duì)象UpSet()實(shí)際上是一個(gè)Heatmap類對(duì)象,因此,您可以通過+或%v%將其添加到其他熱圖和注釋中。
ht = UpSet(m)
class(ht)
## [1] "Heatmap"
## attr(,"package")
## [1] "ComplexHeatmap"
ht + Heatmap(1:3, name = "foo", width = unit(5, "mm")) +
rowAnnotation(bar = anno_points(1:3))

ht %v% Heatmap(rbind(1:7), name = "foo", row_names_side = "left",
height = unit(5, "mm")) %v%
HeatmapAnnotation(bar = anno_points(1:7),
annotation_name_side = "left")

添加多個(gè) UpSet 圖:
m1 = make_comb_mat(lt, mode = "distinct")
m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
UpSet(m1, row_title = "distinct mode") %v%
UpSet(m2, row_title = "intersect mode") %v%
UpSet(m3, row_title = "union mode")

或者先將所有組合矩陣轉(zhuǎn)置,然后水平相加:
m1 = make_comb_mat(lt, mode = "distinct")
m2 = make_comb_mat(lt, mode = "intersect")
m3 = make_comb_mat(lt, mode = "union")
UpSet(t(m1), column_title = "distinct mode") +
UpSet(t(m2), column_title = "intersect mode") +
UpSet(t(m3), column_title = "union mode")

三個(gè)組合矩陣實(shí)際上是相同的,將它們繪制三次是多余的。借助ComplexHeatmap包中的功能,我們可以直接添加三個(gè)條形圖注釋。
top_ha = HeatmapAnnotation(
"distict" = anno_barplot(comb_size(m1),
gp = gpar(fill = "black"), height = unit(2, "cm")),
"intersect" = anno_barplot(comb_size(m2),
gp = gpar(fill = "black"), height = unit(2, "cm")),
"union" = anno_barplot(comb_size(m3),
gp = gpar(fill = "black"), height = unit(2, "cm")),
gap = unit(2, "mm"), annotation_name_side = "left", annotation_name_rot = 0)
# the same for using m2 or m3
UpSet(m1, top_annotation = top_ha)

組合矩陣轉(zhuǎn)置時(shí)類似:
right_ha = rowAnnotation(
"distict" = anno_barplot(comb_size(m1),
gp = gpar(fill = "black"), width = unit(2, "cm")),
"intersect" = anno_barplot(comb_size(m2),
gp = gpar(fill = "black"), width = unit(2, "cm")),
"union" = anno_barplot(comb_size(m3),
gp = gpar(fill = "black"), width = unit(2, "cm")),
gap = unit(2, "mm"), annotation_name_side = "bottom")
# the same for using m2 or m3
UpSet(t(m1), right_annotation = right_ha)

初始 UpSet 實(shí)現(xiàn),組合集大小也繪制在條形圖的頂部。這里我們不直接支持,但是可以通過decorate_annotation()函數(shù)手動(dòng)添加尺寸。請(qǐng)參閱以下示例:
ht = draw(UpSet(m))
od = column_order(ht)
cs = comb_size(m)
decorate_annotation("intersection_size", {
grid.text(cs[od], x = seq_along(cs), y = unit(cs[od], "native") + unit(2, "pt"),
default.units = "native", just = "bottom", gp = gpar(fontsize = 8))
})

我們不直接支持將組合集大小添加到繪圖中的原因有幾個(gè):
1. 添加新文本意味著向函數(shù)添加幾個(gè)新參數(shù),例如圖形參數(shù)的參數(shù)、旋轉(zhuǎn)、位置、條形的邊距,這將使功能變的重復(fù)。
2.需要正確計(jì)算barplot注釋的ylim,讓文字不超過注釋區(qū)域。
3、使用decoration_annotation()更靈活,不僅可以添加大小,還可以添加自定義文本。
8.7 電影數(shù)據(jù)集的例子
UpsetR 包還提供了一個(gè)movies 數(shù)據(jù)集,其中包含 3883 部電影的 17 個(gè)流派。首先加載數(shù)據(jù)集。
movies = read.csv(system.file("extdata", "movies.csv", package = "UpSetR"),
header = TRUE, sep = ";")
head(movies) # `make_comb_mat()` automatically ignores the first two columns
## Name ReleaseDate Action Adventure Children
## 1 Toy Story (1995) 1995 0 0 1
## 2 Jumanji (1995) 1995 0 1 1
## 3 Grumpier Old Men (1995) 1995 0 0 0
## 4 Waiting to Exhale (1995) 1995 0 0 0
## 5 Father of the Bride Part II (1995) 1995 0 0 0
## 6 Heat (1995) 1995 1 0 0
## Comedy Crime Documentary Drama Fantasy Noir Horror Musical Mystery Romance
## 1 1 0 0 0 0 0 0 0 0 0
## 2 0 0 0 0 1 0 0 0 0 0
## 3 1 0 0 0 0 0 0 0 0 1
## 4 1 0 0 1 0 0 0 0 0 0
## 5 1 0 0 0 0 0 0 0 0 0
## 6 0 1 0 0 0 0 0 0 0 0
## SciFi Thriller War Western AvgRating Watches
## 1 0 0 0 0 4.15 2077
## 2 0 0 0 0 3.20 701
## 3 0 0 0 0 3.02 478
## 4 0 0 0 0 2.73 170
## 5 0 0 0 0 3.01 296
## 6 0 1 0 0 3.88 940
要生成與此示例相同的 UpSet 圖:
m = make_comb_mat(movies, top_n_sets = 6)
m
## A combination matrix with 6 sets and 39 combinations.
## ranges of combination set size: c(1, 1028).
## mode for the combination size: distinct.
## sets are on rows.
##
## Top 8 combination sets are:
## Action Comedy Drama Horror Romance Thriller code size
## x 001000 1028
## x 010000 698
## x 000100 216
## x 100000 206
## x 000001 183
## x x 011000 180
## x x 010010 160
## x x 001010 158
##
## Sets are:
## set size
## Action 503
## Comedy 1200
## Drama 1603
## Horror 343
## Romance 471
## Thriller 492
## complement 2
m = m[comb_degree(m) > 0]
UpSet(m)

以下代碼使其看起來與原始圖更相似。代碼有點(diǎn)長,但大部分代碼主要是自定義注釋和行/列順序。
ss = set_size(m)
cs = comb_size(m)
ht = UpSet(m,
set_order = order(ss),
comb_order = order(comb_degree(m), -cs),
top_annotation = HeatmapAnnotation(
"Genre Intersections" = anno_barplot(cs,
ylim = c(0, max(cs)*1.1),
border = FALSE,
gp = gpar(fill = "black"),
height = unit(4, "cm")
),
annotation_name_side = "left",
annotation_name_rot = 90),
left_annotation = rowAnnotation(
"Movies Per Genre" = anno_barplot(-ss,
baseline = 0,
axis_param = list(
at = c(0, -500, -1000, -1500),
labels = c(0, 500, 1000, 1500),
labels_rot = 0),
border = FALSE,
gp = gpar(fill = "black"),
width = unit(4, "cm")
),
set_name = anno_text(set_name(m),
location = 0.5,
just = "center",
width = max_text_width(set_name(m)) + unit(4, "mm"))
),
right_annotation = NULL,
show_row_names = FALSE)
ht = draw(ht)
od = column_order(ht)
decorate_annotation("Genre Intersections", {
grid.text(cs[od], x = seq_along(cs), y = unit(cs[od], "native") + unit(2, "pt"),
default.units = "native", just = c("left", "bottom"),
gp = gpar(fontsize = 6, col = "#404040"), rot = 45)
})

在movies數(shù)據(jù)集中,還有一列AvgRating給出了每部電影的評(píng)分,接下來我們根據(jù)評(píng)分將所有電影分為五組。
genre = c("Action", "Romance", "Horror", "Children", "SciFi", "Documentary")
rating = cut(movies$AvgRating, c(0, 1, 2, 3, 4, 5))
m_list = tapply(seq_len(nrow(movies)), rating, function(ind) {
m = make_comb_mat(movies[ind, genre, drop = FALSE])
m[comb_degree(m) > 0]
})
中的組合矩陣m_list可能有不同的組合集:
sapply(m_list, comb_size)
## $`(0,1]`
## 010000 001000 000100 000001
## 1 2 1 1
##
## $`(1,2]`
## 101010 100110 110000 101000 100100 100010 001010 100000 010000 001000 000100
## 1 1 1 4 5 5 8 14 7 38 14
## 000010 000001
## 3 2
##
## $`(2,3]`
## 101010 110000 101000 100100 100010 010100 010010 001010 000110 100000 010000
## 4 8 2 6 35 3 1 27 7 126 99
## 001000 000100 000010 000001
## 142 77 27 9
##
## $`(3,4]`
## 110010 101010 100110 110000 101000 100010 011000 010100 010010 001100 001010
## 1 6 1 20 6 45 3 4 4 1 11
## 000110 100000 010000 001000 000100 000010 000001
## 5 176 276 82 122 66 87
##
## $`(4,5]`
## 110010 101010 110000 101000 100010 100000 010000 001000 000100 000010 000001
## 1 1 4 1 6 23 38 4 4 10 28
為了用 UpSet 圖在多個(gè)組之間進(jìn)行比較,我們需要對(duì)所有矩陣進(jìn)行歸一化,使它們具有相同的集合和相同的組合集。 normalize_comb_mat()基本上將零添加到以前不存在的新組合集。
m_list = normalize_comb_mat(m_list)
sapply(m_list, comb_size)
## (0,1] (1,2] (2,3] (3,4] (4,5]
## 110001 0 1 0 1 0
## 100101 0 1 4 6 1
## 100011 0 0 0 1 1
## 110000 0 5 6 0 0
## 100100 0 4 2 6 1
## 100010 0 1 8 20 4
## 100001 0 5 35 45 6
## 010100 0 0 0 1 0
## 010010 0 0 3 4 0
## 010001 0 0 7 5 0
## 000110 0 0 0 3 0
## 000101 0 8 27 11 0
## 000011 0 0 1 4 0
## 100000 0 14 126 176 23
## 010000 1 14 77 122 4
## 001000 1 2 9 87 28
## 000100 2 38 142 82 4
## 000010 1 7 99 276 38
## 000001 0 3 27 66 10
我們計(jì)算兩個(gè)條形圖的范圍:
max_set_size = max(sapply(m_list, set_size))
max_comb_size = max(sapply(m_list, comb_size))
最后,我們垂直添加五個(gè) UpSet 圖:
ht_list = NULL
for(i in seq_along(m_list)) {
ht_list = ht_list %v%
UpSet(m_list[[i]], row_title = paste0("rating in", names(m_list)[i]),
set_order = NULL, comb_order = NULL,
top_annotation = upset_top_annotation(m_list[[i]], ylim = c(0, max_comb_size)),
right_annotation = upset_right_annotation(m_list[[i]], ylim = c(0, max_set_size)))
}
ht_list

比較五個(gè) UpSet 圖后,我們可以看到大多數(shù)電影的評(píng)分在 2 到 4 之間??植榔脑u(píng)分往往較低,而愛情片的評(píng)分往往較高。
除了直接比較組合集的大小之外,我們還可以將相對(duì)分?jǐn)?shù)與完整集進(jìn)行比較。在下面的代碼中,我們刪除了c(0, 1]組,因?yàn)槟抢锏碾娪皵?shù)量太少。
m_list = m_list[-1]
max_set_size = max(sapply(m_list, set_size))
rel_comb_size = sapply(m_list, function(m) {
s = comb_size(m)
# because the combination matrix is generated under "distinct" mode
# the sum of `s` is the size of the full set
s/sum(s)
})
ht_list = NULL
for(i in seq_along(m_list)) {
ht_list = ht_list %v%
UpSet(m_list[[i]], row_title = paste0("rating in", names(m_list)[i]),
set_order = NULL, comb_order = NULL,
top_annotation = HeatmapAnnotation(
"Relative\nfraction" = anno_barplot(
rel_comb_size[, i],
ylim = c(0, 0.5),
gp = gpar(fill = "black"),
border = FALSE,
height = unit(2, "cm"),
),
annotation_name_side = "left",
annotation_name_rot = 0),
right_annotation = upset_right_annotation(m_list[[i]],
ylim = c(0, max_set_size))
)
}
ht_list

現(xiàn)在的趨勢(shì)更加明顯,恐怖片評(píng)分低,紀(jì)錄片評(píng)分高。
接下來我們按年份劃分電影:
year = floor(movies$ReleaseDate/10)*10
m_list = tapply(seq_len(nrow(movies)), year, function(ind) {
m = make_comb_mat(movies[ind, genre, drop = FALSE])
m[comb_degree(m) > 0]
})
m_list = normalize_comb_mat(m_list)
max_set_size = max(sapply(m_list, set_size))
max_comb_size = max(sapply(m_list, comb_size))
ht_list1 = NULL
for(i in 1:5) {
ht_list1 = ht_list1 %v%
UpSet(m_list[[i]], row_title = paste0(names(m_list)[i], "s"),
set_order = NULL, comb_order = NULL,
top_annotation = upset_top_annotation(m_list[[i]], ylim = c(0, max_comb_size),
height = unit(2, "cm")),
right_annotation = upset_right_annotation(m_list[[i]], ylim = c(0, max_set_size)))
}
ht_list2 = NULL
for(i in 6:10) {
ht_list2 = ht_list2 %v%
UpSet(m_list[[i]], row_title = paste0(names(m_list)[i], "s"),
set_order = NULL, comb_order = NULL,
top_annotation = upset_top_annotation(m_list[[i]], ylim = c(0, max_comb_size),
height = unit(2, "cm")),
right_annotation = upset_right_annotation(m_list[[i]], ylim = c(0, max_set_size)))
}
grid.newpage()
pushViewport(viewport(x = 0, width = 0.5, just = "left"))
draw(ht_list1, newpage = FALSE)
popViewport()
pushViewport(viewport(x = 0.5, width = 0.5, just = "left"))
draw(ht_list2, newpage = FALSE)
popViewport()

現(xiàn)在我們可以看到大部分電影都是 1990 年代制作的,兩大類型是動(dòng)作片和愛情片。
類似地,如果我們將頂部注釋更改為完整集的相對(duì)分?jǐn)?shù)(代碼未顯示):

最后,我們可以在 UpSet 圖的右側(cè)添加作為箱線圖注釋的每個(gè)組合集的年份、評(píng)級(jí)和觀看次數(shù)的統(tǒng)計(jì)數(shù)據(jù)。
m = make_comb_mat(movies[, genre])
m = m[comb_degree(m) > 0]
comb_elements = lapply(comb_name(m), function(nm) extract_comb(m, nm))
years = lapply(comb_elements, function(ind) movies$ReleaseDate[ind])
rating = lapply(comb_elements, function(ind) movies$AvgRating[ind])
watches = lapply(comb_elements, function(ind) movies$Watches[ind])
UpSet(t(m)) + rowAnnotation(years = anno_boxplot(years),
rating = anno_boxplot(rating),
watches = anno_boxplot(watches),
gap = unit(2, "mm"))

我們可以看到“科幻+兒童”類型的電影制作時(shí)間很長,但收視率還不錯(cuò)?!皠?dòng)作+兒童”類型的電影收視率最低。
8.8 基因組區(qū)域示例
來自六個(gè)路線圖樣本的 H3K4me3 ChIP-seq 峰通過 UpSet 圖進(jìn)行可視化。這六個(gè)樣本是:
首先讀取文件并轉(zhuǎn)換為GRanges對(duì)象。
file_list = c(
"ESC" = "data/E016-H3K4me3.narrowPeak.gz",
"ES-deriv1" = "data/E004-H3K4me3.narrowPeak.gz",
"ES-deriv2" = "data/E006-H3K4me3.narrowPeak.gz",
"Brain" = "data/E071-H3K4me3.narrowPeak.gz",
"Muscle" = "data/E100-H3K4me3.narrowPeak.gz",
"Heart" = "data/E104-H3K4me3.narrowPeak.gz"
)
library(GenomicRanges)
peak_list = lapply(file_list, function(f) {
df = read.table(f)
GRanges(seqnames = df[, 1], ranges = IRanges(df[, 2], df [, 3]))
})
制作組合矩陣?,F(xiàn)在注意集合和組合集合的大小是總堿基對(duì)或區(qū)域?qū)挾鹊目偤?/strong>。我們只保留超過 500kb 的組合集。
m = make_comb_mat(peak_list)
m = m[comb_size(m) > 500000]
UpSet(m)

我們可以通過設(shè)置axis_param很好地格式化軸標(biāo)簽:
UpSet(m,
top_annotation = upset_top_annotation(
m,
axis_param = list(at = c(0, 1e7, 2e7),
labels = c("0Mb", "10Mb", "20Mb")),
height = unit(4, "cm")
),
right_annotation = upset_right_annotation(
m,
axis_param = list(at = c(0, 2e7, 4e7, 6e7),
labels = c("0Mb", "20Mb", "40Mb", "60Mb"),
labels_rot = 0),
width = unit(4, "cm")
))

對(duì)于每組基因組區(qū)域,我們可以將更多信息與其關(guān)聯(lián),例如平均甲基化或與最近 TSS 的距離。
subgroup = c("ESC" = "group1",
"ES-deriv1" = "group1",
"ES-deriv2" = "group1",
"Brain" = "group2",
"Muscle" = "group2",
"Heart" = "group2"
)
comb_sets = lapply(comb_name(m), function(nm) extract_comb(m, nm))
comb_sets = lapply(comb_sets, function(gr) {
# we just randomly generate dist_to_tss and mean_meth
gr$dist_to_tss = abs(rnorm(length(gr), mean = runif(1, min = 500, max = 2000), sd = 1000))
gr$mean_meth = abs(rnorm(length(gr), mean = 0.1, sd = 0.1))
gr
})
UpSet(m,
top_annotation = upset_top_annotation(
m,
axis_param = list(at = c(0, 1e7, 2e7),
labels = c("0Mb", "10Mb", "20Mb")),
height = unit(4, "cm")
),
right_annotation = upset_right_annotation(
m,
axis_param = list(at = c(0, 2e7, 4e7, 6e7),
labels = c("0Mb", "20Mb", "40Mb", "60Mb"),
labels_rot = 0),
width = unit(4, "cm")
),
left_annotation = rowAnnotation(group = subgroup[set_name(m)], show_annotation_name = FALSE),
bottom_annotation = HeatmapAnnotation(
dist_to_tss = anno_boxplot(lapply(comb_sets, function(gr) gr$dist_to_tss), outline = FALSE),
mean_meth = sapply(comb_sets, function(gr) mean(gr$mean_meth)),
annotation_name_side = "left"
)
)
