# Populating a tikz matrix with complex content

I am trying to populate a tikz matrix dynamically using foreach to loop over a list-argument and breaking it further apart using xstring operations.

I am hitting an issue where, as far as I can tell, the temporary macro produced by \StrBefore gets lost / is unreadable further down the macro chain.

The compiler tells me that the file icons/.png could not be found - which boils down to the macro expansion not working as far as I understand it (and LaTeX terminology):

LaTeX Warning: File icons/.png' not found on input line 63.

! Unable to load picture or PDF file 'icons/.png'.
}
l.63 ...{(0,0)}{Fish}{1}{Farmers:800,Workers:1200}


Further I get an actual error telling me about an undefined control sequence. This is the temporary macro generated by \StrBefore:

! Undefined control sequence.

l.63 ...{(0,0)}{Fish}{1}{Farmers:800,Workers:1200}


Here's a MWE:

\documentclass{article}

\usepackage{calc}
\usepackage{geometry}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{xstring}

% PAGE GEOMETRY
\geometry{a4paper,
landscape,
top=1cm,
bottom=1cm,
left=1cm,
right=1cm,
includefoot}
\usetikzlibrary{calc, matrix}
% END PAGE GEOMETRY

% META

% sizes
\newcommand{\unitsize}{1cm}

% #1 > (x,y)
% #2 > Object_Name (filename without .png)
% #3 Amount
% #4 > Comma Separated list: <stratum>:<amount>,<stratum>:<amount>, ...
% >{\SplitList{,}}
\NewDocumentCommand{\consnode}{m m m m}{
\node (#2) at #1 {
\let\matrixcontents\empty
\foreach \c in {#4}{
\StrBefore{\c}{:}[\templeft]
\StrBehind{\c}{:}[\tempright]

\expandafter\gappto\expandafter\matrixcontents{\expandafter\consimg{\expandafter\templeft} \&}
\expandafter\gappto\expandafter\matrixcontents\expandafter{\tempright \\}
}

\begin{tikzpicture}
\node[label={[label distance=-(0.35*\unitsize)]105:#3×}] at (0,0) {
\includegraphics[width=\unitsize, height=\unitsize]{icons/#2}};
\matrix[row sep=-2mm, matrix of nodes, ampersand replacement=\&] (output) at (0,-1) {
\matrixcontents
%\includegraphics[width=\unitsize/2, height=\unitsize/2]{icons/example-image-b.png} \& 800 \\
%\includegraphics[width=\unitsize/2, height=\unitsize/2]{icons/example-image-c.png} \& 1200 \\
};
\end{tikzpicture}};
}

\newcommand{\consimg}[1]{
\includegraphics[width=\unitsize/2, height=\unitsize/2]{icons/#1.png}
}

% END META

\begin{document}

\begin{tikzpicture}
\consnode{(0,0)}{example-image-a}{1}{example-image-b:800,example-image-c:1200}
\end{tikzpicture}

\end{document}


(The commented out parts in the matrix definition produce the desired output, see also the img below, and are what I am trying to replace
!Please note that I replaced the image-names with example names as recommended in comments, the image names in my command serve double-duty as the identifier-names for tikz nodes)

This is the desired result I want to achieve (which I've achieved by hardcoding the matrix):

I am using Overleaf (compiling with XeLaTeX) and would prefer to keep working with it.

I've cobbled the code together with help from various documentations, but in this case mainly the following two questions:

Tikz foreach inside matrix

Foreach loop with command inside Tikz matrix

• Welcome to TeX-SE! Please consider making your example more accessible to everyone. Most of us do not have, say, a graphics Farmers in their TeX path. So please replace these by something like example-image-a. – marmot Apr 20 at 15:50
• Is the file extension the same as you wrote it on the MWE? – manooooh Apr 20 at 15:51
• @marmot thanks for the tip, is there any list of generally accepted sample images? – dot_Sp0T Apr 20 at 16:14
• Most users will have example-image, example-image-duck, example-image-a, example-image-b and example-image-c in their TeX path. – marmot Apr 20 at 16:15
• @marmot I'll go with the boring ones for extra safety.. – dot_Sp0T Apr 20 at 16:18

as posted the first error is

! LaTeX Error: File icons/example-image-a' not found.


I deleted icons/

You then get

! Undefined control sequence.


because you are just defining that token locally but then adding it outside the group.

   \expandafter\gappto\expandafter\matrixcontents\expandafter{\tempright \\}


adds the expansion of \tempright followed by \\to \matrixcontents

but

 \expandafter\gappto\expandafter\matrixcontents{\expandafter
\consimg{\expandafter\templeft} \&}


The first two \expandafter apply expansion to { which is a non expandable token so it is the same as

       \gappto\matrixcontents{\expandafter\consimg{\expandafter\templeft} \&}


so adds \expandafter\consimg{\expandafter\templeft} \& to \matrixcontents but (a) \templeft will not be defined by then and (b) when this is used, the first \expandafter again applies to { so does nothing.

You want to expand \templeft as in the \tempright case, so:

        \expandafter\gappto\expandafter\matrixcontents\expandafter
{\expandafter\consimg\expandafter{\templeft} \&}


This seems vastly over-complicated to just set three images with three labels, it isn't clear why you need xstring or tikz at all but perhaps your real document uses these features and it is just an artefact of the small example.

\documentclass{article}

\usepackage{calc}
\usepackage{geometry}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{xstring}

% PAGE GEOMETRY
\geometry{a4paper,
landscape,
top=1cm,
bottom=1cm,
left=1cm,
right=1cm,
includefoot}
\usetikzlibrary{calc, matrix}
% END PAGE GEOMETRY

% META

% sizes
\newcommand{\unitsize}{1cm}

% #1 > (x,y)
% #2 > Object_Name (filename without .png)
% #3 Amount
% #4 > Comma Separated list: <stratum>:<amount>,<stratum>:<amount>, ...
% >{\SplitList{,}}
\NewDocumentCommand{\consnode}{m m m m}{
\node (#2) at #1 {
\let\matrixcontents\empty
\foreach \c in {#4}{
\StrBefore{\c}{:}[\templeft]
\StrBehind{\c}{:}[\tempright]

\expandafter\gappto\expandafter\matrixcontents\expandafter
{\expandafter\consimg\expandafter{\templeft} \&}
\expandafter\gappto\expandafter\matrixcontents\expandafter{\tempright \\}
}

\begin{tikzpicture}
\node[label={[label distance=-(0.35*\unitsize)]105:#3×}] at (0,0) {
\includegraphics[width=\unitsize, height=\unitsize]{#2}};
\matrix[row sep=-2mm, matrix of nodes, ampersand replacement=\&] (output) at (0,-1) {
\matrixcontents
%\includegraphics[width=\unitsize/2, height=\unitsize/2]{icons/example-image-b.png} \& 800 \\
%\includegraphics[width=\unitsize/2, height=\unitsize/2]{icons/example-image-c.png} \& 1200 \\
};
\end{tikzpicture}};
}

\newcommand{\consimg}[1]{%
\includegraphics[width=\unitsize/2, height=\unitsize/2]{#1}%
}

% END META

\begin{document}

\begin{tikzpicture}
\consnode{(0,0)}{example-image-a}{1}{example-image-b:800,example-image-c:1200}
\end{tikzpicture}

\end{document}