Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include dimension names in row and column headers for LaTeX-formatted contingency table

Tags:

r

xtable

If the categories of the attributes in a contingency table are mere numbers, using only these numbers as column/row header is not enough -- a description what the numbers mean is called for. The picture below shows the cross-classification of household size vs. number of foreigners in a household sample:

Example table

Does anyone have experience in producing such tables using R+LaTeX?

like image 897
krlmlr Avatar asked May 22 '12 14:05

krlmlr


1 Answers

I have a rather hackish solution of my own, but I'd like to see other approaches, too. Of course, it would be nice if a variant of this code was added to xtable.

My solution consists of updating the rownames() and colnames() of the table. The row header goes into rownames()[1], and the column header goes into colnames()[1]. Several things have to be remembered:

  • The number of columns in the resulting table is one larger if using row headers. Hence, the tabular environment must be created by the user.
  • If a row header is added, the column header has to include an additional &
  • Do not sanitize or otherwise reformat row or column names after this operation

The add.crosstab.headers function takes care of everything. It can be applied to the result of an xtable() call. Some helper functions are needed, too.

macrify <- function(m, s, bs='\\') {
  paste(bs, m, '{', s, '}', sep='')
}

boldify <- function(s) {
  macrify('textbf', s)
}

add.crosstab.headers <- function(t, row.header=NA, col.header=NA,
                                 sanitize=boldify) {
  rownames(t) <- sanitize(rownames(t))
  colnames(t) <- sanitize(colnames(t))
  if (!is.na(row.header)) {
    colnames(t)[1] <- paste('&', colnames(t)[1])
    rownames(t) <- paste('&', rownames(t))
    row.header <- sanitize(row.header)
    row.header <- macrify('rotatebox{90}', row.header)
    multirow <- macrify('multirow', nrow(t))
    multirow <- macrify(multirow, '*', bs='')
    row.header <- macrify(multirow, row.header, bs='')
    rownames(t)[1] <- paste(row.header, rownames(t)[1])
  }
  if (!is.na(col.header)) {
    col.header <- sanitize(col.header)
    multicolumn <- macrify('multicolumn', ncol(t))
    multicolumn <- macrify(multicolumn, 'c', bs='')
    col.header <- macrify(multicolumn, col.header, bs='')
    col.header <- paste(col.header, '\\\\\n')
    col.header <- paste(col.header, '&')
    if (!is.na(row.header)) {
      col.header <- paste('&', col.header)
    }
    colnames(t)[1] <- paste(col.header, colnames(t)[1])
  }
  t
}

The usage would be like this.

dat <- matrix(round(rnorm(9, 20, 10)), 3, 3)
t <- xtable(dat)
t <- add.crosstab.headers(t, row.header='Foreigners', col.header='Total persons')

print.xtable(t,
             only.contents=TRUE,
             booktabs=TRUE
             , sanitize.text.function=identity
             )
like image 144
krlmlr Avatar answered Oct 26 '22 16:10

krlmlr