1

I found this post, illustrating how to typeset the header of a table in bold face. Combining it with \csvreader from the csvsimple package worked fine, as long as I don't format the numbers using siunitx package. Below \sisetup fixes two decimal points as in this answer.

\documentclass{article}
\usepackage{csvsimple, siunitx, booktabs, array}

\begin{filecontents}{sample.csv} Player, Merlin, Mordred Andrew, 0.6, 0.55 Ben, 0.54, 0.62 \end{filecontents}

\newcolumntype{+}{>{\global\let\currentrowstyle\relax}} \newcolumntype{-}{>{\currentrowstyle}} \newcommand{\rowstyle}[1]{\gdef\currentrowstyle{#1}#1\ignorespaces}

\csvstyle{boldhead}{ no head, table head=\toprule\rowstyle{\bfseries}, late after first line=\ \midrule, table foot=\bottomrule } \sisetup{round-mode=places, round-precision=2, round-integer-to-decimal}

\begin{document}

\csvreader[tabular=+l-c-c, boldhead]{sample.csv}{}{\csvcoli & \csvcolii & \csvcoliii}

\end{document}

I think there are three problems with this solution:

  1. The option head to column names cannot be used because the no head option is loaded. Is there a better way to display the header using \csvreader that preserves the possibility of using head to column names?
  2. If I replace tabular=+l-c-c with tabular=+l-S-S, then the table no longer typesets because the siunitx package does not recognize the header and throws the error invalid numerical input 'e'.
  3. Personally, I'd prefer typing lcc instead of +l-c-c.

Since the number formatting of the siunitx package can be escaped with a group, my idea for point 2 was to include a \bgroup \egroup pair into the rowstyle as follows:

\newcolumntype{+}{>{\global\let\currentrowstyle\relax\global\let\currentrowstylepost\relax}}
\newcolumntype{-}{>{\currentrowstyle}}
\newcolumntype{^}{<{\currentrowstylepost}}
\newcommand{\rowstyle}[1]{%
    \gdef\currentrowstylepost{\egroup}%
    \gdef\currentrowstyle{#1\bgroup}%
    #1\bgroup\ignorespaces%
}

While the above code works for option tabular=+l^-c^-c^, it still does not work for tabular=+l^-S^-S^. What am I missing?

Regarding point 3, one would imagine that this can be fixed with the tokcycle package. This was my attempt.

\settcEscapechar{:}
\newif\iffirstchar
\Characterdirective{%
    \ifx#1|%
        #1%
    \else%
        \iffirstchar%
            \global\firstcharfalse%
            +#1%
        \else%
            -#1%
        \fi%
    \fi%
}

\newcommand{\csvboldreader}[4]{% \global\firstchartrue% \csvreader[tabular=\tokencyclexpress #1\endtokencyclexpress, boldhead]{#2}{#3}{#4} }

\begin{document} \csvboldreader{lcc}{sample.csv}{}{\csvcoli & \csvcolii & \csvcoliii} \end{document}

Unfortunately, it throws an error illegal token 'c' used. If I call

\tokencyclexpress lcc\endtokencyclexpress

in isolation, the string is transformed correctly. What am I missing?

I have to admit I am not too familiar with the siunitx package and figured I'd tag on two more questions about it:

  1. What is the cleanest \sisetup to align numbers centered with the header, but among each other aligned according to the decimal point? Is there a better way than setting {S[table-format=1.2]} etc. manually for each column?
  2. What is the @{} used for that appears in the siunitx manual? My first guess was that one doesn't have to use braces for each column, but that appears to be incorrect since tabular=@{} l S S[table-format=2.2] @{} doesn't work.

1 Answers1

1

See SUPPLEMENT for alternative.

As to the tokcycle portion of the question (item No. 3), there were two problems with the approach posted:

  1. Running the token cycle inside of \csvreader optional argument does not work.

  2. Even passing a macro with the proper tokens, as in tabular=\mypreamble, does not work. It must be passed the actual tokens of the tabular preamble.

Thus, several things were needed. The token cycle had to be performed in advance of the \csvreader invocation and the result had to be saved in the \cytoks token list. This required the \Characterdirective to be changed from the direct output of <tokens> to the equivalent \addcytoks{<tokens>} format. By using \tokcyclexpress (macro) rather than \tokencyclexpress (pseudo-environment), the automatic typsetting of \the\cytoks output is suppressed, even as the result is stored in \cytoks.

So far, so good. But even here, tabular=\the\cytoks as an option in \csvreader does not work. So, the invocation had to be broken into two parts: \def\tmp{\csvreader[tabular=} followed by \expandafter\tmp\the\cytoks, boldhead]{#2}{#3}{#4}. In this way, \the\cytoks expanded into the actual desired tokens prior to the invocation of \csvreader.

\documentclass{article}
\usepackage{csvsimple, siunitx, booktabs, array,tokcycle}

\begin{filecontents}[overwrite]{sample.csv} Player, Merlin, Mordred Andrew, 0.6, 0.55 Ben, 0.54, 0.62 \end{filecontents}

\newcolumntype{+}{>{\global\let\currentrowstyle\relax}} \newcolumntype{-}{>{\currentrowstyle}} \newcommand{\rowstyle}[1]{\gdef\currentrowstyle{#1}#1\ignorespaces}

\csvstyle{boldhead}{ no head, table head=\toprule\rowstyle{\bfseries}, late after first line=\ \midrule, table foot=\bottomrule } \sisetup{round-mode=places, round-precision=2, round-integer-to-decimal}

\settcEscapechar{:} \newif\iffirstchar \Characterdirective{% \ifx#1|% \addcytoks{#1}% \else% \iffirstchar% \global\firstcharfalse% \addcytoks{+#1}% \else% \addcytoks{-#1}% \fi% \fi% }

\newcommand{\csvboldreader}[4]{% \global\firstchartrue% \tokcyclexpress{#1}% \def\tmp{\csvreader[tabular=}% \expandafter\tmp\the\cytoks, boldhead]{#2}{#3}{#4} }

\begin{document} \csvboldreader{lcc}{sample.csv}{}{\csvcoli & \csvcolii & \csvcoliii} \end{document}

enter image description here

SUPPLEMENT

Here is an alternative approach that supports the siunitx column types as well as a bolded (or other) first line:

\documentclass{article}
\usepackage{siunitx, booktabs, array, tokcycle, readarray}
\begin{filecontents*}[overwrite]{sample.csv}
Player, Merlin, Mordred
Andrew, 0.6, 0.55
Ben, 0.54, 0.62
\end{filecontents*}
\sisetup{round-mode=places, round-precision=2, round-integer-to-decimal}
\newif\iffirstrow
\Characterdirective{%
  \iffirstrow
    \tctestifx{,#1}{\addcytoks{&\xxcmd}}{\addcytoks{{#1}}}
  \else
    \tctestifx{,#1}{\addcytoks{&}}{\addcytoks{#1}}
  \fi
}
\Macrodirective{%
  \iffirstrow
    \tctestifx{\\#1}{\firstrowfalse\addcytoks{#1\midrule}}{\addcytoks{#1}}
  \else
    \addcytoks{#1}
  \fi
}
\newcommand\csvxreader[3][\bfseries]{%
  \readarraysepchar{\\}%
  \readdef{#3}\mytab
  \firstrowtrue
  \def\xxcmd{#1}%
  \expandafter\tokcyclexpress\expandafter{\mytab}%
  \begin{tabular}{#2}%
  \toprule
  #1%
  \the\cytoks
  \bottomrule
  \end{tabular}%
}
\begin{document}
\csvxreader[\scshape]{lcc}{sample.csv}

\bigskip \csvxreader{lSS}{sample.csv} \end{document}

enter image description here

  • Thank you. Let me see if I understand correctly. The \tokcyclexpress cannot be called within an argument because it is a fragile command (as, presumably, most other commands in the package?). Second, \the\cytoks needs to be expanded before it is processed by \csvreader. Because \expandafter looks ahead only one token, we need to store the rest in \tmp. Correct?

    I need some time to process the alternative answer as I was not aware of the readarray package until today. Thanks for pointing me towards it!

    – S. Olafsson May 29 '21 at 07:47
  • 1
    @S.Olafsson Not because \tokcyclexpress is fragile, but because it is unexpandable (because its execution involves assignments, as in \def, \let, and \futurelet). The rest of your comment is on point. The \tmp storage was particularly helpful here, otherwise, to expandafter an input like [tabular= would require \expandafter [\expandafter t\expandafter a\expandafter b\expandafter u\expandafter l\expandafter a\expandafter r\expandafter =. You can see the problem here. – Steven B. Segletes May 29 '21 at 12:08
  • 1
    @S.Olafsson The readarray package is due for an upgrade. See my SUPPLEMENT at https://tex.stackexchange.com/questions/498008/set-value-in-readarray/498009#498009 to see the sort of upgrade it will be. – Steven B. Segletes May 29 '21 at 12:14