# Tikz diagram with matrix and chains

I'm learning how to draw diagrams with tikz I found valuable examples in texample.net, they are free to use, and most authors are very active in tex.stackexchange.com

I downloaded this "Example: BER measurement on fiber optical system Published 2009-07-31 | Author: Jose Luis Diaz" which looks pretty interesting to learn from and produce similar diagrams.

When I compiled the example I got some errors I could not solve. Can anyone help me find the issue in this code?

% BER measurement on fibre optical system
% Author: Jose Luis Diaz
\documentclass{minimal}
\usepackage[a4paper, landscape]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,shapes.arrows,decorations.pathmorphing}
\usetikzlibrary{matrix,chains,scopes,positioning,arrows,fit}

\begin{document}
\sffamily\begin{tikzpicture}
% Define a macro to draw the filter symbol
\def\filterSS{\node{};  % This empty node draws the box.
% Then we draw the inner curves
\draw[line width=1pt] (-2mm,-4mm) to[in=200,out=20] (-2mm, 4mm)
(0mm,-4mm) to[in=200,out=20] (0mm, 4mm)
(2mm,-4mm) to[in=200,out=20] (2mm, 4mm);
}

% Define a macro to draw the MOD symbol
\def\MOD#1{\node{#1}; % The box with the text inside. Then draw the polygon around the text
\draw[line width=1pt,sharp corners](-0.75cm,0cm)--(-0.35cm,0.25cm)--
(0.35cm, 0.25cm)--(0.75cm, 0cm)--(0.35cm, -0.25cm)--(-0.35cm, -0.25cm) -- cycle;
}

% Define a macro to draw the Polariser symbol
\def\Polaris{\node[coordinate]{}; % Node of type coordinate is a simple point
% Now draw the three circles
\draw[line width=1pt] (0mm, -2mm)  circle (2mm)
(-2mm,2mm)  circle (2mm)
(2mm, 2mm)  circle (2mm);}

% Place all element in a matrix of nodes, called m
% By default all nodes are rectangles with round corners
% but some special sytles are defined also
\matrix (m) [matrix of nodes,
column sep=5mm,
row sep=1cm,
nodes={draw, % General options for all nodes
line width=1pt,
anchor=center,
text centered,
rounded corners,
minimum width=1.5cm, minimum height=8mm
},
% Define styles for some special nodes
right iso/.style={isosceles triangle,scale=0.5,sharp corners, anchor=center, xshift=-4mm},
left iso/.style={right iso, rotate=180, xshift=-8mm},
txt/.style={text width=1.5cm,anchor=center},
ellip/.style={ellipse,scale=0.5},
empty/.style={draw=none}
]
{
% First row of symbols (mostly empty, only the power meter at the right end)
% m-1-1 empty
& % m-1-2 empty
& % m-1-3 empty
& % m-1-4 empty
& % m-1-5 empty
& % m-1-6 empty
& % m-1-7
|[txt]| {Power Meter}
\\

% Second row of symbols
% m-2-1
Laser
& % m-2-2
\MOD{MOD}
& % m-2-3
|[right iso]|
& % m-2-4
SOA
& % m-2-5
& % m-2-6
VOA
& % m-2-7
|[ellip]|
& % m-2-8
|[coordinate, xshift=-1cm]|
\\
% Third row of symbols
% m-3-1 empty
& % m-3-2
VOA
& % m-3-3
& % m-3-4
|[left iso]|
& % m-3-5
|[draw=orange!80!white, ultra thick]| \textbf{QDSOA}
& % m-3-6
|[left iso]|
& % m-3-7
\Polaris
& % m-3-8 (no symbol here, only a point to draw the path)
|[coordinate, xshift=-1cm]|
\\
% Fourth row of symbols
% m-4-1
|[txt]| {Power Meter}
& % m-4-2
|[ellip]|
& % m-4-3
|[right iso]|
& % m-4-4
SOA
& % m-4-5
|[right iso]|
& % m-4-6
& % m-4-7
Rx
& % m-4-8
|[txt]| {Error\\Detector}
\\
};  % End of matrix

% Now, connect all nodes in a chain.
% The names of the nodes are automatically generated in the previous matrix. Since the
% matrix was named m'', all nodes have the name m-row-column
{ [start chain,every on chain/.style={join}, every join/.style={line width=1pt}]
\chainin (m-2-1);
\chainin (m-2-2);
\chainin (m-2-3);
\chainin (m-2-4);
\chainin (m-2-5);
\chainin (m-2-6);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-1-7) edge node [right] {$10\%$} (m-2-7);
\chainin (m-2-7);
\chainin (m-2-8);
% Draw the label saying 90%
\path (m-2-8) edge node [right] {$90\%$} (m-3-8) ;
\chainin (m-3-8);
\chainin (m-3-7);
\chainin (m-3-6);
\chainin (m-3-5);
\chainin (m-3-4);
\chainin (m-3-3);
\chainin (m-3-2);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-4-1) edge node [above] {$10\%$} (m-4-2);
\chainin (m-4-2);
% Draw the label saying 90%
\path (m-4-2) edge node [below] {$90\%$} (m-4-3) ;
\chainin (m-4-3);
\chainin (m-4-4);
\chainin (m-4-5);
\chainin (m-4-6);
\chainin (m-4-7);
\chainin (m-4-8);
};
% Finally, put some text above some symbols
\draw (m-2-3.left side) node[above, inner sep=5mm] {Isolator};
\draw (m-2-5.north) node[above, inner sep=3mm] {Filter};
\draw (m-3-7) node[above, inner sep=6mm, text centered, text width=2cm] {Polarisation\\controller};

% The big arrow over the MOD symbol is a bit laborious
\node[yshift=2mm] (MOD arrow) at (m-2-2.north) [anchor=east,single arrow, draw,line width=1pt,
rotate=-90, minimum height=7mm, minimum width=1.3cm,
single arrow head extend=1.2mm, single arrow tip angle=120] {};
% The text above the arrow (the starting of the arrow is at west in the arrow shape, even if the
% arrow was rotated and it lies now at top)
\node (MOD text) at (MOD arrow.west) [above, inner sep=2mm] {10Gb/s PRBS};

% Define the style for the blue dotted boxes
\tikzset{blue dotted/.style={draw=blue!50!white, line width=1pt,
dash pattern=on 1pt off 4pt on 6pt off 4pt,
inner sep=4mm, rectangle, rounded corners}};

% Finally the blue dotted boxes are drawn as nodes fitted to other nodes
\node (first dotted box) [blue dotted,
fit = (MOD text) (m-2-1) (m-2-4)] {};
\node (second dotted box) [blue dotted,
fit = (m-4-4) (m-4-8)] {};

% Since these boxes are nodes, it is easy to put text above or below them
\node at (first dotted box.north) [above, inner sep=3mm] {\textbf{Transmitter}};
\node at (second dotted box.south) [below, inner sep=3mm] {\textbf{Receiver}};
\end{tikzpicture}
\end{document}


Erros: Package pgf Error: No shape named chain-2' is known. \chainin (m-2-2);

Package pgf Error: No shape named chain-5' is known. \chainin (m-2-6);

Package pgf Error: No shape named chain-10' is known. \chainin (m-3-6);

Package pgf Error: No shape named chain-20' is known. \chainin (m-4-7); ...

A matrix implicitly creates a node for every cell. The nodes are named (<matrixname>-<row>-<col>) automatically. However, some nodes in the matrix are defined explicitly, i.e., the commands \filterSS, \MOD, and \Polaris contain \node .... Those nodes do not have names. However, names of the form (m-<row>-<col>) are expected later on, e.g., in the \chainin commands.

One fix would be to name those nodes with

(\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn)


The final code with the change in \filterSS, \MOD, and \Polaris is:

% BER measurement on fibre optical system
% Author: Jose Luis Diaz
\documentclass{minimal}
\usepackage[a4paper, landscape]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,shapes.arrows,decorations.pathmorphing}
\usetikzlibrary{matrix,chains,scopes,positioning,arrows,fit}

\begin{document}
\sffamily\begin{tikzpicture}
% Define a macro to draw the filter symbol
\def\filterSS{\node(\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn){};  % This empty node draws the box.
% Then we draw the inner curves
\draw[line width=1pt] (-2mm,-4mm) to[in=200,out=20] (-2mm, 4mm)
(0mm,-4mm) to[in=200,out=20] (0mm, 4mm)
(2mm,-4mm) to[in=200,out=20] (2mm, 4mm);
}

% Define a macro to draw the MOD symbol
\def\MOD#1{\node(\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn){#1}; % The box with the text inside. Then draw the polygon around the text
\draw[line width=1pt,sharp corners](-0.75cm,0cm)--(-0.35cm,0.25cm)--
(0.35cm, 0.25cm)--(0.75cm, 0cm)--(0.35cm, -0.25cm)--(-0.35cm, -0.25cm) -- cycle;
}

% Define a macro to draw the Polariser symbol
\def\Polaris{\node(\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn)[coordinate]{}; % Node of type coordinate is a simple point
% Now draw the three circles
\draw[line width=1pt] (0mm, -2mm)  circle (2mm)
(-2mm,2mm)  circle (2mm)
(2mm, 2mm)  circle (2mm);}

% Place all element in a matrix of nodes, called m
% By default all nodes are rectangles with round corners
% but some special sytles are defined also
\matrix (m) [matrix of nodes,
column sep=5mm,
row sep=1cm,
nodes={draw, % General options for all nodes
line width=1pt,
anchor=center,
text centered,
rounded corners,
minimum width=1.5cm, minimum height=8mm
},
% Define styles for some special nodes
right iso/.style={isosceles triangle,scale=0.5,sharp corners, anchor=center, xshift=-4mm},
left iso/.style={right iso, rotate=180, xshift=-8mm},
txt/.style={text width=1.5cm,anchor=center},
ellip/.style={ellipse,scale=0.5},
empty/.style={draw=none}
]
{
% First row of symbols (mostly empty, only the power meter at the right end)
% m-1-1 empty
& % m-1-2 empty
& % m-1-3 empty
& % m-1-4 empty
& % m-1-5 empty
& % m-1-6 empty
& % m-1-7
|[txt]| {Power Meter}
\\

% Second row of symbols
% m-2-1
Laser
& % m-2-2
\MOD{MOD}
& % m-2-3
|[right iso]|
& % m-2-4
SOA
& % m-2-5
& % m-2-6
VOA
& % m-2-7
|[ellip]|
& % m-2-8
|[coordinate, xshift=-1cm]|
\\
% Third row of symbols
% m-3-1 empty
& % m-3-2
VOA
& % m-3-3
& % m-3-4
|[left iso]|
& % m-3-5
|[draw=orange!80!white, ultra thick]| \textbf{QDSOA}
& % m-3-6
|[left iso]|
& % m-3-7
\Polaris
& % m-3-8 (no symbol here, only a point to draw the path)
|[coordinate, xshift=-1cm]|
\\
% Fourth row of symbols
% m-4-1
|[txt]| {Power Meter}
& % m-4-2
|[ellip]|
& % m-4-3
|[right iso]|
& % m-4-4
SOA
& % m-4-5
|[right iso]|
& % m-4-6
& % m-4-7
Rx
& % m-4-8
|[txt]| {Error\\Detector}
\\
};  % End of matrix

% Now, connect all nodes in a chain.
% The names of the nodes are automatically generated in the previous matrix. Since the
% matrix was named m'', all nodes have the name m-row-column
{ [start chain,every on chain/.style={join}, every join/.style={line width=1pt}]
\chainin (m-2-1);
\chainin (m-2-2);
\chainin (m-2-3);
\chainin (m-2-4);
\chainin (m-2-5);
\chainin (m-2-6);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-1-7) edge node [right] {$10\%$} (m-2-7);
\chainin (m-2-7);
\chainin (m-2-8);
% Draw the label saying 90%
\path (m-2-8) edge node [right] {$90\%$} (m-3-8) ;
\chainin (m-3-8);
\chainin (m-3-7);
\chainin (m-3-6);
\chainin (m-3-5);
\chainin (m-3-4);
\chainin (m-3-3);
\chainin (m-3-2);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-4-1) edge node [above] {$10\%$} (m-4-2);
\chainin (m-4-2);
% Draw the label saying 90%
\path (m-4-2) edge node [below] {$90\%$} (m-4-3) ;
\chainin (m-4-3);
\chainin (m-4-4);
\chainin (m-4-5);
\chainin (m-4-6);
\chainin (m-4-7);
\chainin (m-4-8);
};
% Finally, put some text above some symbols
\draw (m-2-3.left side) node[above, inner sep=5mm] {Isolator};
\draw (m-2-5.north) node[above, inner sep=3mm] {Filter};
\draw (m-3-7) node[above, inner sep=6mm, text centered, text width=2cm] {Polarisation\\controller};

% The big arrow over the MOD symbol is a bit laborious
\node[yshift=2mm] (MOD arrow) at (m-2-2.north) [anchor=east,single arrow, draw,line width=1pt,
rotate=-90, minimum height=7mm, minimum width=1.3cm,
single arrow head extend=1.2mm, single arrow tip angle=120] {};
% The text above the arrow (the starting of the arrow is at west in the arrow shape, even if the
% arrow was rotated and it lies now at top)
\node (MOD text) at (MOD arrow.west) [above, inner sep=2mm] {10Gb/s PRBS};

% Define the style for the blue dotted boxes
\tikzset{blue dotted/.style={draw=blue!50!white, line width=1pt,
dash pattern=on 1pt off 4pt on 6pt off 4pt,
inner sep=4mm, rectangle, rounded corners}};

% Finally the blue dotted boxes are drawn as nodes fitted to other nodes
\node (first dotted box) [blue dotted,
fit = (MOD text) (m-2-1) (m-2-4)] {};
\node (second dotted box) [blue dotted,
fit = (m-4-4) (m-4-8)] {};

% Since these boxes are nodes, it is easy to put text above or below them
\node at (first dotted box.north) [above, inner sep=3mm] {\textbf{Transmitter}};
\node at (second dotted box.south) [below, inner sep=3mm] {\textbf{Receiver}};
\end{tikzpicture}
\end{document}


As user187803 said in their nice answer, the problem lies in the nesting of nodes insinde matrix nodes. Another way to solve this problem would be to replace the nested \nodes using the insert path option.

For example instead for the definition of the \MOD macro, you could add to the styles of the matrix the following:

mod/.style={insert path={
\pgfextra{
\draw[line width=1pt,sharp corners](-0.75cm,0cm)--(-0.35cm,0.25cm)--(0.35cm, 0.25cm)--(0.75cm, 0cm)--(0.35cm, -0.25cm)--(-0.35cm, -0.25cm) -- cycle;
}
}}


You would then need to replace \MOD{MOD} in the matrix by |[mod]|MOD. The same can be done with the other two definitions for \Polaris and \filterSS. The complete code would then become:

% BER measurement on fibre optical system
% Author: Jose Luis Diaz
\documentclass{minimal}
\usepackage[a4paper, landscape]{geometry}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric,shapes.arrows,decorations.pathmorphing}
\usetikzlibrary{matrix,chains,scopes,positioning,arrows,fit}

\begin{document}
\sffamily\begin{tikzpicture}

% Place all element in a matrix of nodes, called m
% By default all nodes are rectangles with round corners
% but some special sytles are defined also
\matrix (m) [matrix of nodes,
column sep=5mm,
row sep=1cm,
nodes={draw, % General options for all nodes
line width=1pt,
anchor=center,
text centered,
rounded corners,
minimum width=1.5cm, minimum height=8mm
},
% Define styles for some special nodes
right iso/.style={isosceles triangle,scale=0.5,sharp corners, anchor=center, xshift=-4mm},
left iso/.style={right iso, rotate=180, xshift=-8mm},
txt/.style={text width=1.5cm,anchor=center},
ellip/.style={ellipse,scale=0.5},
empty/.style={draw=none},
mod/.style={insert path={
\pgfextra{
\draw[line width=1pt,sharp corners](-0.75cm,0cm)--(-0.35cm,0.25cm)--(0.35cm, 0.25cm)--(0.75cm, 0cm)--(0.35cm, -0.25cm)--(-0.35cm, -0.25cm) -- cycle;
}
}},
polaris/.style={insert path={
\pgfextra{
\draw[line width=1pt] (0mm, -2mm) circle (2mm)
(-2mm,2mm) circle (2mm)
(2mm, 2mm) circle (2mm);
}
}},
\pgfextra{
\draw[line width=1pt] (-2mm,-4mm) to[in=200,out=20] (-2mm, 4mm)
(0mm,-4mm) to[in=200,out=20] (0mm, 4mm)
(2mm,-4mm) to[in=200,out=20] (2mm, 4mm);
}
}}
]
{
% First row of symbols (mostly empty, only the power meter at the right end)
% m-1-1 empty
& % m-1-2 empty
& % m-1-3 empty
& % m-1-4 empty
& % m-1-5 empty
& % m-1-6 empty
& % m-1-7
|[txt]| {Power Meter}
\\

% Second row of symbols
% m-2-1
Laser
& % m-2-2
|[mod]|MOD
& % m-2-3
|[right iso]|
& % m-2-4
SOA
& % m-2-5
& % m-2-6
VOA
& % m-2-7
|[ellip]|
& % m-2-8
|[coordinate, xshift=-1cm]|
\\
% Third row of symbols
% m-3-1 empty
& % m-3-2
VOA
& % m-3-3
& % m-3-4
|[left iso]|
& % m-3-5
|[draw=orange!80!white, ultra thick]| \textbf{QDSOA}
& % m-3-6
|[left iso]|
& % m-3-7
|[polaris]|
& % m-3-8 (no symbol here, only a point to draw the path)
|[coordinate, xshift=-1cm]|
\\
% Fourth row of symbols
% m-4-1
|[txt]| {Power Meter}
& % m-4-2
|[ellip]|
& % m-4-3
|[right iso]|
& % m-4-4
SOA
& % m-4-5
|[right iso]|
& % m-4-6
& % m-4-7
Rx
& % m-4-8
|[txt]| {Error\\Detector}
\\
};  % End of matrix

% Now, connect all nodes in a chain.
% The names of the nodes are automatically generated in the previous matrix. Since the
% matrix was named m'', all nodes have the name m-row-column
{ [start chain,every on chain/.style={join}, every join/.style={line width=1pt}]
\chainin (m-2-1);
\chainin (m-2-2);
\chainin (m-2-3);
\chainin (m-2-4);
\chainin (m-2-5);
\chainin (m-2-6);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-1-7) edge node [right] {$10\%$} (m-2-7);
\chainin (m-2-7);
\chainin (m-2-8);
% Draw the label saying 90%
\path (m-2-8) edge node [right] {$90\%$} (m-3-8) ;
\chainin (m-3-8);
\chainin (m-3-7);
\chainin (m-3-6);
\chainin (m-3-5);
\chainin (m-3-4);
\chainin (m-3-3);
\chainin (m-3-2);
% Connect to the power meter, and put a label saying 10%
\path[line width=1pt] (m-4-1) edge node [above] {$10\%$} (m-4-2);
\chainin (m-4-2);
% Draw the label saying 90%
\path (m-4-2) edge node [below] {$90\%$} (m-4-3) ;
\chainin (m-4-3);
\chainin (m-4-4);
\chainin (m-4-5);
\chainin (m-4-6);
\chainin (m-4-7);
\chainin (m-4-8);
};
% Finally, put some text above some symbols
\draw (m-2-3.left side) node[above, inner sep=5mm] {Isolator};
\draw (m-2-5.north) node[above, inner sep=3mm] {Filter};
\draw (m-3-7) node[above, inner sep=6mm, text centered, text width=2cm] {Polarisation\\controller};

% The big arrow over the MOD symbol is a bit laborious
\node[yshift=2mm] (MOD arrow) at (m-2-2.north) [anchor=east,single arrow, draw,line width=1pt,
rotate=-90, minimum height=7mm, minimum width=1.3cm,
single arrow head extend=1.2mm, single arrow tip angle=120] {};
% The text above the arrow (the starting of the arrow is at west in the arrow shape, even if the
% arrow was rotated and it lies now at top)
\node (MOD text) at (MOD arrow.west) [above, inner sep=2mm] {10Gb/s PRBS};

% Define the style for the blue dotted boxes
\tikzset{blue dotted/.style={draw=blue!50!white, line width=1pt,
dash pattern=on 1pt off 4pt on 6pt off 4pt,
inner sep=4mm, rectangle, rounded corners}};

% Finally the blue dotted boxes are drawn as nodes fitted to other nodes
\node (first dotted box) [blue dotted,
fit = (MOD text) (m-2-1) (m-2-4)] {};
\node (second dotted box) [blue dotted,
fit = (m-4-4) (m-4-8)] {};

% Since these boxes are nodes, it is easy to put text above or below them
\node at (first dotted box.north) [above, inner sep=3mm] {\textbf{Transmitter}};
\node at (second dotted box.south) [below, inner sep=3mm] {\textbf{Receiver}};

\end{tikzpicture}
\end{document}