У меня есть целочисленные данные, которые я хочу построить, используя R
's plotly
как 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
в 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?
Это немного помогло. Я оставлю это для вас, чтобы понять. Если у вас есть какие-либо вопросы, дайте мне знать.