Animate movement through a Neural Network
It is not very difficult to animate something like this. However, a greater challenge is to keep the computation time semi reasonable. This can be achieved by only making the relevant circles nodes, and drawing the others with a pattern.
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,patterns.meta}
\tikzdeclarepattern{
name=neurons,
type=uncolored,
bounding box={(-1.25mm,-1.25mm) and (1.25mm,1.25mm)},
tile size={(\tikztilesize,\tikztilesize)},
parameters={\tikzcircleradius,\tikztilesize},
tile transformation={xshift=1.75mm,yshift=1.75mm},
defaults={
radius/.store in=\tikzcircleradius,radius=1mm,
tile size/.store in=\tikztilesize,tile size=2.5mm,
}, code={
\draw[thin] (0,0) circle[radius=\tikzcircleradius];
} }
\begin{document}
\foreach \Z in {1,...,24}
{\begin{tikzpicture}[font=\sffamily,>={Triangle[angle=45:.1cm 1]},
circ/.style={circle,draw,inner sep=0pt,minimum size=2mm}]
\path[pattern=neurons,local bounding box=input]
(-3.5,-3.5) rectangle +(7,7);
\path[pattern=neurons,pattern color=cyan,
local bounding box=first] (5,-3) rectangle +(6,6)
(.25*\Z+5-0.125, 3-0.125)
node[circ,thick,black] (first-1-1) {};
\path foreach \X in {1,...,5}
{foreach \Y in {1,...,5}
{(-3.5+.25 * \X -0.375+0.25*\Z, 3.5-0.25 * \Y+0.125)
node[circ,red,thick] (input-\X-\Y){}}};
\path (input.north) node[above]{input neurons}
(first.north) node[above=1em]{first hidden layer};
\foreach \X in {1,...,5}
{\foreach \Y in {1,...,5}
{\draw[->,blue!50!cyan,shorten <={(\X-1)*0.25cm}] (input-\X-\Y) to [in=180, out=0] (first-1-1);}}
\end{tikzpicture}}
\end{document}
NOTE: The pdf version of the result looks good.
However, if one produces an animated gif from this then the circles do not match! I have no idea why the conversion does that. But this means that in order to have a gif, patterns
seem to be not optimal. I do not know if this has been noted before...
Here is a code that takes much more time to compile but has not problem with a gif conversion.
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\foreach \Z in {1,...,24}
{\begin{tikzpicture}[font=\sffamily,>={Triangle[angle=45:.1cm 1]},
circ/.style={circle,draw,inner sep=0pt,minimum size=2mm}]
%
\draw[local bounding box=input] foreach \Y in {1, 2, ..., 28} {
foreach \X in {1, 2, ..., 28} {
(.25 * \X - 28/8-0.25, -0.25 * \Y + 28/8+0.25)
circle[radius=1mm]}};
\draw[local bounding box=first,xshift=8cm,cyan] foreach \Y in {1, 2, ..., 24} {
foreach \X in {1, 2, ..., 24} {
(.25 * \X - 24/8-0.25, -0.25 * \Y + 24/8+0.25)
circle[radius=1mm]}}
(.25 * \Z- 24/8-0.25, 24/8)
node[circ,thick,black] (first-1-1) {};
\path foreach \X in {1,...,5}
{foreach \Y in {1,...,5}
{(.25 * \X - 28/8-0.25+0.25*\Z-0.25, -0.25 * \Y + 28/8+0.25)
node[circ,red,thick] (input-\X-\Y){}}};
\path (input.north) node[above]{input neurons}
(first.north) node[above]{first hidden layer};
\foreach \X in {1,...,5}
{\foreach \Y in {1,...,5}
{\draw[->,blue!50!cyan,shorten <={(\X-1)*0.25cm}] (input-\X-\Y) to [in=180, out=0] (first-1-1);}}
\end{tikzpicture}}
\end{document}
ADDENDUM: After having seen Symbol 1's very nice answer I'd like to add that one can get circles very easily with a dash patten. The key ingredient are the keys
dash pattern=on 0mm off 2.5mm,line cap=round,
double distance between line centers=2mm
where 2.5mm
is the distance between the circle centers and 2mm
is their radius.
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\foreach \Z in {1,...,24}
{\begin{tikzpicture}[font=\sffamily,>={Triangle[angle=45:.1cm 1]},
circ/.style={circle,draw,inner sep=0pt,minimum size=2mm}]
\draw[local bounding box=input,
dash pattern=on 0mm off 2.5mm,line cap=round,
double distance between line centers=2mm] foreach \X in {1,...,28}
{(-3.4cm+1.5\pgflinewidth,3.6cm-0.25*\X*1cm+1.5\pgflinewidth) -- ++ (6.75,0)};
\draw[local bounding box=first,cyan,
dash pattern=on 0mm off 2.5mm,line cap=round,
double distance between line centers=2mm] foreach \X in {1,...,24}
{(8cm-2.9cm+1.5\pgflinewidth,3.1cm-0.25*\X*1cm+1.5\pgflinewidth) -- ++ (5.75,0)};
\path
(.25*\Z+5-0.125, 3-0.125)
node[circ,thick,black] (first-1-1) {};
\path foreach \X in {1,...,5}
{foreach \Y in {1,...,5}
{(-3.5+.25 * \X -0.375+0.25*\Z, 3.5-0.25 * \Y+0.125)
node[circ,red,thick] (input-\X-\Y){}}};
\path (input.north) node[above]{input neurons}
(first.north) node[above=1em]{first hidden layer};
\foreach \X in {1,...,5}
{\foreach \Y in {1,...,5}
{\draw[->,blue!50!cyan,shorten <={(\X-1)*0.25cm}] (input-\X-\Y) to [in=180, out=0] (first-1-1);}}
\end{tikzpicture}}
\end{document}
As one can see, there is not offset whatsoever, and the compilation time is very short.
In addition to @Schrödinger's cat's answer, this is meant to be a supplemental material.
If you don't mind having squares instead of circles,
there is a way to generate n^2
squares with O(1)
code.
It uses dash pattern
instead of pattern
.
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw[line width=200,dash pattern=on 2 off 2,dash phase=3]
(-100pt,0)--(100pt,0);
\draw[line width=200,dash pattern=on 2 off 2,dash phase=3]
(0,-100pt)--(0,100pt);
\draw[white,line width=200,dash pattern=on 2 off 6,dash phase=1]
(0,-100pt)--(0,100pt);
\draw[white,line width=200,dash pattern=on 2 off 6,dash phase=1]
(-100pt,0)--(100pt,0);
\end{tikzpicture}
\end{document}
8-bit circles
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\verti{(-100pt,0)--(100pt,0)}\def\horiz{(0,-100pt)--(0,100pt)}
\def\cross{\verti\horiz}
\clip(-100pt,-100pt)rectangle(100pt,100pt);
\begin{scope}[every path/.style={line width=200pt},
blend mode=darken]
\begin{scope}[blend group=normal]
\draw[dash pattern=on2off6,dash phase=5]\verti;
\draw[dash pattern=on2off1on4off1,dash phase=1,white]\horiz;
\end{scope}
\begin{scope}[blend group=normal]
\draw[blend mode=darken]\verti;
\draw[dash pattern=on4off1on2off1,dash phase=2,white]\cross;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on2off6,dash phase=5]\horiz;
\draw[dash pattern=on2off1on4off1,dash phase=1,white]\verti;
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}
octagon
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\verti{(-100pt,0)--(100pt,0)}\def\horiz{(0,-100pt)--(0,100pt)}
\def\diago{(-100pt,-100pt)--(100pt,100pt)}
\def\antid{(-100pt,100pt)--(100pt,-100pt)}
\clip(-100pt,-100pt)rectangle(100pt,100pt);
\begin{scope}[every path/.style={line width=300pt},
blend mode=darken]
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off7,dash phase=6.5]\verti;
\draw[dash pattern=on3off1on5off1,dash phase=1.5,white]\horiz;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off11.142135,dash phase=1.5]\diago;
\draw[dash pattern=on7off1on5.142135off1,dash phase=3.5,
white]\antid;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off11.142135,dash phase=1.5]\antid;
\draw[dash pattern=on7off1on5.142135off1,dash phase=3.5,
white]\diago;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off11.142135,dash phase=8.5710675]\diago;
\draw[dash pattern=on7off1on5.142135off1,dash phase=10.5710675,
white]\antid;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off11.142135,dash phase=8.5710675]\antid;
\draw[dash pattern=on7off1on5.142135off1,dash phase=10.5710675,
white]\diago;
\end{scope}
\begin{scope}[blend group=normal]
\draw[dash pattern=on3off7,dash phase=6.5]\horiz;
\draw[dash pattern=on3off1on5off1,dash phase=1.5,white]\verti;
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}