7

I have a 50x300 binary marix, which I want to display as a colored grid. I tried the approaches of drawing a large binary matrix as colored grid which I like, but

  • the approach using pgfplots table is too large, resizebox results in an out of memory error and I couldn't find an appropriate solution to adjust the cell size of the table in pgfplotsset. setting the fontsize as tinz as possible did not suffice, and
  • the tikz-matrix approach results in a compile timeout.

I have really no idea what to do now.. Increasing the memory assignment seems too hacky for me, isn't there a more elegant option? I also would like to stick to the pgfplots approach..

7
  • 1
    Using the solution in the top answer of the linked question, I can draw a 50x300 matrix with \drawgrid[one color=black,zero color=white,cell wd=2pt,cell ht=2pt]{\matrixfile}; however, it takes quite some time and a lot of space, of course. The thing is, that you can not have a huge chunk of data and think it will not take up space ;-) What are you trying to do exactly? Commented Sep 1, 2015 at 14:13
  • Hm, I get a "TeX capacity exceeded, sorry [main memory size=5000000]." error.. I'd like to produce a picture of my data like the picture on the first page of this paper: (epubs.siam.org/doi/pdf/10.1137/1.9781611972801.15)
    – Sibylse
    Commented Sep 1, 2015 at 14:20
  • What format is desired/required for the matrix input? Commented Sep 1, 2015 at 14:33
  • To me, this looks more like a plot that like a drawing. Commented Sep 1, 2015 at 15:00
  • Format doesn't matter, could convert to anything. Right now I have a csv with zeros and ones. A plot that looks like a colored binary matrix would also be fine, as long its looking good ;)
    – Sibylse
    Commented Sep 1, 2015 at 15:21

4 Answers 4

4

If you want efficiency, primitive is generally better. Note, the Op for this question specified tikz in the solution.

\documentclass{standalone}
\usepackage{xcolor}

\newlength{\cellwidth}
\newlength{\cellheight}
\let\END=\eof

\newcommand{\colormatrix}[1]% #1 = binary matrix
{\parbox{\CMcolumns\cellwidth}{%
  \baselineskip=\cellheight
  \lineskip=0pt
  \def\one{1}%
  \def\zero{0}%
  \bgroup
    \countdef\col=1
    \col=0
    \CMParse#1\END
  \egroup
}}

\def\CMParse#1{\ifx#1\END\else
  \if#1\one\relax{\color{\onecolor}\rule{\cellwidth}{\cellheight}}\fi
  \if#1\zero\relax{\color{\zerocolor}\rule{\cellwidth}{\cellheight}}\fi
  \advance\col by 1
  \ifnum\col<\CMcolumns\relax\else
    \hfil
    \col=0
  \fi
\expandafter\CMParse\fi}% expand \fi first

\newcommand{\setcolormatrix}[6]% #1=width, #2=height, #3=number columns, #4=number rows, #5=one color, #6=zero color
{\global\cellwidth=\dimexpr #1/#3\relax
 \global\cellheight=\dimexpr #2/#4\relax
 \global\def\CMcolumns{#3}%
 \global\def\onecolor{#5}%
 \global\def\zerocolor{#6}%
}

\begin{document}
\setcolormatrix{1in}{1in}{11}{7}{blue}{yellow}%
\colormatrix{%
10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111}

\end{document}

binary matrix


The file image.tex (created by the editor) consists of

10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111

and the updated solution is given by

\documentclass{standalone}
\usepackage{xcolor}

\newlength{\cellwidth}
\newlength{\cellheight}
\newread\imagefile
\let\END=\eof

\newcommand{\colormatrix}[1]% #1 = filename
{\parbox{\CMcolumns\cellwidth}{%
  \baselineskip=\cellheight
  \lineskip=0pt
  \def\one{1}%
  \def\zero{0}%
  \def\empty{\par}%
  \openin\imagefile=#1
  \loop\ifeof\imagefile\else
    \read\imagefile to \buffer%
    \ifx\buffer\empty\relax\else
      \expandafter\CMParse\buffer\END
      \hfil
    \fi
  \repeat
  \closein\imagefile
}}

\long\def\CMParse#1{\ifx#1\END\else
  \if#1\one\relax{\color{\onecolor}\rule{\cellwidth}{\cellheight}}\fi
  \if#1\zero\relax{\color{\zerocolor}\rule{\cellwidth}{\cellheight}}\fi
\expandafter\CMParse\fi}% expand \fi first

\newcommand{\setcolormatrix}[6]% #1=width, #2=height, #3=number columns, #4=number rows, #5=one color, #6=zero color
{\global\cellwidth=\dimexpr #1/#3\relax
 \global\cellheight=\dimexpr #2/#4\relax
 \global\def\CMcolumns{#3}%
 \global\def\onecolor{#5}%
 \global\def\zerocolor{#6}%
}

\begin{document}
\setcolormatrix{1in}{1in}{11}{7}{blue}{yellow}%
\colormatrix{image}

\end{document}
2
  • Looks promising! Unfortunately, I'm too stupid to make this work when the matrix is stored in another file. Tried filecontents and a new command.. nothing worked. Could you please tell me how to integrate this properly?
    – Sibylse
    Commented Sep 2, 2015 at 9:37
  • A revised solution using file I/O has been added. Commented Sep 2, 2015 at 15:43
6

This is MWE using Asymptote:

enter image description here

The sample 30x500 file was generated with

// 
// "gendata.asy" :
//
int m=30, n=500;
file fout=output("binmatrix.txt");
srand(1717177);
string s;
for(int i=0;i<m;++i){
  s="";
  for(int j=0;j<n;++j){
    s+=string(round(unitrand()));
  }
  write(fout,s+'\n');
}
flush(fout);
close(fout);

And the Asymptote code for the image is

//
// "m1.asy" :
// 
settings.tex="pdflatex";
file fin=input("binmatrix.txt"); 

string[] s=fin;

int m=s.length, n=length(s[1]);

real h=1cm;
real w=h/m*n;
size(w,h);

import graph;
import palette;
real[][] v=new real[n][m];
for(int i=0; i < m; ++i){
  for(int j=0; j < n; ++j){
    v[j][i]=(real)substr(s[i],j,1);
  }
}
pen[] Palette=new pen[]{deepblue,orange};
bounds range=image(v,(0,0),(n,m),Palette);

You can also combine bits into colors, for example, like this:

settings.tex="pdflatex";
file fin=input("binmatrix.txt"); 

string[] s=fin;

int m=s.length, n=length(s[1]);

real h=1cm;
real w=h/m*n/3;
size(w,h);

import graph;
import palette;
pen[][] v=new pen[(int)(n/3)][m];
for(int i=0; i < m; ++i){
  for(int j=0; j < (int)(n/3); ++j){
    v[j][i]=rgb((real)substr(s[i],3*j,1),(real)substr(s[i],3*j+1,1),(real)substr(s[i],3*j+2,1));;
  }
}
image(v,(0,0),(n/3,m)); 

enter image description here

2
  • I like this one. Is it LaTeX though? I though Asymptote was a whole other thing.
    – voices
    Commented Aug 4, 2019 at 21:33
  • @tjt263: Asymptote is part of TeXLive distribution ans is deeply integrated with LaTeX.
    – g.kov
    Commented Aug 5, 2019 at 2:06
1

You might consider using imagemagick for this. For example, you could format your data in a plain PGM format.

File "sample.pgm"

P2
8 8
1
0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 0
0 1 0 0 0 0 1 0
0 1 0 1 1 0 1 0
0 1 0 1 1 0 1 0
0 1 0 0 0 0 1 0
0 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0

Converting it with imagemagick using the following command.

convert sample.pgm -scale 320x320 sample.bmp

results in the following bitmap.

enter image description here

4
  • Nice idea. What about: "No line should be longer than 70 characters." ? Commented Sep 1, 2015 at 15:36
  • Good call. I didn't notice that requirement. Maybe it would be easy for the OP to list one pixel per line. Maybe there is another raw ascii image format that doesn't have the 70 char/line limit?
    – James
    Commented Sep 1, 2015 at 15:42
  • @PhilippImhof: Actually I just violated the 70 char/line requirement and imagemagick didn't mind at all. Maybe some image readers wouldn't like it, but for imagemagick it doesn't seem to be an issue.
    – James
    Commented Sep 1, 2015 at 15:47
  • I just re-read the page you linked to. It says "should", so that's not a very strict limit and I thought there might be some hope... :) Commented Sep 1, 2015 at 15:49
1

Using \pdfliteral to produce inline image is, I believe, the most efficient way.

The drawback is that each small square is represented by two characters.

The idea comes from this question: Include PDF via \pdfliteral

\pdfcompresslevel0
\documentclass{article}
\begin{document}
\hbox to 10cm{%
    \immediate\pdfliteral{
        q
            11 0 0 7 0 0 cm            % input width = 11px;
                                       % input height = 7px
            10 0 0 3 0 0 cm            % output width = 10cm
                                       % output height = 3cm
            2.57693 0 0 2.57693 0 0 cm % magic number
            BI
                /W 11                  % input width = 11px;
                /H 7                   % input height = 7px
                /CS [
                    /Indexed /RGB
                    1                  % = using 2 colors
                                       % maximal is 255 = using 256 colors
                    <FF0000 0000FF>    % red and blue
                ]
                /BPC 8
                /F /AHx
                /I false
            ID
                01 00 01 01 00 01 00 01 00 01 00
                01 00 00 01 00 01 00 01 00 01 00
                00 01 00 01 00 01 01 01 00 01 00
                01 01 01 01 00 00 01 00 01 00 00
                00 01 01 00 00 00 01 01 00 00 01
                01 01 01 00 01 00 01 00 01 01 01
                01 00 01 00 01 00 01 00 01 01 01
                >
            EI
        Q
    }
    \hfill
}\vbox to3cm{}

\bigskip

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .