diff --git a/NEWS.md b/NEWS.md index a01e3d26d6..f8e61262b1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,8 @@ - For the `tikz` engine, the class options of the `standalone` document classs can be specified via the chunk option `engine.opts$classoption` (thanks, @XiangyunHuang, #1985). The default value is `tikz`, i.e., `\documentclass[tikz]{standalone}` is used by default. +- `kable()` operating in LaTeX mode now typesets numeric columns in math mode for improved rendering of minus signs; decimal and thousands separator commas are wrapped in braces (`{}`) to preserve spacing (thanks, @krivit, #1709). + ## MAJOR CHANGES - An error is now thrown when an inline code result is not coercible to character. This has always been the assumed behavior but it happens to be different in certain formats with unknown automatic coercion. This is now enforced to prevent any unexpected output. An inline code expression must evaluate to a character vector or an object coercible by `as.character()` (#2006). diff --git a/R/table.R b/R/table.R index cb8bab5e74..6107f39efc 100644 --- a/R/table.R +++ b/R/table.R @@ -144,6 +144,7 @@ kable = function( x = cbind(' ' = rownames(x), x) if (!is.null(col.names)) col.names = c(' ', col.names) if (!is.null(align)) align = c('l', align) # left align row names + isn = c(FALSE, isn) } n = nrow(x) x = replace_na(to_character(x), is.na(x)) @@ -157,7 +158,7 @@ kable = function( if (format == 'simple' && nrow(x) == 0) format = 'pipe' res = do.call( paste('kable', format, sep = '_'), - list(x = x, caption = caption, escape = escape, ...) + list(x = x, caption = caption, escape = escape, isn = isn,...) ) structure(res, format = format, class = 'knitr_kable') } @@ -281,7 +282,7 @@ kable_latex = function( midrule = getOption('knitr.table.midrule', if (booktabs) '\\midrule' else '\\hline'), linesep = if (booktabs) c('', '', '', '', '\\addlinespace') else '\\hline', caption = NULL, caption.short = '', table.envir = if (!is.null(caption)) 'table', - escape = TRUE + escape = TRUE, isn = logical(ncol(x)) ) { if (!is.null(align <- attr(x, 'align'))) { align = paste(align, collapse = vline) @@ -308,6 +309,7 @@ kable_latex = function( linesep = ifelse(linesep == "", linesep, paste0('\n', linesep)) x = escape_latex_table(x, escape, booktabs) + x[, isn] = paste0('\\(', gsub(',', '{,}', x[, isn], fixed=TRUE), '\\)') if (!is.character(toprule)) toprule = NULL if (!is.character(bottomrule)) bottomrule = NULL tabular = if (longtable) 'longtable' else 'tabular' diff --git a/tests/testit/test-table.R b/tests/testit/test-table.R index 093282ec75..0502de69a4 100644 --- a/tests/testit/test-table.R +++ b/tests/testit/test-table.R @@ -36,9 +36,22 @@ assert('kable() does not add extra spaces to character columns', { \\hline x & y\\\\ \\hline -1.20 & fooooo\\\\ +\\(1.20\\) & fooooo\\\\ \\hline -4.87 & bar\\\\ +\\(4.87\\) & bar\\\\ +\\hline +\\end{tabular}' +}) + +assert('kable() in LaTeX mode formats minus signs and decimal and thousands separators correctly', { + kable2(data.frame(x = c(-1111, 2222), y = c(1111, -0.5), z = c('text,comma', '-0.5')), 'latex', format.arg=list(big.mark = ',')) %==% ' +\\begin{tabular}{r|r|l} +\\hline +x & y & z\\\\ +\\hline +\\(-1{,}111\\) & \\(1{,}111.0\\) & text,comma\\\\ +\\hline +\\(2{,}222\\) & \\(-0.5\\) & -0.5\\\\ \\hline \\end{tabular}') }) @@ -89,11 +102,11 @@ assert('kable(format = "latex", linesep = ...) works', { \\hline x\\\\ \\hline -1\\\\ -2\\\\ -3\\\\ +\\(1\\)\\\\ +\\(2\\)\\\\ +\\(3\\)\\\\ \\midrule -4\\\\ +\\(4\\)\\\\ \\hline \\end{tabular}') })