11

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?

krlmlr
  • 25,056
  • 14
  • 120
  • 217

3 Answers3

6

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
             )
krlmlr
  • 25,056
  • 14
  • 120
  • 217
0

Here's one approach. Start with some data (you should do this when posting the question) in matrix form.

dat<-matrix(round(rnorm(9,20,10)),3,3)

Create a vector of names. Apply the names to the matrix. Print the matrix

persons<-c(seq("0","2"))
foreign<-c(seq("0","2"))
dimnames(dat)<-list(persons=persons, foreign=foreign)
dat

You can use xtable to output a Latex-formatted table.

library(xtable)
xtable(dat)
charlie
  • 602
  • 4
  • 12
  • Sure I should have posted a minimal working example. Sorry for not doing it. Do you mind if I adapt your example? -- The generated xtable does not include the dimension names, though. – krlmlr May 23 '12 at 11:49
  • No problem. And yes, I realized afterwards that the latex output doesn't include the dimension names. My approach would probably be to just fix that in tex itself, though if you figure out how to do it directly using xtable do let me know. – charlie May 24 '12 at 13:14
  • See my own answer for an `xtable` solution. – krlmlr Jun 06 '12 at 19:20
0

There's ftable that turns a contingency table into a two-dimensional formatted table and allows specifying what is shown in rows and what in columns (also useful for tables of more than two dimensions). The memisc package helps turning this into nice LaTeX:

library(magrittr)
library(memisc)
expand.grid(Foreigners = 0:5, `Total persons` = 1:8) %>%
  cbind(Freq = rnorm(6*8, 20, 10)) %>%
  xtabs(formula = Freq~.) %>%
  ftable %>%
  toLatex

No hacking needed, and LaTeX can be used for the names of the columns in expand.grid (to support e.g. rotation and/or spanning multiple rows). The generated LaTeX code requires the booktabs and dcolumn packages.

Compiled output

Related: Creating a latex table from ftable object in R.

Community
  • 1
  • 1
krlmlr
  • 25,056
  • 14
  • 120
  • 217