交互式复杂热图是如何实现的

祖光谷(z.gu@dkfz.de

2022-10-02

热图主要用于可视化行和列组共享的常见模式。观察到模式后,下一步是从热图中提取相应的行和列组,这需要热图上的交互性。的ComplexHeatmap包以生成而闻名静态的热图(单个热图或热图列表,可能带有复杂的注释)。这是包裹InteractiveComplexHeatmap带来互动性ComplexHeatmap.新功能允许用户通过点击/悬停单个单元格或从热图中选择区域来捕获次热图。

与其他支持基于JavaScript的交互式热图的包不同,如。iheatmapr的热图d3heatmap,包装InteractiveComplexHeatmap有一种特殊的方法来捕获用户选择的位置,并从矩阵中提取相应的值。在这篇短文中,我将详细解释交互是如何实现的ComplexHeatmap

为了演示它,我首先生成一个包含两个热图的列表并应用k-表示在数值热图上聚类。

图书馆(ComplexHeatmap)图书馆(InteractiveComplexHeatmap)set.seed123mat1 =矩阵rnormOne hundred.),10rownames(mat1) =colnames(mat1) =paste0“一个”110mat2 =矩阵样本(信110],One hundred.取代=真正的),10rownames(mat2) =colnames(mat2) =paste0“b”110ht_list =的热图(mat1name =“mat_a”row_km =2column_km =2+的热图(mat2name =“mat_b”

InteractiveComplexHeatmap实现两种类型的交互性:

  1. 在交互式图形设备上,
  2. 在一个闪亮的应用程序。

交互式图形设备上的交互性是Shiny应用程序交互性的基础,因此在接下来的部分中,我将首先介绍如何使用交互式图形设备实现交互性。

在交互式图形设备上

这里的“交互式图形设备”是指在终端或本地R GUI中使用R时,在R会话中为生成图形而打开的窗口,或者是Rstudio IDE中的图形面板。

我将首先解释如何做InteractiveComplexHeatmap捕获用户在设备上单击的位置,以及它如何与矩阵中的值相关联。

当用户在设备上单击时,相对于设备的物理位置(设备在x和y方向上的左下角偏移量)将被捕获网格:grid.locator ().热图的物理位置(更准确地说,热图切片)也可以通过网格:deviceLoc ().知道了点击点和热图的确切位置,就有可能知道点击点在哪个热图中。此外,通过计算热图中单击点的相对距离,还可以知道单击点对应的行和列。

为了将用户的点击点与热图相关联,我们首先需要计算所有热图的位置。有一个辅助函数htPositionsOnDevice ()它能完成这项工作。

在执行之前htPositionsOnDevice ()时,应在设备上绘制热图,并已生成热图布局,以便htPositionsOnDevice ()可以访问情节的各种视口。因此,热图对象ht_list是否应该由画()函数。

下面的代码在宽6英寸、高4英寸的设备中绘制热图。

ht_list =(ht_list)pos =htPositionsOnDevice(ht_list)

返回的对象pos是一个DataFrame对象,该对象包含所有热图切片的位置。一个DataFrame对象(DataFrame类定义在S4Vectors)在本质上与数据帧非常相似,但它可以存储更复杂的数据类型,例如simpleUnit向量(由网格::单元()).

pos
# # DataFrame用6 # # 8行和列的热图片row_slice column_slice # # <人物> <人物> <整数> <整数> # # 1 mat_a mat_a_heatmap_body_1_1 1 1 # # 2 mat_a mat_a_heatmap_body_1_2 1 2 # # 3 mat_a mat_a_heatmap_body_2_1 2 1 # # 4 mat_a mat_a_heatmap_body_2_2 2 2 # # 5 mat_b mat_b_heatmap_body_1_1 1 1 # # 6 mat_b mat_b_heatmap_body_2_1 2 1 # # x_min x_max y_min # # < simpleUnit > < simpleUnit > < simpleUnit > # 0.742676161627057 # 1 . n:行情). .1.78748414410527英寸1.02923575725979英寸## 2 1.82685422284543英寸2.87166220532365英寸1.02923575725979英寸## 3 0.742676161627057inc..1.78748414410527英寸## 4 1.82685422284543英寸2.87166220532365英寸0.43284365824135英寸## 5 2.95040236280396英寸5.07938840650056英寸1.02923575725979英寸## y_max ##  ## 1 3.25732383837294inch ## 2 3.25732383837294inch ## 3 0.989865678519637inc..0.989865678519637inc..## 5 3.25732383837294英寸## 6 0.989865678519637inc..

我们可以通过下面的代码确认位置是否被正确捕获。在下面的图中,黑色矩形对应热图切片,虚线矩形对应整个图像的边界。

dev.new宽度=6身高=4grid.newpage()grid.rectgp =gparlty =2))(我seq_lennrow(pos))) {x_min =pos(我“x_min”x_max =pos(我“x_max”y_min =pos(我“y_min”y_max =pos(我“y_max”pushViewport视窗x =x_min,y =y_min,name =pos(我“切”],宽度=x_max-x_min,身高=y_max-y_min,就=c“左”“底”)))grid.rect()upViewport()}

是的,所有热图切片的位置都被正确捕获了!

因为现在我们知道点击点的位置(通过网格:grid.locator ())和所有热图切片的位置,就可以计算出用户的点击对应于原始矩阵中的哪一行和哪一列。

下一张图中,坐标为蓝色的点\ \ ((a, b))由用户单击。用户点击进入的热图切片有范围\ ((x_1、x_2) \)在x方向和范围上\ ((y_1 y_2) \)在y方向上,这个热图切片可以很容易地通过比较每个热图切片的位置与点击的位置来找到。有\ (n_r \)行(\ (n_r = 8 \)),\ (n_c \)列(\(n_c = 5\)),并以虚线标记。注意所有的坐标值(即。\ \ ()\ (b \)\ (x_1 \)\ (y_1 \)\ (x_2 \)\ (y_2 \))被测量为图形设备中的物理位置。

在此热图切片中,行索引\ (i_r \)和列索引\ (i_c \)可以计算为(假设左下角对应于行和列的索引都为1):

\ [i_c = \ lceil \压裂{a - x_1} {x_2 - x_1} \ cdot n_c \ rceil \]\ [i_r = \ lceil \压裂{b - y_1} {y_2 - y_1} \ cdot n_r \ rceil \]

这里是符号\(\ ccell x \ ccell \)表示数值的上限\ \ (x).在ComplexHeatmap时,索引为1的行始终放在热图的顶部,则\ (i_r \)应调整为:

\ [i_r = n_r - \ lceil \压裂{b - y_1} {y_2 - y_1} \ cdot n_r \ rceil + 1 \]

属于所选热图片的原始矩阵的行索引和列索引的子集已经存储在其中ht_list对象(可以通过row_order ()column_order ()函数),这样我们就可以很容易地得到用户点对应的原始矩阵的行索引和列索引\ (i_r \)\ (i_c \)

表示完整热图(不切片)的矩阵为\ \(米),并将该热图中的行和列索引的子集表示为阿\ (^ {\ mathrm{行}}\)阿\ (^ {\ mathrm{坳}}\).请注意,阿\ (^ {\ mathrm{行}}\)阿\ (^ {\ mathrm{坳}}\)可以由于集群而重新排序。然后,行和列索引(\ (j_r \)\ (j_c \))中选定的点\ \(米)

\[j_r = o^{\math {row}}_{i_r}\]\[j_c = o^{\math {col}}_{i_c}\]

和对应的值\ \(米)\ (M_ {j_r, j_c} \)

InteractiveComplexHeatmap有两个功能selectPosition ()selectArea ()它允许用户从热图中选择单个位置或选择区域。在图形设备的交互下,用户不需要运行htPositionsOnDevice ()明确。热图的位置自动计算,缓存和重用,如果热图是相同的,设备没有改变它的大小。如果用户改变了设备大小,htPositionsOnDevice ()将自动重新执行。

下一张图片显示了一个使用的例子selectPosition ()

交互方面,该功能要求用户点击热图上的一个位置。函数返回一个DataFrame包含热图名称、片名称和该热图中矩阵的行/列索引。

## heatmap slice row_slice column_slice row_index ##      ## 1 mat_a mat_a_heatmap_body_1_2 1 2 9 ## column_index ##  ## 1 1

输出意味着,用户单击的位置位于名为“mat_a”的热图中,位于其第一行片和第二列片中。假设矩阵是否发送给热图“mat_a”,点击点对应值垫(9,1)

如果单击的位置不在任何热图切片中,则函数返回

类似地,selectArea ()功能要求用户单击热图上定义区域的两个位置。

注意,由于所选区域可能在多个热图和切片上重叠,该函数返回一个DataFrame包含热图名称、片名称和该热图中的行/列索引的多行。使用示例如下。

##热图切片row_slice column_slice row_index ## <字符> <字符> <数字> <数字>  ## 1 mat_a mat_a_heatmap_body_1_2 1 2 7,5,2,…## 2 mat_a mat_a_heatmap_body_2 2 2 6,3 ## 3 mat_b mat_b_heatmap_body_1_1 1 1 7,5,2,…## 4 mat_b mat_b_heatmap_body_2_1 2 1 6,3 ## column_index ##  ## 1 2,4,1,…## 2 2,4,1,…## 3 1,2,3,…## 4 1,2,3,…

row_indexcolumn_index存储在IntegerList格式。来得到行下标如。mat_a_heatmap_body_1_2(在第一行中),用户可以使用以下命令之一(假设DataFrame对象的df):

df (1“row_index”] [[1]]unlist(df [1“row_index”])df美元row_index [[1]]

矩形和标记区域的点可以通过设置关闭马克参数

在屏幕外的图形设备上

也可以使用selectPosition ()selectArea ()在其他屏幕外图形设备上,例如pdf ()png ().现在您不能交互地选择位置,但是可以指定位置pos论点selectPosition ()pos1/pos2selectArea ()模拟点击。的值pospos1pos2所有都应该是单位长度为2的对象,对应于位置的x坐标和y坐标。

pdf(…)ht_list =(ht_list)pos =selectPosition(ht_listpos =单位c3.3.),“厘米”))dev.off()

##点:x = 3.0 cm, y = 3.0 cm(在图形设备中测量)## ##热图已更改。计算新的热图位置。##搜索热图“mat_a”## -行切片1,列切片1 [mat_a_heatmap_body_1_1]…重叠
pos
## heatmap slice row_slice column_slice row_index ##      ## 1 mat_a mat_a_heatmap_body_1_1 1 1 8 ## column_index row_label column_label ##    ## 1 7 a8 a7
pdf(…)ht_list =(ht_list)pos =selectArea(ht_listpos1 =单位c3.3.),“厘米”),pos2 =单位c55),“厘米”))dev.off()

##点1:x = 3.0 cm, y = 3.0 cm(在图形设备中测量)##点2:x = 5.0 cm, y = 5.0 cm(在图形设备中测量)## ##热图位置已经计算出来,使用缓存的位置。##搜索热图“mat_a”## -行切片1,列切片1 [mat_a_heatmap_body_1_1]…* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *在热图'mat_a' ##中查找行切片2,列切片1 [mat_a_heatmap_body_2_1]…##在热图“mat_a”中查找## -行切片2,列切片2 [mat_a_heatmap_body_2_2]…##在热图'mat_b'中搜索## -行切片1,列切片1 [mat_b_heatmap_body_1_1]…##在热图'mat_b' ##中搜索行切片2,列切片1 [mat_b_heatmap_body_2_1]…没有重叠
pos
##热图切片row_slice column_slice row_index ## <字符> <字符> <数字> <数字>  ## 1 mat_a mat_a_heatmap_body_1_1 1 1 7,5,2,…## 2 mat_a mat_a_heatmap_body_1_2 1 2 7,5,2,…## column_index row_label column_label ##    ## 1 7,3,5 a7,a5,a2,…A7,a3,a5 ## 2 6 A7,a5,a2,…a6

用户不需要直接在屏幕外的图形设备上使用这个功能,但是,当开发一个在屏幕外的图形设备下实际生成情节的Shiny应用程序时,这个功能非常有用。我将在下一节解释它。

闪闪发光的应用

有三个功能htPositionsOnDevice ()selectPosition ()selectArea (),可以实现与热图交互工作的Shiny应用程序。现在的问题是服务器端如何捕捉用户在网页上点击的位置。幸运的是,有一个解决方案。输出热图通常放在一个闪亮的::plotOutput ()plotOutput ()提供两个操作点击.然后在服务器端,可以获得用户点击的位置信息。然后可以将位置设置为selectPosition ()selectArea ()通过pospos1/pos2参数与原始矩阵中的值正确对应。