1

I boiled down the problem to much more simple MWE. See the update below.

I tried to customize the tabular environment to make it easy to use a coherent style throughout my thesis. I wanted for the tabular environment to be able to

  • automatically add \addlinespace after every line in the table body (except for the last one)
  • automatically do alternating row colors - not for individual lines, but for groups of lines (mostly 3, somewhere else on stackexchange this was recommended

I know there is \arraystretch, but this also affects the header, and thus it looks awkward if the two types of tables are used close each other. I also know that the \rowcolors command exists, but that does not allow to colorize groups of lines (to the best of my knowledge).

I did all those modifications inside a custom environment, and I can select which one (or both) of the modifications with a command. Both options work, but unfortunatelly the row coloring has a strange effect on the next tabular environment, i.e., not the one that is modified by me.

I prepared a minimal working example:

\documentclass[a4paper,11pt]{book}

\usepackage[T1]{fontenc}
\usepackage[english]{babel}
\usepackage{booktabs}
\usepackage[table]{xcolor}
\usepackage{ifthen}
\usepackage{calc}

\input{tables}

\begin{document}

\begin{stable}
\srowgroupcolors{2}{white}{orange}
\begin{tabular}{ccc}
\toprule
a & b & c\\ 
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}

\begin{stable}
\begin{tabular}{ccc}
\toprule
a & b & c\\ 
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}

\begin{stable}
\begin{tabular}{ccc}
\toprule
a & b & c\\ 
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}

\end{document}

The \srowgroupscolors{2}{white}{orange} command in the first table activates the row coloring. The second table shows the problem in the first column of the first line (after the \toprule). The third table works as excepted. Note that the problem still persists even if the second tabular environment is used without the surrounding stable environment.

The result looks like this (for the 2nd table inside the stable environment):

tables

The code for stable is defined in the file tables.tex below. I removed the part that is used for the automatic line spacing, because it causes no problems. It's still rather long (although it consists or more comments than code).

What it does is the following: it counts the table rows, but only for the body, i.e., after \midrule has been used. While in the header, the counter stays at zero. For each body row, \stable@color@step is called by the overridden \@arraycr command. (Note that stable@color@step is defined in \srowgroupcolors, otherwise it's empty.) It calls \stable@calc@rowcolor (in a \noalign command) that calculates the color based for the next row and stores the corresponding \rowcolor command in \stable@rowcolor. The latter is called directly after the \noalign command. Therefore the \rowcolor command for the next line is issued immediately after the \\.

 \makeatletter                                                                                                                                                                                                                           

% counter for the line number (modulo 2 * group@size)
\newcounter{stable@counter}
% size of groups (row coloring)
\newcounter{stable@group@size}
% modulo value, used to get the right color
\newcounter{stable@modulo}
% whether array / tabular have already been patched
\newboolean{stable@patched}

% replacement for table
% arguments:
% #1 - placement - default is !htb
\newenvironment{stable}[1][!htb]{%
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % internal commands for auto spacing and coloring of rows
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %   
    % set the group size and calculate the modulo
    \newcommand*{\stable@set@group@size}[1]{%
        \setcounter{stable@group@size}{##1}%
        \setcounter{stable@modulo}{2*\value{stable@group@size}}%
    }%  
    %   
    % calculate the rowcolor based on the row number
    % step the rownumber (module 2 * group size) if > 0 (body)
    % TODO refactor: extract a step method
    \newcommand{\stable@calc@rowcolor}{%
        \ifthenelse{\value{stable@counter}=0}%
            % we're still in the header
            {\gdef\stable@rowcolor{}}%
            % we're in the body
            {%  
                % 1 - group size: color 1, above group size: color 2
                \ifthenelse{\value{stable@counter}>\value{stable@group@size}}%
                    {\gdef\stable@rowcolor{\rowcolor{stable@color2}}}%
                    {\gdef\stable@rowcolor{\rowcolor{stable@color1}}}%
                % increase counter -> number of the NEXT row 
                \stepcounter{stable@counter}%
                % modulo operation
                \ifthenelse{\value{stable@counter}>\value{stable@modulo}}%
                    % reset to 1 (sic!), as 0 would be header
                    {\setcounter{stable@counter}{1}}%
                    {}% 
            }%  
    }%  
    %   
    % shortcut: call stable@calc@color in a \noalign, use the calculated color
    % the default implementation does nothing, the command has to be changed
    \def\stable@color@step{}
    %   
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % modify the array / tabular package
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % backup the original array / tabular commands
    \newcommand{\stable@arraycr}{}%
    \let\stable@arraycr\@arraycr%
    \newcommand{\stable@midrule}{}%
    \let\stable@midrule\midrule%
    %
    % patch the array / tabular commands
    % lazy patching makes sure this does not break anything
    \newcommand*{\stable@patch@array}{%
        \ifthenelse{\boolean{stable@patched}}%
            % already patched, do nothing
            {}%
            {%
                \setboolean{stable@patched}{true}%
                % replace the \\ command (@arraycr): integrate coloring and spacing
                \renewcommand{\@arraycr}{%
                    \stable@arraycr%
                    \stable@color@step%
                }%
                %
                % replace \midrule: start coloring and spacing
                \renewcommand{\midrule}{%
                    \stable@midrule%
                    % set counter to 1 (end of heading}
                    \noalign{%
                        \setcounter{stable@counter}{1}%
                    }%
                    % start coloring (1st row)
                    \stable@color@step%
                }%
            }%
    }%
    %
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % external commands for tables
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % alternating colored groups of rows
    % arguments:
    % #1 - group size
    % #2 - first color (tables always start with this color)
    % #3 - second color
    \newcommand{\srowgroupcolors}[3]{%
        % shortcut: call stable@calc@color in a \noalign, use the calculated color
        \def\stable@color@step{\noalign{\stable@calc@rowcolor}\stable@rowcolor}%
        % store the settings
        \stable@set@group@size{##1}%
        \colorlet{stable@color1}{##2}%
        \colorlet{stable@color2}{##3}%
        % patch the array commands
        \stable@patch@array
    }%
    %
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % configuration / defaults
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % prepare row counter
    % (count rows modulo (2 * colored group size), value 0 means: header)
    \setcounter{stable@counter}{0}%
    % initialize with default values                                                                                                                                                                                                       
    \stable@set@group@size{1}%
    % array / tabular commands have not yet been patched
    \setboolean{stable@patched}{false}%
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % start of the actual table
    % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % use small sized sans serif font
    \begin{table}[#1]%
}{%
    \end{table}%
}%

\makeatother

Somehow my code must have managed to break something in tabular although everything is done inside the stable group. The only exception to this is the use of \gdef in the \stable@calc@rowcolor that is used to temporarily store the \addlinespace (if required). I used this workaround (taken from this question) to avoid the !Misplaced \noalign error.

Has anybody an idea what can be the source of this problems?

Update

The following code triggers the same problem - this is exactly what my tabular extension does:

\documentclass[a4paper,11pt]{book}

\usepackage[T1]{fontenc}
\usepackage[english]{babel}
\usepackage{booktabs}
\usepackage[table]{xcolor}

\begin{document}

\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\                                           
\midrule
\rowcolor{white} 0 & 0 & 0 \\
\rowcolor{white} 0 & 1 & 1 \\
\rowcolor{orange} 1 & 0 & 1 \\
\rowcolor{orange} 1 & 1 & 0 \\
\rowcolor{orange} \bottomrule
\end{tabular}
\end{table}

\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\ 
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{table}

\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\ 
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{table}

\end{document}

This is triggered by adding the \rowcolor command directly after the \\ (using either \everycr or by overwriting \@arraycr). At that point it is not clear if another row follows. For some reason, the tabular environment does not like a \rowcolor in the last line, if the last line is either a \bottomrule or a \hline.

Is there a way to fix this problem? Does tabular offer a hook at the beginning of a row that I can use instead? Is it possible to check that a row does not contain a \bottomrule?

Or is there a way to "undo" the \rowcolor command in an overwritten \bottomrule? Actually this is what I do to get the spacing part (not shown in the example) working.

Update 2

I further investigated the issue. It boils down to a problem in colortbl. When \rowcolor is used without being followed by a \\, the next tabular shows the error. The most minimal example I found is the following:

\documentclass{article}                                      

\usepackage[english]{babel}
\usepackage{colortbl}

\begin{document}

\begin{tabular}{c}
a \\                                        
\rowcolor{orange}
\end{tabular}

\begin{tabular}{c}
a \\
\end{tabular}

\end{document}

The result looks like this:

tables

To me this seems to be a bug in colortbl. Even if this "trailing" \rowcolor it totally pointless, it should not have an effect on the next tabular.

I tried to look at how \rowcolors solves the problem - it does not seem to generate such a "trailing" rowcolor command, but I do not understand the source completely.

My workaround is to create the next tabular in a savebox that is then discarded. The tabular created after the savebox does not show the problem.

\documentclass{article}

\usepackage[english]{babel}
\usepackage{colortbl}

\begin{document}

\begin{tabular}{c}
a \\                                           
\rowcolor{orange}
\end{tabular}

\newsavebox{\bin}
\savebox{\bin}{\tabular{c}\\\endtabular}

\begin{tabular}{c}
a \\
\end{tabular}

\end{document}

Anyway, if there is a better way that fixes my extension I'd happily use that instead of this ugly workaround.

3
  • 1
    colortbl does quite a lot settings globally -- after all the rowcolor should affect the whole row and as every cell is a group it has to do it globally. I don't have the time to check your code but it looks as if you should better use \everycr to insert your colors instead of redefining \@arraycr. See e.g. tex.stackexchange.com/questions/89324/… Aug 5, 2015 at 17:09
  • @Ulrike: I tried the hack from egreg (best answer in the question you linked), but it does not change anything. The second table still contains the black box. Aug 5, 2015 at 20:05
  • I updated the question as the problem clearly seems not to be related to redefining \@arraycr. Aug 5, 2015 at 20:49

1 Answer 1

1

There doesn't really seem to be any use case for adding \rowcolor after all rows, however if that's done you can clear its settings after the table:

\documentclass{article}                                      

\usepackage[english]{babel}
\usepackage{colortbl}

\begin{document}

\begin{tabular}{c}
a \\                                        
\rowcolor{orange}
\end{tabular}

\makeatletter\global\let\CT@do@color\relax\makeatother

\begin{tabular}{c}
a \\
\end{tabular}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .