Problem
I would like to create several nodes whose text is a placeholder for an image, i.e., \phantom{\pgfuseimage{mypicture}}
. This is easily done as, for example:
\matrix {
\node {\phantom{\pgfuseimage{firstpicture}}}; & \node {\phantom{\pgfuseimage{secondpicture}}}; \\
\node {\phantom{\pgfuseimage{thirdpicture}}}; & \node {\phantom{\pgfuseimage{fourthpicture}}}; \\
% etc.
};
The problem is that this is quite verbose. I would like to avoid having to type \phantom{\pgfuseimage{...}}
in each node. Besides saving keystrokes, it would make the code much cleaner and easier to read.
Attempted solutions
Defining a macro to abbreviate
Of course, I could define a command \pgfimageplaceholder
to be \phantom{\pgfuseimage{...}}
. But I would still need to write \pgfimageplaceholder
in each node, so the macro doesn't help save many keystrokes or improve readability much at all.
Using the execute at begin/end node keys
After seeing how matrix of nodes
is defined (page 207 of the PGF/TikZ 2.10 manual), I thought that I might be able to use the execute at begin node
and execute at end node
options in TikZ to factor out \phantom{\pgfuseimage{...}}
. Following the definition of matrix of nodes
, I tried:
\matrix [every node/.append style={execute at begin node=\phantom\bgroup\pgfuseimage\bgroup,
execute at end node=\egroup\egroup}]
{
\node {firstpicture}; & \node {secondpicture}; \\
\node {thirdpicture}; & \node {fourthpicture}; \\
% etc.
};
Unfortunately, this gives the error Missing } inserted.
I've never done any plain TeX coding, so I'm not familiar with \bgroup
and \egroup
. Am I using them correctly? If so, why does this error occur? (Interestingly, I do not get an error if I replace \phantom\bgroup\pgfuseimage\bgroup
with \textit\bgroup
and \egroup\egroup
with \egroup
.)
Using a PGF key
In response to an earlier version of this question, @AndrewStacey suggested using a key to pass the picture name to the node, rather than relying on the node text. I've never created PGF keys before, but, if I understand them correctly, then the code would be something like the following. (Please correct me if I am misinterpreting your suggestion, @AndrewStacey.)
\pgfkeyssetvalue{/picture name}{}
\matrix [every node/.append style={execute at begin node=\phantom{\pgfuseimage{\pgfkeysvalueof{/picture name}}}}]
{
\node[/picture name=firstpicture] {}; & \node[/picture name=secondpicture] {}; \\
\node[/picture name=thirdpicture] {}; & \node[/picture name=fourthpicture] {}; \\
% etc.
};
Is this the correct way to create and use a key? If so, this approach is more readable, but doesn't save very many keystrokes.
Using a \foreach construction
I thought about using \foreach
, but I do not see how to combine it with the \matrix
structure that I want.
A minimal working example
For completeness, here is a MWE.
\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\pgfdeclareimage{firstpicture}{pic1.pdf}
\pgfdeclareimage{secondpicture}{pic2.pdf}
\pgfdeclareimage{thirdpicture}{pic3.pdf}
\pgfdeclareimage{fourthpicture}{pic4.pdf}
% etc.
\newcommand{\pgfimageplaceholder}[1]{\phantom{\pgfuseimage{#1}}}
\begin{tikzpicture}[every node/.style={draw=black},
every matrix/.style={draw=red}]
% Here is a working example of what I need to do,
% but it is rather verbose. I would rather not
% have to type \phantom{\pgfuseimage{ each time.
\matrix (part1)
{
\node {\phantom{\pgfuseimage{firstpicture}}}; & \node {\phantom{\pgfuseimage{secondpicture}}}; \\
\node {\phantom{\pgfuseimage{thirdpicture}}}; & \node {\phantom{\pgfuseimage{fourthpicture}}}; \\
% etc.
};
% I could replace \phantom{\pgfuseimage{ with a
% macro, but that doesn't save many keystrokes
% or improve readability much.
\matrix (part2)
[right=of part1]
{
\node {\pgfimageplaceholder{firstpicture}}; & \node {\pgfimageplaceholder{secondpicture}}; \\
\node {\pgfimageplaceholder{thirdpicture}}; & \node {\pgfimageplaceholder{fourthpicture}}; \\
% etc.
};
% I was hoping to be able to somehow use the hooks
% execute at begin/end node to factor out the
% repeated \phantom{\pgfuseimage{.
\matrix (part3)
[right=of part2
% When the following two lines are uncommented,
% the error is ``Missing } inserted.''
% , every node/.append style={execute at begin node=\phantom\bgroup\pgfuseimage\bgroup,
% execute at end node=\egroup\egroup}
]
{
\node {firstpicture}; & \node {secondpicture}; \\
\node {thirdpicture}; & \node {fourthpicture}; \\
% etc.
};
% Andrew Stacey suggested using a key to specify
% the picture, rather than putting it in the node
% text. Here is my attempt at doing that.
\pgfkeyssetvalue{/picture name}{}
\matrix (part4)
[right=of part3,
every node/.append style={%
execute at begin node=\phantom{\pgfuseimage{\pgfkeysvalueof{/picture name}}}}]
{
\node[/picture name=firstpicture] {}; & \node[/picture name=secondpicture] {}; \\
\node[/picture name=thirdpicture] {}; & \node[/picture name=fourthpicture] {}; \\
% etc.
};
\end{tikzpicture}
\end{document}
Best Answer
There's a lot of information buried in the comments so I'm going to try to extract my contributions into some form of answer. My recommended solution is to use
pgfkeys
. The key lengths can be short - single letter if really wanted - so the number of key strokes needed to use them is not really that much more than putting the picture name in the node text. Indeed, if you are going to use names that match some pattern (as in the example), there's no need to specify the picture name at all whereupon it isn't necessary to use any key in the actual node commands. Or you could patch into theunknown
key handler so that an unknown key is taken to the the name of a picture. Thepgfkeys
method is the most robust, I think, and the most flexible. For example, it will work withmatrix of nodes
.Second in my list of solutions would be Jake's solution of defining an entirely new macro. The only downside to this is that it doesn't work transparently with
matrix of nodes
(that is, you can always put the new macro into the cells but you can't take advantage of the automatically inserted nodes).Way, way down at the bottom of my list is a hack that allows you to actually do what you originally asked: use the node text as the argument to a macro. This is a Very Bad Idea for lots of reasons. Firstly, it involves modifying the TikZ node processing commands directly rather than via hooks. Secondly, the opening bracket of the node text is actually removed before TikZ starts its node machinery (this is what TikZ looks for to know to start processing the text and the test is destructive) so we have to put it back again and this means More Hackery. It is not possible to insert stuff in the begin node/end node hooks for two reasons: Firstly, what appears between those two hooks is not just the node text. It is:
followed by the node text. There's even more junk after the node text and before the end hook is called. So if we want to get at the actual node text we need to add something after that
\ignorespaces
and it has to have a genuine opening brace.Here's code illustrating all the above-mentioned solutions.