# Macro expansion in TikZ node

I am having some problems with macro expansion in TikZ nodes. The MWE below is supposed to draw nodes at specified coordinates and display their coordinate rounded to the nearest number, but it shows the coordinates of the last node for both of them.

\documentclass[]{article}

\usepackage{pgfplots}
\usepackage{xparse}

\ExplSyntaxOn

\tl_new:N \x
\tl_new:N \x_round

\NewDocumentCommand \mynode { m } {
\tl_set:Nn \x {
\fp_eval:n { #1 }
}

\tl_set:Nn \x_round {
\fp_eval:n { round ( \x ) }
}

\addplot [style={mark=none}] coordinates { ( \x , \x ) } node { \x_round } ;
}

\ExplSyntaxOff

\begin{document}
\begin{tikzpicture}
\begin{axis}
\mynode{1.1}
\mynode{2.2}
\end{axis}
\end{tikzpicture}
\end{document}


I assume the problem is that the \x_round is not expanded in the node until the end of the environments. How can I ensure \x_round is expanded immediately?

I have noticed that replacing the command with

\NewDocumentCommand \mynode { m } {
\addplot [style={mark=none}] coordinates { ( #1 , #1 ) } node { \fp_eval:n { round ( #1 ) }  } ;
}


does fix the problem, but for my real code, it is inadequate as the code is more complex.

• \x is a blasphemy regarding expl3 naming convention ;-)
– user31729
Feb 4, 2019 at 9:29
• Hehe, I wanted to keep it simple for the MWE. My actual code as proper naming ;)
– slo
Feb 4, 2019 at 10:52

You should use \tl_set:Nx, but it's quite pointless anyway:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \mynode { m }
{
coordinates { ( \fp_eval:n { #1 } , \fp_eval:n { #1 } ) }
node { \fp_eval:n { round(#1) } } ;
}

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\begin{axis}
\mynode{1.1}
\mynode{2.2}
\end{axis}
\end{tikzpicture}

\end{document}


Avoid names such as \x and \x_round, use the proper naming conventions.

You can use variables (here I use fp ones, but tl can be good as well, provided you set them with \tl_set:Nx). However, text in the node has to be expanded before passing it to PGF:

\documentclass{article}

\usepackage{pgfplots}
\usepackage{xparse}

\ExplSyntaxOn

\fp_new:N \l_slo_coord_x_fp
\fp_new:N \l_slo_coord_x_round_fp

\NewDocumentCommand \mynode { m }
{
\fp_set:Nn \l_slo_coord_x_fp { #1 }
\fp_set:Nn \l_slo_coord_x_round_fp { round ( \l_slo_coord_x_fp ) }
\use:x
{
coordinates { ( \fp_use:N \l_slo_coord_x_fp , \fp_use:N \l_slo_coord_x_fp ) }
node { \fp_use:N \l_slo_coord_x_round_fp } ;
}
}

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\begin{axis}
\mynode{1.1}
\mynode{2.2}
\end{axis}
\end{tikzpicture}

\end{document}

• Perhaps worth using an auxiliary? I'd tend to avoid evaluating the same expression multiple times, both for efficiency and as it could have a random component. Feb 4, 2019 at 9:47
• @JosephWright It doesn't really work here, because one has to expand the argument to node. Feb 4, 2019 at 9:55
• Thanks, it works great. I actually tried using \tl_set:Nx, but I guess node has to be unexpanded if I understand things correctly, right?
– slo
Feb 4, 2019 at 11:54
• Can you add some explanation what you fixed in the first case? (the expression to be computed is substituted directly into the node label (\fp_eval:n { round(#1) }), so even though \addplot only expand it at the end of the environment, it evaluates to the correct result; on the other hand \x_round is dependent on the definition of that control sequence which is changed afterwards), I think? Nov 7, 2021 at 7:52
• @user202729 I'm not sure what youu mean by “expands it at the end of the environment”. What I can see is that the arguments are expanded when \addplot is executed. In the OP's version, \x_round was stored, not its value, so, at \end{axis} it received the last value. Nov 7, 2021 at 10:01