LaTeX document is actually a program, with text to be formatted. However they are not particularly friendly to program on. At least it takes a lot of trial and error… Here is how I tackled a problem with working with macro in LaTeX.
Problem:
I recently had to generate a rather complex table with colouring rules. (essentially a ‘heatmap’ table) To do this, I have used several packages: \colortbl
, \color
and \fp
.
colortbl
and color
was used to set the colour of the cell itself using \cellcolor{}
command. In addition, fp
was needed to compute a colour based on the value by simply doing ‘1 – decimal value’ to get the ratio between the two colours in RGB. While LaTeX document is a program, is really not designed for us, endusers, to write a program that requires computation. By default, decimal point calculation is a nightmare, thus fp
was imported to make it less painful.
One of the troublesome aspect is how LaTeX documents are compiled. The gist of this is basically a series of token expansion. It expands top to bottom, left to right, through a series of commands. And in the context of macros, something like this becomes a nightmare:
\cellcolor[rgb]{\mycommand{#1},0,0}
Something like this will probably cause an error indicating this is an invalid argument for \cellcolor{}
as they expect three values in the range of 0.0-1.0 representing red, green, and blue.
To solve this, you need to prevent LaTeX compiler to attempt expanding \cellcolor{}
before \mycommand
. My initial attempt was to insert \expandafter
to make LaTeX expand the later tokens to expand first. However, that did not solve this.
Solution:
The solution ended up being rather hacky but almost similar to C macro:
\edef\tmp{\noexpand\cellcolor[rgb]{\mycommand{#1},0,0}}% \tmp%
UPDATE: The solution (I believe) does the following:
- Define temporary macro using
\edef
- Avoid the expansion of
\cellcolor
by prepending\noexpand
when\edef
is being expanded to define a macro - But that did not stop expanding
\mycommand
- Calls the temporary macro defined with the result of
\mycommand
inserted
I don’t claim to understand perfectly how it was expanded, but I believe this is what has happened. This idea came from [2]. In addition, I found [1] to be useful in understanding how LaTeX parses the commands. (I also saw a great table summarising different commands used to instruct expansion order, which now I can’t find…)
In the process of trying this, I have also discovered that macros should have escapes for new lines (\n
) as part of the macros by appending %
at the end of each lines. As similar to macros, it will paste the whole block when being expanded. This lead to an interesting problem in the context of \tabular{}
command where the text inside the cell had an odd padding in the cell, breaking centering column alignment, which was caused by this new lines interpreted and inserted. Thus if you want a sensible looking macros in LaTeX, where not everything is in a single line, end of line has to be escaped.
In short:
- If
\expandafter
fails, try defining a temporary macro and use\noexpand
. - Remember to escape the end of line when changing line in your multi-line LaTeX macro by using
%
.
References:
[1] Overleaf – How does \expandafter work: An introduction to TeX tokens
https://www.overleaf.com/learn/latex/Articles/How_does_%5Cexpandafter_work:_An_introduction_to_TeX_tokens
[2] A Tutorial on \expandafter – Stephan v. Bechtolsheim http://www.tug.org/TUGboat/Articles/tb09-1/tb20bechtolsheim.pdf
UPDATE (2020 08 05): Added bit of explanation of the solution. Also fixed some typos…
I realise this is a whole other rabbit-hole, but I wonder if this would have been easier in luatex, where you have a sensible programming language to write programs in?
Thank you for the comment!
The world of typesetting, let alone TeX and LaTeX is already a massive rabbit-hole! (And add the spice called curiosity of typesetting in multiple writing system, mixed language typesetting and oh my, it’s *complex*!)
LuaTeX could have helped me here – people have been suggesting LuaTeX in very complex TeX macro and operations other people were struggling on the forum. But in the context of paper submission to a publisher, having a coauthor to work with, and the fact that I have never touched or seen Lua, I have decided against even looking into it.
Now that I had a brief peek at some articles on overleaf about LuaTeX I am a little intrigued.
I am not entirely sure how much it made this specific snipped easier – but the possibility more ‘sane’ programming environment could bring to the table is very tempting. The macro I wrote has to be inserted before the content of the cell, which you’d think “why not wrap the whole thing?”. The problem with that is that the cell content is a tuple with angled brackets, fractions and multiple decimal values, and colour the cell using one element of the decimal values. So, it felt easier/safer to copy-paste the desired decimal value into the macro argument, which gets replaced to \cellcolor{} after macro expansion. But with Lua, I could perhaps parse the whole cell and extracted the second element correctly and still append the \cellcolor{} macro before pasting the whole tuple.
In short, I do think LuaTeX would be useful, but considering the situation, I’ll have to be very careful if I wanted to use it and will have to learn a lot.