14

I'm pretty much a beginner at programmatically formatting R output, but I've got a basic understanding of knitr, xtable, Markdown, and Pandoc's ability to convert one markup format to another. What I want to do is write an R dataframe df to an HTML table, and apply a particular color to each row that meets a condition (e.g., df$outcome == 1). However, I'm not sure which package would accomplish this in a simple and efficient way, but from browsing a few table formatting threads (xtable thread 1, xtable thread 2, kable documentation 1), I've gathered that kable and xtable might be capable of accomplishing my desired result.

To clarify, here is my reproducible example (using xtable, but am interested in an answer using kable or another package as well):

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))

library(xtable)
dfxt <- xtable(df)

knit2html(input      = "~/rowcolor_ex.Rmd",
          output     = OUTPUTHERE
          stylesheet = "STYLESHEET.css")

withknit2html referencing the file named "rowcolor_ex.Rmd", shown below:

```{r,echo=FALSE,results='asis',warning=FALSE,message=FALSE}
print(dfxt, 
      type = "html",
      include.rownames = FALSE,)
```

I understand that if I'm to use xtable, I'd include one or more arguments after the print(dfxt, part of the function call in the Rmd document, and this thread shows the add.to.row argument that makes sense for type = "latex", but it isn't clear how the code would change for HTML output. Also, I'm not sure if referencing a CSS stylesheet in knit2html would override the HTML table's formatting.

Community
  • 1
  • 1
mcjudd
  • 1,520
  • 2
  • 18
  • 33
  • 1
    [similar question about highlighting individual rows](http://stackoverflow.com/questions/31323885/how-to-color-specific-cells-in-a-data-frame-table-in-r) – rawr Aug 29 '16 at 16:08

4 Answers4

16

Here is a solution using Gmisc::htmlTable

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(Gmisc)
htmlTable(as.matrix(df), altcol = cols, 
          rgroup = '', n.rgroup = rep(1, length(cols)))

EDIT

Since htmlTable has since been moved to the package, htmlTable, and is no longer in Gmisc >= 1.0, the new way to do this would be

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

which also gives:

enter image description here

and your markdown code would simply be

```{r, results='asis'}
htmlTable(as.matrix(df), altcol = cols, 
          rgroup = '', n.rgroup = rep(1, length(cols)))
```

And my .Rmd would look like:

---
output: 
  html_document:
    css: ~/knitr.css
---

```{r, results='asis', message=FALSE}
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(Gmisc)
htmlTable(as.matrix(df), altcol = cols, 
          rgroup = '', n.rgroup = rep(1, length(cols)))
```
rawr
  • 20,481
  • 4
  • 44
  • 78
  • Wonderful! One question though. Since I'm using a data.frame with vectors of multiple types, I changed `as.matrix(df)` to just `df`, and now the first column is the table name (df) and includes row numbers. How do I remove this rownumber column? Thanks. – mcjudd Nov 25 '14 at 15:27
  • 1
    `rownames(df) <- NULL` or `rownames(df) <- rep('', nrow(df))`. It's just a habit of mine to turn everything into a matrix in these situations because 1) you can turn everything into character strings so the output respects your formatting and number of digits; 2) you can use duplicate row and column names (duplicate rownames not possible in data.frames which is why they will need to be there if you are using a data frame, hence why I coerce to a matrix usually) – rawr Nov 25 '14 at 15:30
  • Great, thanks. Also, can I specify a .css file from which htmlTable reads and applies the proper formatting? I have a .css file that applies to the rest of the HTML page, and want the tables to have uniform formatting, except for of course the rows that are highlighted a different color. Looks like `tableCSSclass = "table tr"` might inherit the `table tr` CSS from the CSS template I call in `knit2HTML`, but I see my table still shows the following class: `Classes 'htmlTable', 'character' atomic [1:1]
    – mcjudd Nov 25 '14 at 16:31
  • Yes you can do that. I have my css handle the table alignment, fonts, sizes, all that good stuff – rawr Nov 25 '14 at 16:34
  • OK, I see you have "gmisc_table" as the default CSS. When I change `tableCSSclass` to the filename of my CSS template, it still retains the default formatting. Can you append your answer above with an example of changing the CSS template? I'd very much appreciate it. – mcjudd Nov 25 '14 at 18:51
  • 1
    oh I see. Not sure about that exactly. I usually use the yaml front matter to handle the css, see edits and [screenshot](http://i.imgur.com/dz5cCvt.png). The tr formatting is embedded in the html which htmlTable produces, you can `cat(htmlTable(df))` to see. Not sure why the tableCSSclass would mess with that – rawr Nov 25 '14 at 19:10
  • is there a way to accomplish this where only one column is highlighted given the condition (i.e. so its not the whole row)? – Cyrus Mohammadian Aug 28 '16 at 18:53
  • 1
    @CyrusMohammadian I added [this answer](http://stackoverflow.com/a/39210488/2994949) to another question since this one was asking something slightly different, but I don't think there is a direct/easy way – rawr Aug 29 '16 at 16:02
5

Well, not using colors (as not supported by markdown), but you can highlight cells/rows/columns of the table with pandoc.table and the general pander method by using bold or italics font face:

> library(pander)
> emphasize.rows(which(df$outcome == 2))
> pander(df)

-------------------------
 id   inputval   outcome 
---- ---------- ---------
 29     0.89        1    

*79*   *0.69*      *2*   

*41*   *0.64*      *2*   

*89*    *1*        *2*   

 95     0.66        1    

 5      0.71        1    

 53     0.54        1    

*90*   *0.6*       *2*   

*56*   *0.29*      *2*   

 46     0.14        4    

 96     0.97        1    

*46*   *0.91*      *2*   

 68     0.69        4    

 58     0.8         1    

 11     0.02        3    

 90     0.48        1    

 25     0.76        1    

 5      0.21        4    

 33     0.32        4    

*96*   *0.23*      *2*   
-------------------------
daroczig
  • 28,004
  • 7
  • 90
  • 124
2

I've played around a good amount with formatting RMarkdown documents.

Since RMarkdown gets converted to LaTeX before the end PDF is generated, you can pass arguments that would work in LaTeX to RMarkdown. So, adding

header-includes:
  - \usepackage{xcolor}

in the heading of the RMarkdown document, and then adding something like

for(i in seq(1, nrow(yourDataframe), by = 2)){
  yourDataframe[i, ] <- paste0("\\color{purple}", yourDataframe[i, ])
  row.names(yourDataframe)[i] <- paste0("\\color{purple}", row.names(yourDataframe)[i])
}

will get you purple (or whatever color specified and allowed in the xcolor LaTeX package) entries in every other row of your table. Just another way to emphasize entries that isn't the base bold or italics given.

This isn't row highlighting, but could give you further customizable options.

*Tested with the pander package.

**You'll need to convert any factor columns to character columns for this method.

Output

Mika Sundland
  • 18,120
  • 16
  • 38
  • 50
Devuroasts
  • 31
  • 2
1

Here is a solution using ReporteRs:

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))

library( ReporteRs )
library( magrittr )

# create and format table
myft = df %>% FlexTable() %>% 
  setRowsColors( df$outcome == 1, 'magenta') %>% 
  setFlexTableWidths( c( 1, 1, 1) )

# create an html doc and send myft into
doc = bsdoc() %>% addFlexTable( myft )

# write the html file in a new dir
writeDoc( doc, "example_out/df.html")
David Gohel
  • 9,180
  • 2
  • 16
  • 34