Reputation: 199
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!
Upvotes: 12
Views: 38929
Reputation: 20811
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 havencol(x) + 1
the first row will correspond to the rowname style. Correspondingly if the size isnrow(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)
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)))
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;')))
Upvotes: 6
Reputation: 54237
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")))
Upvotes: 20
Reputation: 1367
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
Upvotes: 4