2013/12/18

colortbl で \cline を使いたい

日本でLaTeXが生きのこるには、縦横無尽に罫線が引かれた彩り豊かな表を描けなければならない。 でも、表のセルに色を塗るための colortbl パッケージと、横線を好きな場所に引くための標準的な方法である \cline には、罫線までもが色で塗りつぶされてしまうという困った問題があります。

\begin{tabular}
  {|>{\color{white}\columncolor{red}  }c
   |>{\color{white}\columncolor{green}}c
   |>{\color{white}\columncolor{blue} }c|} \hline
  a & b & c \\ \cline{1-1}\cline{3-3}
  1 &   & 3 \\ \hline
\end{tabular}

本当なら、こんな具合に、左右の列だけにセル間の横罫線が引かれてほしいわけです。

これは TeX & LaTeX Advent Calendar の18日目の記事です。 昨日はabenoriさんの「可換図式を書こう:tikz-cdを使う.」です。

公式見解

この \cline が上書きされてしまう現象は、 colortbl のマニュアルでも言及されている既知の問題です。 いわく、「これは \cline の仕様なので代わりに \hhline を使え」とあります。

10 Less fun with \cline
Lines produced by \cline are coloured if you use \arrayrulecolor but you may not notice as they are covered up by any colour pannels in the following row. This is a `feature' of \cline. If using this package you would probably better using the - rule type in a \hhline argument, rather than \cline.

実際、"TeX - LaTeX Stack Exchange" における質問でも、 \hhline を使った回答が寄せられているようです(参照1参照2)。 しかしぶっちゃけ \hhline はまったく解決策になりません。 それどころか、今度は罫線を引きたくない箇所に白い線が出現したり、縦罫線が切断されたりしてしまいます。

\usepackage{hhline}
...
\begin{tabular}
  {|>{\color{white}\columncolor{red}  }c
   |>{\color{white}\columncolor{green}}c
   |>{\color{white}\columncolor{blue} }c|} \hline
  a & b & c \\ \hhline{-|~|-}
  1 &   & 3 \\ \hline
\end{tabular}

これはひどい。

ごまかし方

colortbl で特定の列にだけ横罫線を引くことは不可能なのでしょうか。 実は、方法がないではないので、それを紹介します。ただし後述するように、厳密にいうとこの解法には落とし穴があるので注意してください。

そもそもなんで罫線が塗りつぶされるかというと、 colortbl では罫線を引くプロセスのあとにセルに色を塗っているからなのですが、これは TeX の仕組み的にはチートできません。 色を塗るにはセルの大きさが決定していなければならず、その段階では罫線も引き終わることになっているからです。

でも逆に考えれば、セルの高さに対して罫線の位置をはじめからずらして引くようにしてしまえば、罫線を微妙に避けて色を塗ってくれるはずです。 そこで次のような \cline の定義(もとは latex.ltx にあるけど colortbl パッケージで上書きされてるもの)を……

%% \@cine from colortbl.sty
\def\@cline#1-#2\@nil{%
  \omit
  \@multicnt#1%
  \advance\@multispan\m@ne
  \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi
  \@multicnt#2%
  \advance\@multicnt-#1%
  \advance\@multispan\@ne
  {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}%
  \cr
  \noalign{\vskip-\arrayrulewidth}}

次のように書き換えてプリアンブルに書きます(\makeatletter を忘れずに)。

\def\@cline#1-#2\@nil{%
  \noalign{\vskip-\arrayrulewidth}
  \omit
  \@multicnt#1%
  \advance\@multispan\m@ne
  \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi
  \@multicnt#2%
  \advance\@multicnt-#1%
  \advance\@multispan\@ne
  {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}%
  \cr}

元の定義で一番最後にあった \noalign{\vskip-\arrayrulewidth} を先頭にもってきただけで、ほかはそのままです。 これだけで、ふつうに \cline を使えば横罫線が出現するようになります。もちろん不要な箇所に白線が出ることもありません。

\begin{tabular}
  {|>{\color{white}\columncolor{red}  }c
   |>{\color{white}\columncolor{green}}c
   |>{\color{white}\columncolor{blue} }c|} \hline
  a & b & c \\ \cline{1-1}\cline{3-3}
  1 &   & 3 \\ \hline
\end{tabular}

やったね。

うまくないところ

この方法は、罫線を、罫線の幅だけ上にちょっとずらすことで、一見成功しているように見える結果を得ています。 なので、ずれてない本来の位置に罫線を一緒に引いてみると、アラがわかります。

\begin{tabular}
  {|>{\color{white}\columncolor{red}  }c
   |>{\color{white}\columncolor{green}}c
   |>{\color{white}\columncolor{blue} }c|} \hline
  a & b & c \\ \cline{1-1}\cline{3-3}\hilne
  1 &   & 3 \\ \hline
\end{tabular}

残念ですね。

No comments :