# Drawing a large binary matrix as colored grid in TikZ

I have a pretty big binary matrix of maybe 70 rows and 64 columns. For ease of viewing, I would like to draw this matrix in TikZ where e.g. a 1 is represtented by a red square and a 0 is a white square. Does anyone have any idea how I could obtain this?

Ideally, I would have something where I can just load the matrix from a file and TikZ would handle everything else. Otherwise, I am also happy with a solution having to do find/replace every 0 by some string, and replace every 1 by another string.

Example matrix:

10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111

-

The answer provides two solutions: by means of the first one it is possible to customize the dimension of the squares and perhaps suits better your needs. Both are based on answers given here.

Solution n.1 is based on Create square and custom size cells in a table using pgfplotstable:

\documentclass{article}
\usepackage{filecontents}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.8}

\begin{filecontents}{matrix.cvs}
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
\end{filecontents}

\makeatletter
\tikzset{
zero color/.initial=white,
zero color/.get=\zerocol,
zero color/.store in=\zerocol,
one color/.initial=red,
one color/.get=\onecol,
one color/.store in=\onecol,
cell wd/.initial=1ex,
cell wd/.get=\cellwd,
cell wd/.store in=\cellwd,
cell ht/.initial=1ex,
cell ht/.get=\cellht,
cell ht/.store in=\cellht,
}

\newcommand{\drawgrid}[2][]{
\medskip
\begin{tikzpicture}[#1]
\pgfplotstableforeachcolumn#2\as\col{
\pgfplotstableforeachcolumnelement{\col}\of#2\as\colcnt{%
\ifnum\colcnt=0
\fill[\zerocol]($-\pgfplotstablerow*(0,\cellht) + \col*(\cellwd,0)$) rectangle+(\cellwd,\cellht);
\fi
\ifnum\colcnt=1
\fill[\onecol]($-\pgfplotstablerow*(0,\cellht) + \col*(\cellwd,0)$) rectangle+(\cellwd,\cellht);
\fi
}
}
\end{tikzpicture}
\medskip
}
\makeatother

\begin{document}

\drawgrid{\matrixfile}

\drawgrid[zero color=green, one color=cyan]{\matrixfile}

\drawgrid[zero color=orange,
one color=violet,
cell ht=2em,
cell wd=2em]{\matrixfile}
\end{document}


The result:

Solution n.2 is based on Parametrize shading in table through TikZ:

\documentclass{article}
\usepackage{filecontents}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.8}

\begin{filecontents}{matrix.cvs}
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
\end{filecontents}

\makeatletter
\pgfplotstableset{
zero color/.initial=white,
zero color/.get=\zerocol,
zero color/.store in=\zerocol,
one color/.initial=red,
one color/.get=\onecol,
one color/.store in=\onecol,
color cells/.style={
string type,
postproc cell content/.code={%
\pgfkeysalso{@cell content=\rule{0cm}{2.4ex}\cellcolor{\zerocol}
\pgfmathtruncatemacro\number{##1}
\ifnum\number>0\cellcolor{\onecol}\fi}%
},
columns/x/.style={
column name={},
postproc cell content/.code={}
}
}
}
\makeatother

\begin{document}

\begin{table}
\centering
\pgfplotstabletypeset[color cells]\matrixfile
\end{table}

\begin{table}
\centering
\pgfplotstabletypeset[color cells, zero color=green, one color=cyan]\matrixfile
\end{table}
\end{document}


The result:

-
Is it possible to remove the lines between the cells? – Tom Dec 19 '13 at 22:24
@Tom: I think they depend on the viewer; did you try to increase the resolution? If the problem persist, likely we can remove them taking into account the \pgflinewidth. – Claudio Fiandrino Dec 20 '13 at 7:59
Your solution requires, that the digits are separated by space. Can yoiu adjust the code to visualize the original matrix? – user15941 Jul 7 '14 at 6:43
@user15941: you're right. Do you mean you would like to remove the spaces? They are used as delimiter, so it's not easy to get rid of them. You may want to use another delimiter, but still it does not answer your question. – Claudio Fiandrino Jul 7 '14 at 6:46
Yes, I tried to tinker with this code, but It interprets only whole numbers not the single digits. – user15941 Jul 7 '14 at 6:50

Just for fun and for comparison, I implemented a lualatex solution.

In this solution I use lua to transform the matrix from its textual form as a sequence of 0 and 1 into another string containing a lot of tikz commands which draw the figure.

The lua based solution seems to be slower than the pure tikz solutions, but perhaps this is due to the lualatex startup. The execution of the lua functions is very fast, but the compilation of the resulting tikz code is apparently the bottleneck. Probably my lua code could generate a more efficient tikz code.

To compile my example you'll require:

• A working lualatex
• A copy of the file matrix2tikz.lua (below)
• The document sample.tex (below)

## sample.tex

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit}
\directlua{dofile("matrix2tikz.lua")}
\newcommand{\bitmapmatrix}[2][10]{%
\begin{scope}[bitmapmatrix]
\directlua{matrix2tikz("#2",#1)}%
\end{scope}
}
\tikzset{
bitmapmatrix/.style = {line width = 2sp},
pixel on/.style = {red},
pixel off/.style = {white},
pixel err/.style = {pink}
}

\def\mydata{
10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111
}

\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[node distance=2mm]
\bitmapmatrix[5]{\mydata}
\node[below=of matrix] {This is a test};
\end{tikzpicture}
\end{document}


## matrix2tikz.lua

local function matrix_to_tikz(tab , size)
local width = size
if (size == nil) then size=10 end
local pixel_width = size / #tab[1]
local height = pixel_width * #tab
local pixel_cmd = string.format("\\filldraw[%%s] (%%f, %%f) +(-%f, %f)         → rectangle +(%f, -%f);",
pixel_width/2, pixel_width/2, pixel_width/2, pixel_width/2)
local str_tab = {}

for y=1,#tab do
row = {}
for x=1,#tab[y] do
if tab[y][x] == 1 then
style = "pixel on"
elseif tab[y][x] == 0 then
style = "pixel off"
else
style = "pixel err"
end
row[x] = string.format(pixel_cmd, style, x*pixel_width, -y*pixel_width)
end
str_tab[y] = table.concat(row, "\n")
end
local extra = {}
extra[1] = string.format("\\coordinate (aux1) at (%f,-%f);", pixel_width/2,    → height+pixel_width/2)
extra[2] = string.format("\\coordinate (aux2) at (%f, %f);", width+            → pixel_width/2, -pixel_width/2)
extra[3] = "\\node[inner sep=0pt, fit=(aux1) (aux2)] (matrix) {};"
str_tab[#tab+1] =  table.concat(extra, "\n")
return table.concat(str_tab,"\n")
end

function justWords(str)
local t = {}
local function helper(word) table.insert(t, word) return "" end
if not str:gsub("%w+", helper):find"%S" then return t end
end

local function text_to_matrix(txt)
local m = {}
local l = justWords(txt)
for i=1,#l do
if (l[i]~= nil and #l[i]>1) then
j = 1; row = {}
for c in l[i]:gmatch(".") do
row[j] = tonumber(c)
j = j + 1
end
m[i] = row
end
end
return m
end

function matrix2tikz(data, size)
local t = text_to_matrix(data)
local s = matrix_to_tikz(t, size)
tex.print(s)
end


## Compiling

Put both in the same folder and run lualatex sample.tex. This is the result:

-

run with xelatex

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{matrix.data}
/dotmatrix [
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
] def
\end{filecontents*}

\begin{document}

\begin{pspicture}(-0.5,-0.75)(7,11)
\psframe*[linecolor=blue!60](0.5,0.5)(11.5,7.5)
\psMatrixPlot[dotsize=1.1cm,dotstyle=square*,linecolor=red!60]{7}{11}{matrix.data}
\end{pspicture}

\end{document}


-

For comparison, here is a solution that uses ConTeXt (MkIV) and Metapost that loads data from an external file.

\startluacode
local draw = function (x,y, size, color)
context("fill fullsquare xyscaled (%s, %s) shifted (%d*%s, -%d*%s) withcolor \\MPcolor{%s}; ",
size, size, x, size, y, size, color)
end

function commands.visualize_data(filename, zero_color, one_color, size)
size = size or "5mm" -- default

local data = ""
local f = io.open(filename,'r')

if not f then
print("Error:", "Cannot load file " .. filename)
else
f:close()

local lines = string.splitlines(data)
context.startMPcode()

for i = 1, #lines do
local current_line = lines[i]
for j = 1, #current_line do
local current_character = current_line:sub(j,j)
local color
if current_character == "0" then
color = zero_color
else
color = one_color
end
draw(j, i, size, color)
end
end

context.stopMPcode()
end
end
\stopluacode

\starttext

\ctxcommand{visualize_data("data.txt", "red", "blue")}

\stoptext


which gives

-
Bah, showing off.... :P – percusse Jul 12 '13 at 18:39

Just for the fun of it, directly from the provided data. Probably L3 version is on the way :)

\documentclass{standalone}
\usepackage{tikz,xstring,etoolbox,catchfile}
\usetikzlibrary{matrix}

%=== Remove these later, it creates a dummy data file
\usepackage{filecontents}
\begin{filecontents*}{testdata.txt}
101101010101011010101010110101010
100101010101001010101010010101010
010101110100101011101001010111010
111100101001111001010011110010100
011000110010110001100101100011001
111010101111110101011111101010111
101010101111010101011110101010111
101101010101011010101010110101010
100101010101001010101010010101010
010101110100101011101001010111010
111100101001111001010011110010100
011000110010110001100101100011001
111010101111110101011111101010111
101010101111010101011110101010111
\end{filecontents*}
%================================

\CatchFileDef{\mydata}{testdata.txt}{}

\def\doit#1{%
\let\mymatrixcontent\empty%
\StrCount{#1}{ }[\myrownumber]%
\xdef\mormatrix{#1}%
\foreach \m in {1,...,\myrownumber}{%
\StrCut{\mormatrix}{ }\myextractedrow\myremainingmatrix%
\xdef\mormatrix{\myremainingmatrix}%
\StrLen{\myextractedrow}[\mycolnum]%
\foreach \k in {1,...,\mycolnum}{%
\StrChar{\myextractedrow}{\k}[\kk]%
\begingroup\edef\x{\endgroup%
\noexpand\gappto\noexpand\mymatrixcontent{\ifnum\kk>0|[fill=red]|\fi\noexpand\&}}\x%
}\gappto\mymatrixcontent{\\}}%
\begin{tikzpicture}
\matrix[matrix of nodes,ampersand replacement=\&,inner sep=0pt,
nodes={minimum size=4mm,outer sep=0pt}] {\mymatrixcontent};
\end{tikzpicture}%
\let\mymatrixcontent=\empty
}

\begin{document}
\doit{\mydata}
\end{document}


-
I used this example, however when any of the border columns or rows contains only 0 values, it disappears. In latex file matrices of the same dimensions are not of equal size. Maybe we can output some phantom squares. – user15941 Jul 7 '14 at 6:46
@user15941 If you add nodes in empty cells key to the matrix, phantom cells can be created. – percusse Jul 7 '14 at 7:10