Appending an empty row after every 5 or 10 rows in LaTeX table
The following solution sets up an environment blocktable
derived from longtable
that provides the desired functionality using LaTeX only.
Implementation notes
First, a few counters are needed:
\newcounter{@tabrow}
\newcounter{@emptyrow}
\newcounter{@modulus}
\newcounter{@default@blocksize}
@tabrow
will be incremented every row to determine the current row number while @emptyrow
will hold multiples of @modulus
(which accordingly is set to the number of rows one block/chunk should contain; to be precise it will be @modulus+1
). Last mentioned is set internally through \@setblocksize
:
\newcommand{\@setblocksize}[1]{%
\setcounter{@modulus}{#1}
\setcounter{@emptyrow}{\the@modulus}
\stepcounter{@modulus}
}
@default@blocksize
holds the global default value that will be given to @modulus
if no optional argument is specified (see below: blocktable
).
The core macro is \empty@or@void@line
which expands to an empty line, i.e. &...&\\
, if \the@tabrow
is a multiple of \the@modulus
and to simply nothing if not:
\def\empty@or@void@line{%
\ifnum\the@tabrow=\the@emptyrow
\addtocounter{@emptyrow}{\the@modulus}%
\@colseps\ltx@LT@tabularcr
\fi}
It will be added to every occurance of \\
by saying:
\def\LT@tabularcr{\ltx@LT@tabularcr\empty@or@void@line}
As seen, in \empty@or@void@line
internally the empty row internally gets constructed via \@colseps\ltx@LT@tabularcr
where \ltx@LT@tabularcr
is a stored version of \LT@tabularcr
and \@colseps
contains the right number of &
s which is done with the help of longtable
's \LT@cols
(which holds the number of columns!) by an auxiliary command:
\newcommand\build@colseps{%
\@tempcnta\@ne
\loop
\advance\@tempcnta by 1
\g@addto@macro\@colseps{&}
\ifnum\@tempcnta<\the\LT@cols\repeat
}
The core functionality is applied to a new environment blocktable
based on longtable
:
\newenvironment{blocktable}[2][\the@default@blocksize]
{\@setblocksize{#1}\build@colseps\longtable{@{\stepcounter{@tabrow}}#2}}
{\endlongtable \gdef\@colseps{} \setcounter{@tabrow}{0}}
which assembles all the work done before. It also cleans up the @tabrow
count and \@colseps
macro -- which was also allocated empty beforehand.
To make sure that the blocking/chunking begins at the right row the following lines conclude the solution code:
\g@addto@macro\endfirsthead{\setcounter{@tabrow}{1}}
\g@addto@macro\endhead{\setcounter{@tabrow}{1}}
\g@addto@macro\endfoot{\setcounter{@tabrow}{1}}
\g@addto@macro\endlastfoot{\setcounter{@tabrow}{1}}
Example
Figure
Before the complete code here is an example pic produced using the default chunk size of 5:
Complete code
\documentclass{article}
\usepackage{booktabs}
\usepackage{longtable,array}
\makeatletter
\newcounter{@tabrow}
\newcounter{@emptyrow}
\newcounter{@modulus}
\newcounter{@default@blocksize}
\setcounter{@default@blocksize}{5}
\def\@colseps{}
\let\ltx@LT@tabularcr=\LT@tabularcr
\def\empty@or@void@line{%
\ifnum\the@tabrow=\the@emptyrow
\addtocounter{@emptyrow}{\the@modulus}%
\@colseps\ltx@LT@tabularcr
\fi}
\def\LT@tabularcr{\ltx@LT@tabularcr\empty@or@void@line}
\newenvironment{blocktable}[2][\the@default@blocksize]
{\@setblocksize{#1}\build@colseps\longtable{@{\stepcounter{@tabrow}}#2}}
{\endlongtable \gdef\@colseps{} \setcounter{@tabrow}{0}}
\newcommand\build@colseps{%
\@tempcnta\@ne
\loop
\advance\@tempcnta by 1
\g@addto@macro\@colseps{&}
\ifnum\@tempcnta<\the\LT@cols\repeat
}
\newcommand{\@setblocksize}[1]{%
\setcounter{@modulus}{#1}
\setcounter{@emptyrow}{\the@modulus}
\stepcounter{@modulus}
}
\newcommand{\defaultBTblocksize}[1]{\setcounter{@default@blocksize}{#1}}
\g@addto@macro\endfirsthead{\setcounter{@tabrow}{1}}
\g@addto@macro\endhead{\setcounter{@tabrow}{1}}
\g@addto@macro\endfoot{\setcounter{@tabrow}{1}}
\g@addto@macro\endlastfoot{\setcounter{@tabrow}{1}}
\makeatother
%\defaultBTblocksize{10}
\begin{document}
\listoftables
\begin{blocktable}{ccc}
\caption{Boring example table}\\
\toprule
\textbf{col1} & \textbf{col2} & \textbf{col3}\\
\midrule
\endfirsthead
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
foo & bar & baz\\
\bottomrule
\end{blocktable}
\end{document}
Remarks
- I don't use knitr and therefore I did not test the solution with a table generated from an external data file like in the OP's mwe, but it should work without any problems when you declare
tabular.environment = 'blocktable'
. - When inserting an actual blank line there is the caveat that material inserted by
@{...}
also affects the lines left out (which isn't desiderable in my eyes) and the row numbering is just wrong and tricks are needed. # - To not overload this answer I packaged an alternative solution merged with the old one into a github repository: https://github.com/giannotr/blocktable (as a package called
blocktable
. This isn't an official package and it's neither properly documented nor tested. You get the original solution by chosing the 'emptyline' option).
Since you are using knitr
, the simplest thing is to add \\
every tenth row using add.to.row
parameter of print.xtable
.
This is a very rough code; in the general case you need also to check that MatrixData
has more than 10 rows.
\documentclass{article}
\usepackage{longtable}
\begin{document}
\listoftables
<< label=LongTable, results='asis', echo = FALSE >>=
library(xtable)
set.seed(12345)
MatrixData <- matrix(rnorm(1000), ncol = 10)
caption <- paste("\\hline \\endfirsthead" , # First caption
"\\caption[]{Example of longtable spanning several pages} \\label{tab:MatrixData} \\\\ \\hline", # Additional captions
paste("&", 1:ncol(MatrixData),collapse=" "), # Column names
"\\\\ \\hline ",
"\\endhead",
"\\hline \\multicolumn{11}{r}{\\textit{Continued}} \\
\\endfoot
\\endlastfoot",collapse=" ")
positions <- seq(from=10, to=dim(MatrixData)[1], by=10)
print(
xtable(
x = MatrixData
, caption = "Example of longtable spanning several pages"
#, label = "tab:MatrixData"
, align = c("l|", rep("r", ncol(MatrixData)))
, digits = c(rep(3, ncol(MatrixData)+1))
)
, table.placement = "H"
, caption.placement = "top"
, include.rownames = TRUE
, include.colnames = TRUE
, size = "small"
, tabular.environment = 'longtable'
, floating = FALSE
, add.to.row =
list(pos = as.list(c(0,positions)),
command = c(caption,rep("\\\\",length(positions)))))
@
\end{document}