根据矢量或梯度对 plotly 文本注释进行颜色编码

Color coding plotly text annotations according to a vector or gradient

我有整数数据,我想使用 Rplotly 作为 heatmap 绘制,heatmap 颜色的元素按大小编码整数数据。我还想通过整数的文本注释来注释每个元素,并根据整数数据的大小对该文本进行颜色编码。

这是数据:

library(dplyr)

pal <- grDevices::colorRamp(c("black","gray"))
set.seed(1)
df <- rbind(data.frame(col = "a",
                 group = paste0("g",1:20),
                 n = as.integer(runif(20, 1, 20))) %>%
  dplyr::mutate(text.col = rgb(pal((n - min(n))/diff(range(n))),max=255)),
  data.frame(col = "b",
             group = paste0("g",1:20),
             n = as.integer(runif(20, 1, 40))) %>%
    dplyr::mutate(text.col = rgb(pal((n - min(n))/diff(range(n))),max=255)))
df$group <- factor(df$group, levels = paste0("g",1:20))

所以我的 heatmap 将有 20 行对应于 df$group 和 2 列对应于 df$col。如您所见,我在 df.

中指定了每个元素的颜色

这里有一个 data.frame 指定 heatmap 背景颜色的颜色范围,对于每个 df$col:

colors.df <- data.frame(col = c("a", "b"),
                        fill.low = c("#a6c4ba", "#f2edda"),
                        fill.high = c("#4e8a75", "#b49823"),
                        stringsAsFactors = F)

这是我的 plotly 代码:

lapply(c("a","b"), function(l){
  col.df <- dplyr::filter(df, col == l)
  n.text <- as.character(col.df$n)
  plotly::plot_ly(ygap = 1, z = col.df$n, x = col.df$col, y =col.df$group,
                  colors = grDevices::colorRamp(c(dplyr::filter(colors.df,col == l)$fill.low, dplyr::filter(colors.df,col == l)$fill.high)), type = "heatmap") %>%
    plotly::hide_colorbar() %>%
    plotly::add_annotations(font = list(color = col.df$text.col, size = 8),text = n.text,x = col.df$col,y = col.df$group,showarrow = F)
}) %>% plotly::subplot(shareX = T, shareY = T, nrows = 1, margin = 0.001, widths = c(0.5, 0.5))

给出:

如您所见,将 col.df$text.col 传递给 font list in plotly::add_annotations 不被遵守,所有文本注释都是颜色相同的颜色。

知道如何根据 col.df$text.col 给它们上色吗?

Plotly 对您的代码的解释导致为 40 个注释中的每一个注释列出了每种可能的颜色。

那我怎么知道的?我做的第一件事是将绘图发送到一个对象,如下所示:

lapply(c("a","b"), function(l){
  col.df <- dplyr::filter(df, col == l)
  n.text <- as.character(col.df$n)
  plotly::plot_ly(data = col.df, ygap = 1, 
                  z = ~n, x = ~col, y = ~group,
                  colors = grDevices::colorRamp(
                    c(dplyr::filter(colors.df, col == l)$fill.low, 
                      dplyr::filter(colors.df, col == l)$fill.high)), 
                  type = "heatmap") %>%
    plotly::hide_colorbar() %>%
    plotly::add_annotations(font = list(color = ~text.col, size = 8),
                            text = n.text, x = ~col,
                            y = ~group, showarrow = F)
  }) %>% 
  plotly::subplot(shareX = T, shareY = T, nrows = 1, 
                  margin = 0.001, widths = c(0.5, 0.5)) -> a

我想在源代码窗格中查看绘图对象。然而,这个情节不是一个完整的构建,所以我接下来做了。

a <- plotly_build(a)  # embed the JSON data and layout

然后我又看了看对象

您可以在该图像中看到颜色值列表。所以,让我们帮助 Plotly 决定一种颜色,因为它今天看起来相当优柔寡断。

lapply(1:40,
       function(k){
         base = a$x$layout$annotations[[k]] # find the annotation
         # find the color that should be there
         col = filter(df, col == base$x, group == base$y) %>%  
           select(text.col) %>% unlist()
         # change the plotly object
         a$x$layout$annotations[[k]]$font$color <<- col
       })
a # take another look at that graph

这就是你想要的,但是真的很难读!

我将文字加粗以查看是否提高了易读性。

lapply(1:40,
       function(j){
         base = a$x$layout$annotations[[j]]
         t = base$text
         a$x$layout$annotations[[j]]$text <<- paste0('<b>', t, '</b>')
       })

a # any better?

有点帮助。我会留给你弄清楚。如果您有任何问题,请告诉我。