# TikZ: colors stored in matrix with coordinates inferred

I'd like to use data stored in an external CSV file to fill nodes inside a tikzpicture matrix. If my data is stored as x/y/z, I can write the following loop (put together from this and this):

\documentclass{standalone}
\usepackage{tikz}
\usepackage{xcolor}
\usepackage{catchfile}

\begin{filecontents*}{\jobname.dat}
1/1/20, 1/2/80, 1/3/20,
2/1/80, 2/2/100, 2/3/80,
3/1/20, 3/2/80, 3/3/20
\end{filecontents*}

\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro\k{\c*1} % \c values could be transformed here
\fill[color=red!\k] (\x,\y) rectangle +(1,1);
}
\end{tikzpicture}
\end{document}


My data, instead, is stored as a matrix of z values (color intensities), e.g.

\begin{filecontents*}{\jobname.csv}
20, 80, 20
80, 100, 80
20, 80, 20
\end{filecontents*}


Please help me adapt the code so that I can read the colors from the file and that the x and y coordinates are inferred from the cell position inside the matrix.

The tikzpicture looks like this:

• Do you want to read the actual color from your dat file (red!20), or do you prefer it as you have it? Also not all these data needed in dat file.... just the color could be enough. – koleygr Sep 14 '18 at 8:48
• Ok... but it could be a matrix of integers with just the color value like z_i but without 1/1/z_1 1/2/z_2 etc... Would this be accepted or you prefer your own dat file format? – koleygr Sep 14 '18 at 8:53
• When I posted my question, I expected that the answer would be straightforward, but as the answers of koleygr and marmot show, it involves quite a bit of trickery! On second thoughts, I could have edited my CSV file to put it in the x/y/z format and use the code that I present in the OP. In R, this is one way to do it: If m is my matrix of color intensities, then matrix(mapply(function(x, i, j) paste0(i,"/",j,"/",x), m, row(m), col(m)), nrow = nrow(m)) returns the matrix in the x/y/z format. But I'm glad to be learning how to do this stuff in LaTeX! – PatrickT Sep 14 '18 at 16:13
• If the loaded data is quoted, e.g. "1/2/100", then sticking \catcode"=9 at the start of the tikzpicture will remove the quote marks (there may be undesirable side effects to this bulldozer approach, but it worked in this example). – PatrickT Sep 14 '18 at 16:56

First version: The size of the data matrix is known and hard-coded (here a 3 x 3 matrix):

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\usepackage{catchfile}
\usepackage{filecontents}

\begin{filecontents*}{\jobname.csv}
2, 8, 2,
8, 10, 8,
2, 8, 2
\end{filecontents*}

\begin{document}
\def\MySpaceLength{3}
\begin{tikzpicture}
\foreach \k[count=\i from 0] in \loadeddata{
\pgfmathsetmacro\myx{-3*int(\i/3)+\i}
\pgfmathsetmacro\myy{int(\i/3)}
\fill[color=red!\k] ({\MySpaceLength*\myx},-{\MySpaceLength*\myy}) rectangle+ ($(\MySpaceLength,\MySpaceLength)$);
}
\end{tikzpicture}
\end{document}


Second version: the size of the matrix is known and set by the user, but not hard-coded. It is stored in the variables \XMatrixDimension and \YMatrixDimension:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\usepackage{catchfile}
\usepackage{filecontents}

\begin{filecontents*}{\jobname.csv}
2, 8, 2, 5,
8, 10, 8, 90,
2, 8, 2,60,
20, 2 , 56, 40,
30, 20, 50, 70
\end{filecontents*}

\begin{document}
\def\MySpaceLength{3}
\def\XMatrixDimension{4}
\def\YMatrixDimension{5}
\begin{tikzpicture}
\foreach \k[count=\i from 0] in \loadeddata{
\pgfmathsetmacro\myx{-\XMatrixDimension*int(\i/\XMatrixDimension)+\i}
\pgfmathsetmacro\myy{int(\i/\XMatrixDimension)}
\fill[color=red!\k] ({\MySpaceLength*\myx},-{\MySpaceLength*\myy}) rectangle+ ($(\MySpaceLength,\MySpaceLength)$);
}
\end{tikzpicture}
\end{document}


Output:

• Thanks for your answer koleygr. I think I understand the steps. I'll play around with this a little and get back to you if I get stumped. Perhaps I should have considered making a CSV of my data (obtained with R) in the 1/2/3 format. Might have been easier. That said, it's good to learn how to do this with LaTeX! Thanks. – PatrickT Sep 14 '18 at 12:33
• For your second version, I think that \pgfplotstablegetelem can be used to calculate the dimension of the matrix, such that it would not have to be set by the user at all, something similar to what marmot does in their answer and/or similar to this answer: tex.stackexchange.com/questions/343770/… – PatrickT Sep 14 '18 at 16:10
• @PatrickT, Nice addition and very nice edit. But instead of using a huge package (pgfplots) just to avoid one or two copy pastes is not recommended. If you want to use this functionality many times and you dont want just to copy paste the matrix and change any // with comma, then the way is what you already mentioned. So, the comment is useful – koleygr Sep 14 '18 at 16:24
• indeed good point about not loading a package that is not absolutely needed. My purpose has been served, so I thank you and shall accept your answer, as it came before marmot's, whose answer relies on the pgfplots package and is also very commendable! :-) – PatrickT Sep 14 '18 at 16:35
• Thanks. marmot has my vote now because I just learned some pgf – koleygr Sep 14 '18 at 16:40

Here is a solution based on matrix plot that comes with pgfplots. It is taken from this answer, whose second part has some similarity with koleygr's answer. The advantage of the pgfplots solution is that you can use color maps for that. Of course, you can drop the colorbar.

\documentclass[border=3.14mm,tikz]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{pgfplots.colormaps}
\pgfplotsset{compat=1.16}
\usepackage{pgfplotstable}
\usepackage{filecontents}

\begin{filecontents*}{\jobname.csv}
2, 8, 2
8, 10, 8
2, 8, 2
\end{filecontents*}
\pgfplotstablegetelem{#2}{[index]#3}\of{#1}%
\let#4\pgfplotsretval
}
\begin{document}
\pgfplotstablegetrowsof{\datatable}
\pgfmathtruncatemacro{\numrows}{\pgfplotsretval}
\pgfplotstablegetcolsof{\datatable}
\pgfmathtruncatemacro{\numcols}{\pgfplotsretval}
\xdef\LstX{}
\xdef\LstY{}
\xdef\LstC{}
\foreach \Y [evaluate=\Y as \PrevY using {int(\Y-1)},count=\nY] in {1,...,\numrows}
{\pgfmathtruncatemacro{\newY}{\numrows-\Y}
\foreach \X  [evaluate=\X as \PrevX using {int(\X-1)},count=\nX] in {1,...,\numcols}
{
\pgfmathtruncatemacro{\nZ}{\nX+\nY}
\ifnum\nZ=2
\xdef\LstX{\PrevX}
\xdef\LstY{\PrevY}
\xdef\LstC{\Current}
\else
\xdef\LstX{\LstX,\PrevX}
\xdef\LstY{\LstY,\PrevY}
\xdef\LstC{\LstC,\Current}
\fi
}
}
\edef\temp{\noexpand\pgfplotstableset{
create on use/x/.style={create col/set list={\LstX}},
create on use/y/.style={create col/set list={\LstY}},
create on use/color/.style={create col/set list={\LstC}},}}
\temp
\pgfmathtruncatemacro{\strangenum}{\numrows*\numcols}
\pgfplotstablenew[columns={x,y,color}]{\strangenum}\strangetable

%\pgfplotstabletypeset[empty cells with={---}]\strangetable
\begin{tikzpicture}
\pgfplotsset{%
colormap={WhiteRedBlack}{%
rgb255=(255,255,255)
rgb255=(255,0,0)
rgb255=(0,0,0)
},
}
\begin{axis}[%
small,
every tick label/.append style={font=\tiny},
tick align=outside,
minor tick num=5,
%
xlabel=$\beta$,
xticklabel pos=right,
xlabel near ticks,
xmin=-1, xmax=\numcols,
xtick={0, 5, ..., 4},
%
ylabel=$\alpha$,
ylabel style={rotate=-90},
ymin=-1, ymax=\numrows,
ytick={0, 5, ..., 4},
%
point meta min=0,
point meta max=32,
point meta=explicit,
%
%colorbar sampled,
colorbar as palette,
colorbar style={samples=3},
colormap name=WhiteRedBlack,
scale mode=scale uniformly,
]
\draw (axis description cs:0,0) -- (axis description cs:1,0);

• Yours is an excellent answer and I have learned (and am still learning) quite a lot about the pgfplots` package. I like how all the computations are automated. It was a difficult decision, but I selected koleygr's answer as it came first and is a little simpler (though not quite as general as yours). Thanks again! – PatrickT Sep 14 '18 at 16:38