如何在R中对数据框/表中的特定单元格进行着色?

12
我想要对下面的数据框中特定的单元格进行着色。例如,在inputval列中,我想要突出显示范围在[0.8, 0.9) 的单元格为品红色,同一列中在[0.7, 0.8) 范围内的单元格为蓝色。同样地,我想将值为1的output列单元格着成品红色,而值为4的单元格着成蓝色。对于数据框中的其余单元格,我希望它们保持为白色。
我有以下可重复的代码只能按行着色,并限制我仅以品红色和白色进行着色。如何添加另一种颜色并且可以按单元格进行着色?
set.seed(123)
df <- data.frame(id       = sample(1:100, 20, replace = TRUE),
                 inputval = sample(seq(0, 1, by=0.01), 20, replace = TRUE),
                 outcome  = sample(1:4, 20, replace = TRUE))

cols <- with(df, ifelse(outcome == 1, 'magenta', 'white'))

library('htmlTable')
htmlTable(as.matrix(df), col.rgroup = cols)

我意识到添加不同颜色的问题在于with中的ifelse调用,它限制了我只能使用品红和白色。如何在这里添加另一个条件?

虽然我知道导致多种颜色问题的原因,但我对如何仅给特定单元格上色一无所知。

这与此问题的已接受答案相同。 谢谢!


请查看 formatter 包,https://cran.r-project.org/web/packages/formattable/vignettes/formattable-data-frame.html。我使用这个包完全满足了我的表格格式化需求(逐单元格格式化),只需调用 knitr::kable 函数即可。 - Nova
有条件地给表格单元格上色。 - moodymudskipper
3个回答

19

你有考虑过DT吗?

library(DT)
datatable(df, rownames = FALSE) %>%
  formatStyle(columns = "inputval", 
              background = styleInterval(c(0.7, 0.8, 0.9)-1e-6, c("white", "lightblue", "magenta", "white"))) %>%
  formatStyle(columns = "outcome", 
              background = styleEqual(c(1, 4), c("magenta", "lightblue"))) 

输入图像描述


哇!这真是太简单了,谢谢!如果我知道要更改颜色的每列中的行号,我该如何指定呢?例如,在outcome列中,假设我想让第1、2、4行为蓝色,第3、5、6行为品红色。那么formatstyle的参数会像background = styleEqual(c(1,2, 4, 3, 5, 6), c(rep("lightblue", 3),rep("magenta", 3)) 这样吗?当然,我不会明确地写出行号。我会将向量blue存储蓝色的行号,将向量magenta存储品红色的行号。 - gbrlrz017
我现在可以更容易地根据单元格中的值而不是行号来突出显示,就像您为列“outcome”所做的那样。再次感谢!那个表格真漂亮! - gbrlrz017
你是怎么把整个表格变成一张图片的?当我从Rstudio导出表格时,部分内容会丢失。 - gbrlrz017
您可以在datatable中设置options = list(paging = FALSE),打开您的tempdir(),然后在浏览器中打开相应的HTML,并使用Nimbus或其他截图工具从浏览器内部进行截图。 - lukeA
+1 感谢。选择全部 -> 复制 -> 粘贴到 Libre Office 中效果不错,可以保留颜色和大部分表格格式,供大家参考。对于较小的表格,Nimbus 或类似软件效果最佳,可以保持图像质量。 - gbrlrz017
显示剩余3条评论

6

下面是我的愚蠢答案...这是正确的方法:

通过css.cell参数,此功能已内置于htmlTable中:

css.cell元素允许您向表格单元格添加任何可能的CSS样式。如果您提供了一个向量,则假定该向量应在整个列中重复样式。如果您提供了与x参数相同大小的矩阵,则如果有ncol(x) + 1,则第一行将对应于行名称样式。相应地,如果大小为nrow(x) + 1,则假定第一行是标题行。

因此,基本上您只需要为每个单元格定义一个样式矩阵:

x <- head(cars)

## indices defining where the styles go
where <- rbind(c(2,2), c(2,1), c(5,2))
style <- c('background-color: red; color: white;',
           'border: solid 1px;',
           'font-weight: 900; color: blue;')

css.cell <- matrix('', nrow(x), ncol(x))
css.cell[where] <- style

#      [,1]                 [,2]                                  
# [1,] ""                   ""                                    
# [2,] "border: solid 1px;" "background-color: red; color: white;"
# [3,] ""                   ""                                    
# [4,] ""                   ""                                    
# [5,] ""                   "font-weight: 900; color: blue;"      
# [6,] ""                   ""                                

htmlTable(head(cars), css.cell = css.cell)

这里输入图片描述

如果你不进行来回切换,很难分辨出这个表格和下面那个类似的表格之间的间距略有不同。在inject_div示例中,看起来更加居中。


有点晚了,但@CyrusMohammadian发表了一条评论,既然这条评论/问题与此相同,我会将答案添加在这里,而不是编辑我的答案,因为它针对的是一个(稍微)不同的问题。

表格可能会变得很复杂,每个人都有不同的功能要求。我认为Max没有内置解决方案能够满足所有需求。

因此,我认为最简单的方法是(hackily)将一些html/css注入到你的表格中(你可能也可以在运行htmlTable后进行这样做,即直接在html代码中进行,但这样更容易):

#' Inject div
#' 
#' Inject an html division tag with style attribute.
#' 
#' @param x a matrix or data frame
#' @param where an \code{nx2} matrix of row and column indices or vector (of
#' the form c(row, col, row, col, ...)) specifying which cells to select
#' @param style vector of character string(s) applied to each cell, recycled
#' if necessary

inject_div <- function(x, where, style = 'background-color: lightgrey; border: solid 1px') {
  if (!all(sapply(style, nzchar)))
    return(x)
  where <- matrix(where, ncol = 2L, byrow = !is.matrix(where))
  style <- rep_len(style, nrow(where))
  if (length(where) > 0)
    x[where] <- sprintf('<div style=\'%s\'>%s</div>',
                      gsub(';*$', ';', style), x[where])
  x
}

library('htmlTable')
htmlTable(inject_div(head(cars), cbind(2,2)))

enter image description here

htmlTable(inject_div(head(cars), where = c(2,2,2,1,5,2),
                     ## equivalently
                     # where = rbind(c(2,2), c(2,1), c(5,2))
                     style = c('background-color: red; color: white;',
                               'border: solid 1px;',
                               'font-weight: 900; color: blue;')))

enter image description here


4

如果想添加更多的颜色,你需要增加更多的条件。例如,如果你想为 outcome 为1和特定的 inputval 设置不同的颜色:

cols <- with(df, ifelse(outcome == 1,
                        ifelse(inputval == 5, 'magenta', 'red'),
                        'white')

所以,任何outcome == 0的内容都应该被涂成白色,如果outcome == 1并且inputval == 5,那么它将会是品红色;其他内容将会是红色。
对于您的另一个问题,您可以使用rgroupcgroup相结合来指定要着色的特定行/列,请参考说明文档或单击此处查看:http://cran.r-project.org/web/packages/htmlTable/vignettes/tables.html

谢谢!有没有一个可行的示例来指定我需要的rgroup和cgroup的组合?你给出的链接没有清晰地选择不同单元格的示例,我认为。 - gbrlrz017
抱歉,您可能需要阅读文档并尝试一些操作。 - Chris Watson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接