# Fitting a list of points with TikZ and its \foreach

I have a list of N points (e.g. {(0,0),(42,7),...,(0,1)}). I want to use them as coordinates in TikZ, to draw some things. And I would like to fit them into a node (using TikZ's fit module (cf. http://www.texample.net/tikz/examples/feature/fit/ or PGF documentation §34) to put a label under them.

If I have, for example, 4 points, I can manually do it, and it works perfectly :

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{calc,fit}
\begin{document}
\begin{tikzpicture}

\newcounter{i}
\setcounter{i}{0}
\foreach \point in
{(0,0),(0,2),(2,0),(2,2)}
{
\node[coordinate] (point-\arabic{i}) at \point { };
\fill (point-\arabic{i}) circle (0.1);
\stepcounter{i}
}

\node (box) [draw=gray,dashed, inner sep=10pt,fit=(point-0) (point-1) (point-2) (point-3)] {};
\node (label) at (box.south) [below] { blah };

\end{tikzpicture}

\end{document}


which gives :

Now I want to do the same for an arbitrary number of points. I hoped a \foreach would work:

\node (boxforeach) [draw=gray,dashed, inner sep=10pt,fit= \foreach \j in {0,1,...,3}{(point-\j) } ] {};


but all I get are lots of ! Package tikz Error: Cannot parse this coordinate..

Is there a mean to get that working? If there isn't, do you have a simple method to calculate the coordinates of the box manually?

-
fixed your figure for you. – Yossi Farjoun Oct 31 '10 at 22:04

Well, I had hoped there'd be a nicer way to do it, but there's nothing in the TikZ manual, so this is what I'd do:

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{calc,fit}
\begin{document}
\begin{tikzpicture}

\edef\points{}
\foreach \point [count=\i] in {(0,0),(0,2),(2,0),(2,2)} {
\def\this{point-\i}
\node[coordinate] (\this) at \point {} ;
\fill (\this) circle (0.1) ;
\xdef\points{(\this) \points}
}

\node (box) [draw=gray,dashed, inner sep=10pt,fit=\points] {};
\node (label) at (box.south) [below] { blah };

\end{tikzpicture}

\end{document}


If you haven't seen \edef before, it's like \def or \newcommand, except it expands the definition before assigning it; \xdef is equivalent to \global\edef, so its effects can escape the foreach. Essentially, I just build up the list as you construct the points, and then use the result.

I also removed your manual counter and replaced it with the [count=\i] option to \foreach. \foreach actually has a lot of useful options; I recommend checking out section 51 of the TikZ & PGF manual.

-
+1 for the xdef explanation – Christian Oct 31 '10 at 17:59
Going back to the manual counter solution ([count=\i] doesn't work with my version of pgf/tikz), it works perfectly. Thanks. – stzagorec Oct 31 '10 at 19:53
I have posted a related question what is the count=\i – Peter Grill Jun 25 '11 at 1:44

This is a hack of the fit library that should work in most cases (the only altered original macro is \tikz@lib@fit@scan to allow a \foreach parsing).

Note that the fit work is done inside a \foreach (see \tikz@scan@one@point\tikz@lib@fit@scan@handle@foreach@ in \tikz@lib@fit@scan@handle@foreach), so changes to dimensions must be made \global.

\documentclass[border=.5cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{fit}
\makeatletter
\def\tikz@lib@fit@scan{%
\pgfutil@ifnextchar\pgf@stop{\pgfutil@gobble}{%
\pgfutil@ifnextchar\foreach{\tikz@lib@fit@scan@handle@foreach}{%
\tikz@scan@one@point\tikz@lib@fit@scan@handle}}}
\def\tikz@lib@fit@scan@handle@foreach\foreach#1in#2#3{%
\foreach #1 in {#2}
{\tikz@scan@one@point\tikz@lib@fit@scan@handle@foreach@#3}
\tikz@lib@fit@scan}
\def\tikz@lib@fit@scan@handle@foreach@#1{%
\iftikz@shapeborder
\pgfpointanchor{\tikz@shapeborder@name}{west}}%
\pgfpointanchor{\tikz@shapeborder@name}{east}}%
\pgfpointanchor{\tikz@shapeborder@name}{north}}%
\pgfpointanchor{\tikz@shapeborder@name}{south}}%
\else
\fi
\global\pgf@xa=\pgf@xa
\global\pgf@ya=\pgf@ya
\global\pgf@xb=\pgf@xb
\global\pgf@yb=\pgf@yb}
\makeatletter
\begin{document}
\begin{tikzpicture}
\foreach \point [count=\i] in {(0,0),(0,2),(2,0),(2,2),(3,3),(-1,-1)}{%
\node[coordinate] (point-\i) at \point {};
\fill (point-\i) circle (0.1);}
\node [draw=gray,dashed,inner sep=10pt,
fit = \foreach \j in {1,2,...,4}{(point-\j) }] (boxforeach1) {};
\node [draw=red,dashed, inner sep=10pt,
fit = (point-1) \foreach \j in {2,...,5}{(point-\j) }] (boxforeach2) {};
\node [draw=blue,dashed, inner sep=10pt,
fit = (point-1) \foreach \j in {2,...,5}{(point-\j) } (point-6)]
(boxforeach3) {};
\end{tikzpicture}
\end{document}

-
Note that a feature request has been added at the sourceforge project web page. – cjorssen Mar 20 '12 at 11:59

Maybe a .List handler can be helpful in other cases, too?

The second TikZ picture shows cjorssen’s examples from his answer. Of course, with the .List handler, in all cases one would just do {(point-1),...,(point-<last>)} but I wanted to show how one would need to give an example that does not fit in the scheme.

### Thoughts

PGFkeys offers with the .list handler already a \foreach alternative that doesn’t group its content (it actually does nearly the same), but what would be the benefit (besides checking whether \foreach is defined)? Maybe

I guess, it wouldn’t be too hard to implement a .foreach handler so that one could use the full power of a \foreach loop (multiple variables, options like count, evaluate and so on) …

## Code

\documentclass[tikz]{standalone}
\usetikzlibrary{fit}
\makeatletter
\pgfqkeys{/handlers}{%
.List/.code={%
\let\pgfkeys@global@temp\pgfutil@empty
\foreach \pgfkeys@temp in{#1}{
\ifx\pgfkeys@global@temp\pgfutil@empty
\global\let\pgfkeys@global@temp\pgfkeys@temp
\else
{\pgfkeys@temp}%
\fi}%
\expandafter\pgfkeys@exp@call\expandafter{\pgfkeys@global@temp}}}
\begin{document}
\begin{tikzpicture}
\foreach \point[count=\cnt from 0] in {(0,0),(0,2),(2,0),(2,2)}

\node[label=below:blah, draw=gray, dashed, inner sep=+10pt,
fit/.List={(point-0),(point-...),(point-3)}] {};
\end{tikzpicture}

\begin{tikzpicture}[nodes={draw, dashed, inner sep=+10pt}]
\foreach \point [count=\cnt] in {(0,0), (0,2), (2,0), (2,2), (3,3), (-1,-1)}
\node[gray, fit/.List={(point-1),(point-...),(point-4)}]  {};
\node[red,  fit/.List={(point-1),(point-2),(point-...),(point-5)}]  {};
\node[blue, fit/.List={(point-1),(point-2),(point-...),(point-5),(point-6)}] {};
\end{tikzpicture}
\end{document}


## Output

-

Maybe this will do the job:

\begin{tikzpicture}
\newcounter{i}
\setcounter{i}{0}
\foreach \point in
{(0,0),(0,2),(2,0),(2,2)}
{
\node[coordinate] (point-\arabic{i}) at \point { };
\fill (point-\arabic{i}) circle (0.1);
\stepcounter{i}
}

\path (current bounding box.south west) -- (current bounding box.south east)
node[midway, below] {blah};
\end{tikzpicture}


This example simply uses the current bounding box.

-
I looked a bit too quickly at your answer, it would also work in this case, but not if this is part of a bigger picture. However, there is a local bounding box option to {scope}'s. In my case, it would be more elegant, but it doesn't allow to "fit" points that are defined at different places. But thanks. – stzagorec Oct 31 '10 at 20:09