7

I am drawing diagrams which consist of grids, some cells of which are filled with circles, like this:

enter image description here

I created this picture with

\begin{tikzpicture}[scale=0.6]
  \draw[shift={(0.5,0.5)}] (0,0) grid (6,6);
  \foreach \x in {0,1,...,5} {
    \node at (\x+1,7) {$\x$};
    \node[left] at (0,6-\x) {$\x$};
  }
  \foreach \x in {2,3,4,5} {
     \foreach \y in {3,4} {
        \fill (\x,\y) circle(0.2);
        \fill (\y,\x) circle(0.2);
     }
  }
\end{tikzpicture}

Now in this picture the dots are nicely symmetric, so I can place them with some neat \foreach statements. But in other diagrams the dots are more randomly scattered, and so I need some way of entering them one by one.

This works (for a different diagram):

\begin{tikzpicture}[circ/.style = {circle,radius=2mm,fill=black},scale=0.6]
\draw[shift={(0.5,0.5)}] (0,0) grid (6,6);
  \foreach \x in {0,1,...,5} {
    \node at (\x+1,7) {$\x$};
    \node[left] at (0,6-\x) {$\x$};
  }
\matrix[matrix of nodes,row sep=2.8mm,column sep=2.8mm,shift={(2.1,2.1)}] {
\node[circ] {}; & \node[circ] {}; & \node[circ] {}; &&&\\
\node[circ] {}; & \node[circ] {}; & \node[circ] {}; &&&\\
\node[circ] {}; & \node[circ] {}; & \node[circ] {}; & \node[circ] {};&&\\
&&\node[circ] {}; & \node[circ] {}; & \node[circ] {};\\
&&&\node[circ] {}; & \node[circ] {}; & \node[circ] {};\\
&&&\node[circ] {}; & \node[circ] {}; & \node[circ] {};\\
};
\end{tikzpicture}

But it's a pain getting the matrix lined up in the right place. Also, I don't seem to be able to scale the circles properly - they end up filling the entire cell like this:

enter image description here

which is clearly not what I want.

So - how do I use matrix in TiKZ to fill certain cells in a grid with small circles? Or is there another, better, way?

  • Please always post a complete example people can compile - especially when using specialised packages and libraries. It makes your question easier to answer and more helpful to other users. – cfr Feb 5 '15 at 3:06
  • This would be straightforward to do if you combined tikz with lualatex. That doesn't answer your question, but it may be worth looking into. – JPi Feb 5 '15 at 3:45
8

I would draw the grid using \matrix instead, as doing so provides anchors like m-i-j (as the ith row and jth column of the matrix) which you can later access in drawing circles.

I've automated stuff a bit by defining a \mygrid command, which takes two arguments that specify the dimension of the grid. (If it's always a square, then the command can be simplified by dropping the second argument.)

In terms of scaling, the circles themselves can be scaled by passing the scale option to tikzpicture, and if you want to scale the grid, pass the scale option to \mygrid.

MWE

\documentclass{article}

\usepackage{tikz,etoolbox}
\usetikzlibrary{matrix}

\newcommand\mygrid[3][]{      % this definition uses \foreach inside a matrix
  \let\mymatrixcontent\empty  % see http://tex.stackexchange.com/q/60394/18228
  \newcommand{\row}{%
    \foreach \j in {1,...,#2}{
      \foreach \i in {1,...,#3} {%
        \begingroup\edef\x{\endgroup
           \noexpand\gappto\noexpand\mymatrixcontent{|[draw,minimum size=1cm,#1]| \&}}\x
        }%
      \gappto\mymatrixcontent{\\}%
    }
  }
  \row
  \matrix(m)[matrix of nodes,ampersand replacement=\&,row sep=-\pgflinewidth,column sep=-\pgflinewidth]{
    \mymatrixcontent
  };
  \foreach \x[count=\i from 0] in {1,...,#2}\node[left] at (m-\x-1.west) {$\i$};
  \foreach \y[count=\j from 0] in {1,...,#3}\node[above] at (m-1-\y.north) {$\j$};
}

\begin{document}

\begin{tikzpicture}[scale=.5,]
\mygrid[scale=.6]{6}{8} % two extra columns just for demonstration

\foreach\j[count=\i,remember=\i as \x(initially 3)] in{1,...,6}{
  \filldraw(m-\i-\j)circle[radius=2pt];
  \filldraw(m-\x-\j)circle[radius=2pt];
  \filldraw(m-\j-\x)circle[radius=2pt];
  \filldraw(m-6-4)circle[radius=2pt];
}
\end{tikzpicture}
\end{document}

Output

enter image description here

  • That's a very nice mygrid command! However, it doesn't really help me place large numbers of dots which are not in a nice ordered position. At this stage I'm reduce to \foreach \a in {(1,3),(4,5),(4,7) <and so on>...} \fill \a circle(0.2); where the foreach list contains the coordinates of each point. I hoped there might be a simpler way! – Alasdair Feb 5 '15 at 7:03
  • @Alasdair: May I ask how are the positions of the dots determined? If the cells to be filled are determined through another numerical program, then you could try to get the coordinates of those cells from the program and feed them into the \foreach command. – Herr K. Feb 5 '15 at 7:41
  • 1
    @Alasdair: I came up with a way to place dots for your second example a bit more efficiently than my last attempt (See updated code). The method uses a combination of the count and remember keys for \foreach. In general, though, if the dots don't possess a nice pattern, then I can't see a way to improve much on my current solution, which at least addresses the scaling problem and offers the (m-i-j) syntax to refer to the i-jth cell on the grid. – Herr K. Feb 5 '15 at 8:07
5

Another option without \mygrid command. It draws a matrix with empty nodes and defines a node style which uses append after command to place a dot inside.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{matrix,positioning}


\begin{document}


\begin{tikzpicture}[
    mycell/.style={draw, minimum size=1cm},
    dot/.style={mycell,
        append after command={\pgfextra \fill (\tikzlastnode) circle[radius=5pt]; \endpgfextra}}]

\matrix (m) [matrix of nodes, row sep=-\pgflinewidth, column sep=-\pgflinewidth, 
    nodes={mycell}, nodes in empty cells]
{
&&&|[dot]|&&\\
&&&&&\\
&&&&|[dot]|&\\
|[dot]|&&&&&\\
&&&&&\\
&|[dot]|&&&&\\
};

% labels on top and left
\foreach \i [count=\xi from 0] in  {1,...,6}{
    \node[mycell, label=above:\xi] at (m-1-\i) {}; 
    \node[mycell,label=left:\xi] at (m-\i-1) {}; 
}
\end{tikzpicture}
\end{document}

enter image description here

  • Many thanks! That looks to be the sort of thing I was after. Seems to be a case of sorting out the matrix parameters exactly so that you end up with a nice square grid effect. Thank you again. – Alasdair Feb 5 '15 at 23:04
  • @Alasdair Yes, a matrix is not a grid but a set of 2D aligned nodes. Each node keeps its own size. If you want to build a grid with a matrix, all nodes must have same width and height. – Ignasi Feb 6 '15 at 9:18
3

Here is a short solution to create this kind of diagrams :

\documentclass[tikz,border=7mm]{standalone}
\usetikzlibrary{calc}
\begin{document}
  \begin{tikzpicture}
    % draw the grid and the numbers
    \draw (-1,-1) grid (5,5) foreach \i in {0,...,5}{
      (\i-.5,5.5) node{\i} (-1.5,4.5-\i) node{\i}};
    % for every line we give first and last index to fill
    \foreach[count=\j] \a/\b in {0/2,0/2,0/3,2/4,3/5,3/5}
      \foreach \i in {\a,...,\b}
        \fill[red,shift={(-.5,5.5)},yscale=-1] (\i,\j) circle(2mm);
  \end{tikzpicture}
\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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