16

The table function in base R adds nice row/column labels, but when I use knitr::kable these go away. Any simple way to keep these, aside from adding them on the html/markdown side?

Reproducible example:

library(knitr)

# reproducibility
set.seed(123) 

# here's a df
some_data <-
  data.frame(a=sample(c('up','down'), 10, replace=T),
             b=sample(c('big','small'), 10, replace=T))

# using table() you get nice labels ('a' and 'b', in this case)
table(some_data)

enter image description here

# that goes away with kable, in either markdown or html format (I care about html)
kable(table(some_data))
kable(table(some_data), format='html')

enter image description here

arvi1000
  • 9,393
  • 2
  • 42
  • 52

4 Answers4

6

Neat that someone else posted a bounty on my old question. Anyway, if it's helpful, my solution was a homebrew html generator function

table_label <- function(tbl) {

  # table dimensions
  rows <- dim(tbl)[1]
  cols <- dim(tbl)[2]

  # get started
  html_out <- '<table>\n'

  # first row: label only
  blank_cell <- '<td>&nbsp;</td>'
  html_out <- 
    paste0(html_out,
           '\t<tr>',
           blank_cell, 
           '<td>', names(dimnames(tbl))[2], '</td>', # column label
           rep(blank_cell, cols-2),
           '</tr>\n')

  # second row:
  html_out <- 
    paste0(html_out,
           '\t<tr>',
           # label...
           '<td>', names(dimnames(tbl))[1], '</td>',
           # ...and headers
           paste0('<td>', dimnames(tbl)[[2]], '</td>', collapse=''),
           '</tr>\n')

  # subsequent rows
  for (i in 1:rows) {
    html_out <- 
      paste0(html_out,
             '\t<tr>',
             # header... 
             '<td>', dimnames(tbl)[[1]][i], '</td>',                        
             # ...and values
             paste0('<td>', tbl[i,], '</td>', collapse=''),
             '</tr>\n')
  }

  # last row
  html_out <- paste0(html_out, '</table>')
  return(html_out)
}

Now this markdown doc:

Produce table
```{r}
set.seed(123) 

some_data <-
  data.frame(a=sample(c('up','down'), 10, replace=T),
             b=sample(c('big','small', 'medium'), 10, replace=T))

tbl <- table(some_data)
```

Now display
```{r, results='asis'}
cat(table_label(tbl))
```

Produces the results I had wanted:

enter image description here

The generated html is somewhat readable, too:

<table>
    <tr><td>&nbsp;</td><td>b</td><td>&nbsp;</td></tr>
    <tr><td>a</td><td>big</td><td>medium</td><td>small</td></tr>
    <tr><td>down</td><td>4</td><td>0</td><td>2</td></tr>
    <tr><td>up</td><td>0</td><td>4</td><td>0</td></tr>
</table>
arvi1000
  • 9,393
  • 2
  • 42
  • 52
  • This only works with a two dimensional table, but accommodates any number of row/columns. I find that any table i want to display is usually 2d anyway, but someone could extend this if more dims desired – arvi1000 Jan 18 '15 at 04:49
  • Hmm does not seem to work on a pdf_document. It just outputs the HTML as code. Thanks for sharing though! (edit: actually it appears as code even with html_document. I'm not sure why our results differ) – Jeff Jan 18 '15 at 21:54
  • managed to get it working in HTML by removing the `\t`s, but unfortunately still does not work in a pdf_document – Jeff Jan 18 '15 at 23:07
  • Hmm. Are you using `cat` to print the results in the chunk, and are you specifying `results='asis'` in the chunk options? Both are necessary. I then used `knitr::knit2html('input_file.Rmd', 'output_file.html')` to knit – arvi1000 Jan 19 '15 at 13:07
  • yup. as mentioned, it worked when i removed the `\t`s, though only for html_document – Jeff Jan 19 '15 at 16:49
  • Odd. Tab characters shouldn't make any difference when rendering 'as is' in html. I'm running R version 3.1.1 (2014-07-10) on x86_64-apple-darwin13.1.0 (64-bit) in en_US.UTF-8 locale with knitr_1.7, for reference – arvi1000 Jan 21 '15 at 16:26
  • Ah, that seems to be the problem. `knitr::knit2html` works with your code, I was using `rmarkdown::render`. I think it's because if you [indent something by four spaces](http://rmarkdown.rstudio.com/#comment-1803401694) in rmarkdown, it prints verbatim. I replaced `\t` with four spaces, and had the same problem. changed to 3 spaces, works fine. – Jeff Jan 21 '15 at 16:59
6

@Yihui should get the credit for this. Straight from the printr package:

# BEGINNING of Rmd file:

```{r echo=FALSE}
# devtools::install_github("yihui/printr")
require(printr)

# reproducibility
set.seed(123) 

# here's a df
some_data <-
  data.frame(a=sample(c('up','down'), 10, replace=T),
             b=sample(c('big','small'), 10, replace=T))

table(some_data)
```

# End of Rmd file

Results in:

|a/b  | big| small|
|:----|---:|-----:|
|down |   5|     1|
|up   |   0|     4|
mikeck
  • 3,534
  • 1
  • 26
  • 39
  • Sorry, I'm looking for actual axis labels, not another entry in the header row. It also happens to look [bad](http://i.imgur.com/PujdBWl.png) on my data, and only allows me to use the data.table column names (as opposed to a string) – Jeff Jan 18 '15 at 21:50
4

Not an optimal solution (as Pandoc's markdown does not support col/rowspans), but give a try to pander, which is intended to transform R objects into markdown with ease (and bunch of options):

> library(pander)
> pander(ftable(some_data))

------ --- ----- -------
       "b" "big" "small"

 "a"                    

"down"       5      1   

 "up"        0      4   
------ --- ----- -------

> pander(ftable(some_data), style = 'rmarkdown')

|        |     |       |         |
|:------:|:---:|:-----:|:-------:|
|        | "b" | "big" | "small" |
|  "a"   |     |       |         |
| "down" |     |   5   |    1    |
|  "up"  |     |   0   |    4    |
daroczig
  • 28,004
  • 7
  • 90
  • 124
1

Although a bit hacky, combining the tables and xtable package can get you the html of the contingency table with the row/column names. Does this work for you?

require(xtable)
require(tables)

some_data <-
  data.frame(a=sample(c('up','down'), 10, replace=T),
             b=sample(c('big','small'), 10, replace=T))

tab <- as.matrix(tabular(Factor(a)~Factor(b), data=some_data))

print(xtable(data.frame(tab)), type="html", include.rownames=F, include.colnames=F)
cdeterman
  • 19,630
  • 7
  • 76
  • 100
  • Thank you for your answer. I feel like this is more lines/more complexity than just sticking with `kable` and accessing the labels via `names(dimnames(...))` for display in the markdown doc, though – arvi1000 Oct 17 '14 at 18:10
  • @arvi1000, agreed, it's whatever works best for you. – cdeterman Oct 17 '14 at 18:12