Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

Thank you in advance!

Example matrix:

10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111
share|improve this question

5 Answers 5

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}
% read the file
\pgfplotstableread{matrix.cvs}{\matrixfile}

\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:

enter image description here

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={
        every head row/.style={output empty row},
        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}
% read the file
\pgfplotstableread{matrix.cvs}{\matrixfile}

\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:

enter image description here

share|improve this answer
    
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 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 at 6:46
    
Yes, I tried to tinker with this code, but It interprets only whole numbers not the single digits. –  user15941 Jul 7 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:

Result

share|improve this answer

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 
      data = f:read("*all")
      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

enter image description here

share|improve this answer
2  
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*}
%================================

%Replace your file name 
\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}

enter image description here

share|improve this answer
    
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 at 6:46
    
@user15941 If you add nodes in empty cells key to the matrix, phantom cells can be created. –  percusse Jul 7 at 7:10

run with xelatex

\documentclass{article}
\usepackage{filecontents}
\usepackage{pstricks-add}

\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}

enter image description here

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.