12

I would like to color specific cells in the following dataframe. For example, in the inputval column, I would like to highlight cells in the range of [0.8, 0.9) magenta, and the cells in that same column in the range of [0.7, 0.8) blue. Similarly, I'd like the output column cells with a value of 1 to be colored magenta and those with value 4 to be colored blue. For the rest of the cells in the dataframe, I would like them to remain white.

I have the following reproducible code which highlights by row only, and limits me to coloring in magenta and white only. How can I add another color and do so by cell?

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)

I realize that the issue for adding different colors is with the ifelse call in with that limits me to just magenta and white. How can I add another condition here?

While I know what's causing the multiple color issue, I'm pretty clueless about how to color only specific cells.

This is the same example as the accepted answer to this question. Thanks!

Community
  • 1
  • 1
gbrlrz017
  • 199
  • 1
  • 1
  • 10
  • Check out the formatter package, https://cran.r-project.org/web/packages/formattable/vignettes/formattable-data-frame.html . I got my table formatting needs totally covered with this (cell-by-cell formatting) using only this package, which calls the knitr::kable function. – Nova Feb 03 '17 at 15:07
  • relevant: https://stackoverflow.com/questions/18663159/conditional-coloring-of-cells-in-table – moodymudskipper Jun 22 '18 at 12:02

3 Answers3

19

Have you considered 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"))) 

enter image description here

lukeA
  • 53,097
  • 5
  • 97
  • 100
  • Wow! That's as easy as it gets, thanks! If I happen to know the row numbers in each of the columns that I want to change color, how would I specify this? For example, in column `outcome`, say rows 1, 2, 4 I want to be blue & rows 3, 5, 6 to be magenta. Would the argument to `formatstyle` be something like `background = styleEqual(c(1,2, 4, 3, 5, 6), c(rep("lightblue", 3),rep("magenta", 3)) `? Of course I wouldn't explictly write out the row numbers. I'd have vector `blue` store the row numbers for blue, and the vector `magenta` store the row numbers for magenta. – gbrlrz017 Jul 09 '15 at 19:05
  • I was able to more easily highlight based on the value in the cell instead of the row number just like you did for the column `outcome`. Once again, thank you! That table is beautiful! – gbrlrz017 Jul 09 '15 at 19:24
  • How did you get the entire table into one image? When I export the table from Rstudio, part of it is missing. – gbrlrz017 Jul 13 '15 at 07:48
  • You could set `options = list(paging = FALSE)` within `datatable`, open your `tempdir()`, then open the appropriate html in a browser and take a screenshot from within the browser using Nimbus or another screenshot tool. – lukeA Jul 13 '15 at 08:41
  • +1 thanks. Selecting all -> copy -> paste on Libre Office works decently and maintains color and majority of table format for anyone's future reference. Nimbus or the like works best for smaller tables, maintaining image quality. – gbrlrz017 Jul 13 '15 at 16:28
  • what does the `-1e-6` bit do in `styleInterval(c(0.7, 0.8, 0.9)-1e-6` ? – Laura Apr 26 '19 at 14:13
  • @Laura It subtracts a small fraction. (I think to exclude the numbers - can't remember: 4 yrs ago) – lukeA Apr 28 '19 at 15:12
  • @lukeA I am creating an HTML file with the code `print(xtable(extract1), type = "html", sanitize.text.function = function(str) gsub("..", "Output", str, fixed = TRUE), file = "Output/extracted.html")` that uses `xtable` package. I want to color its specific column enteries, How should I approach to this. – Bhavneet sharma Jul 12 '19 at 10:30
6

My answer below is really dumb.. Here is the proper way:

This feature is built into htmlTable via the css.cell argument:

The css.cell element allows you to add any possible CSS style to your table cells. If you provide a vector the vector it is assummed that the styles should be repeated throughout the columns. If you provide a matrix of the same size as your x argument. If have ncol(x) + 1 the first row will correspond to the rowname style. Correspondingly if the size is nrow(x) + 1 it is assummed that the first row is the header row.

So Basically you just need to define a matrix of styles for each cell:

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)

enter image description here

It's hard to tell unless you are swapping back and forth, but the spacing in this table and the similar one below is slightly different. The inject_div example looks a little more centered.


A little late, but @CyrusMohammadian made a comment on my other answer, and since the comment/question is the same as this one, I'll add the answer here rather than editing my answer which was for a (slightly) different question.

Tables can get complex, and everyone has different features they want. I don't think it is possible for Max to have solutions built-in for them all.

Therefore, the easiest way I think would be to (hackily) inject some html/css into your table (you could probably also do this after running htmlTable, ie directly in the html code, but this is easier I think):

#' 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

rawr
  • 20,481
  • 4
  • 44
  • 78
4

For adding additional colors, you would need more conditions, e.g. if you want to have a different color for an outcome of 1 and a specific inputval:

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

So this should color anything with outcome == 0 as white, and if outcome == 1 and inputval == 5, it will be magenta; the others will be red.

For your other question, you can use a combination of rgroup and cgroup to specify which rows/columns you want to color, see the vignette, or see here: http://cran.r-project.org/web/packages/htmlTable/vignettes/tables.html

Chris Watson
  • 1,347
  • 1
  • 9
  • 24
  • Thanks for this! What is a working example to specify the combination of rgroup and cgroup I need? The link you gave didn't have a clear example of selecting distinct cells, I believe. – gbrlrz017 Jul 09 '15 at 18:03
  • Sorry, you may have to read the documentation and try some things out. – Chris Watson Jul 09 '15 at 19:50