Dynamically filling a grid with TikZ from a data array
The macro \BITARRAY
has already almost the form, how it can be easily used by TikZ's \foreach
. The additional surrounding braces are not needed and there should not be a space after the last element.
First the cells with values 1 are filled. During the loop, the values of \x
and \y
are stored in global variables to have the maximum values after the loops. \foreach
works inside a group, thus the meaning of \x
and \y
are lost afterwards.
Then the grid is drawn. Since the rows are drawn from the top, negative values are used for the y coordinate.
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\BITARRAY{
{1,0,0,1},
{1,0,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,1}%
}
\fill[orange]
\foreach \row [count=\y] in \BITARRAY {
\foreach \cell [count=\x] in \row {
\ifnum\cell=1 %
(\x-1, -\y+1) rectangle ++(1, -1)
\fi
\pgfextra{%
\global\let\maxx\x
\global\let\maxy\y
}%
}
}
;
\draw[thin] (0, 0) grid[step=1] (\maxx, -\maxy);
\end{tikzpicture}
\end{document}
You can't say
\ifthenelse{\value{1}<1}{...
because 1
is not a counter and \value{}
takes the name of a counter as its argument. This is why you get strange errors complaining about not being about to use \else
after \the
. The value of the counter mycounter
is typeset using \themycounter
so \value{1}
tries something like \the1
which doesn't make sense.
If you replace the 1
with the name of a counter, it will work. For example,
\ifthenelse{\value{page}<1}{%
works because page
is a counter. Obviously it isn't a very interesting counter for this purpose as the condition with either be satisfied for every case or fail for every case, since the page number won't vary within the picture.
Note that, since you are using TikZ anyway, it would probably be easier to use TikZ's facilities for maths. However, I wanted to demonstrate how to minimally modify the code, so I've tried to change it as little as possible for the most part.
\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{fp}
\usepackage{ifthen}
\begin{document}
\newcommand\bitfieldwidth{4}
\newcommand\numberofrounds{5}
\makeatletter
%divide the column width by the bitfield width to figure out how many boxes we need
\FPeval{\blockwidth}{((\strip@pt\columnwidth) / \bitfieldwidth)}
%truncate the decimals
\FPtrunc\blockwidth{\blockwidth}{0}
%get a whole number, but then truncate it anyway
\FPmul\gridwidth{\bitfieldwidth}{\blockwidth}
\FPtrunc\gridwidth{\gridwidth}{0}
\FPmul\gridheight{\numberofrounds}{\blockwidth}
\FPtrunc\gridheight{\gridheight}{0}
\makeatother
% this creates a box at the appropriate location
% It just uses the index and not a location, so it can scale with
% the type of grid width
\newcommand{\gridbox}[2]{%you pass the x,y of the lower location.
\fill [orange] (#1*\blockwidth pt, -#2*\blockwidth pt) rectangle ++(-\blockwidth pt,\blockwidth pt)}
\def\BITARRAY{{%
{1,0,0,1},
{1,0,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,1}%
}}
\begin{tikzpicture}
\draw[step=\blockwidth pt,gray,very thin] (0pt,0pt) grid (\gridwidth pt,-\gridheight pt);
\foreach \y in {1,...,\numberofrounds}{%the y is going down the array, the x is left to right
\foreach \x in {1,...,\bitfieldwidth}{%
\pgfmathtruncatemacro{\resultbit}{int(\BITARRAY[\y-1][\x-1])}
\ifthenelse{\resultbit<1}{%
\gridbox{\x}{\y};
}{};
}
}
\gridbox{1}{2};
\end{tikzpicture}
\end{document}
A TeX-y solution (built on Heiko's) using \csname
, since your data contains only two different values :
\documentclass{article}
\usepackage{tikz}
\begin{document}
\expandafter\def\csname box0\endcsname#1#2{}
\expandafter\def\csname box1\endcsname#1#2{\fill[orange] (#1-1, -#2+1) rectangle ++(1, -1);}
\begin{tikzpicture}
\def\BITARRAY{
{1,0,0,1},
{1,0,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,0,1}%
}
\foreach \row [count=\y] in \BITARRAY {
\foreach \cell [count=\x] in \row {
\csname box\cell\endcsname{\x}{\y}
\pgfextra{%
\global\let\maxx\x
\global\let\maxy\y
}%
}
}
\draw[thin] (0, 0) grid[step=1] (\maxx, -\maxy);
\end{tikzpicture}
\end{document}