Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to draw the following using PSTricks (or TikZ):

polygonal-numbers

(Found on http://i1.wp.com/mathandmultimedia.com/wp-content/uploads/2012/08/polygonal-numbers.png.)

I can do it myself using an extremely low-tech soluton where I draw every blue and yellow dot maunally, but I can't figure out how to do it' automatically'.

Thank you in advance.

P.S. Sorry for not giving it a try myself; I really don't know where to start (other than the fact that is probably has to involve \multidos).

Update

I would like a representation of the triangle numbers too.

Update 2

Consider the following code (from Qrrbrbirlbel):

\documentclass{article}

\usepackage[margin=2.4cm]{geometry}
\usepackage{tikz}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={draw},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @1@0.center)
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @1@0.center)
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
      }
    }
  }
}
\makeatother

\newcommand*\polygonnumbers[1]{%
\foreach \sides in {3,...,#1}{%
\begin{tikzpicture}
\path [polynum={/tikz/rotate=360/\sides/2,sides=\sides}];
\foreach \corner in {1,...,\the\numexpr\sides-1\relax}{%
  \pgfmathanglebetweenpoints{\pgfpointanchor{pn@\corner@1@0}{center}}
                            {\pgfpointanchor{pn@\corner@\pgfkeysvalueof{/polynum/levels}@0}{center}}
  \let\angle\pgfmathresult
  \draw[
    blue,
    rotate=\angle,
    rounded corners=1pt,
    thick] (pn@\corner@1@0.\angle+180) ++ (left:2pt) coordinate (@aux)
                                         -- ++ (up:4pt)
                                         -| ([shift=(right:2pt)] pn@\corner@\pgfkeysvalueof{/polynum/levels}@0.\angle)
                                         |- ([shift=(down:4pt)] @aux)
                                         -- cycle
                                        ;
}
\end{tikzpicture}
}
}

\begin{document}

\begin{figure}[htbp]
  \centering
    \polygonnumbers{6}
\end{figure}

\end{document}

How to I create a command where \polygonnumbers takes the two arguments #1 = <number of dots in each row> and #2 = <maximal n-gon>? (Now I just have a command with the single argument #1 = <maximal n-gon>.)

Update 3

Unfortunately, I get an error if I change \polygonnumbers{5}{6} to \polygonnumbers{4}{6} in the following code:

\documentclass{article}

\usepackage[margin=2.4cm]{geometry}
\usepackage{tikz}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={draw},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @1@0.center)
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @1@0.center)
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
      }
    }
  }
}
\makeatother

\newcommand*\polygonnumbers[2]{%
\foreach \sides in {3,...,#2}{%
\begin{tikzpicture}
\path [polynum={/tikz/rotate=360/\sides/2,levels=#1,sides=\sides}];
\foreach \corner in {1,...,\the\numexpr\sides-1\relax}{%
  \pgfmathanglebetweenpoints{\pgfpointanchor{pn@\corner@1@0}{center}}
                            {\pgfpointanchor{pn@\corner@\pgfkeysvalueof{/polynum/levels}@0}{center}}
  \let\angle\pgfmathresult
  \draw[
    blue,
    rotate=\angle,
    rounded corners=1pt,
    thick] (pn@\corner@1@0.\angle+180) ++ (left:2pt) coordinate (@aux)
                                         -- ++ (up:4pt)
                                         -| ([shift=(right:2pt)] pn@\corner@\pgfkeysvalueof{/polynum/levels}@0.\angle)
                                         |- ([shift=(down:4pt)] @aux)
                                         -- cycle
                                        ;
}
\end{tikzpicture}
}
}

\begin{document}

\begin{figure}[htbp]
  \centering
    \polygonnumbers{4}{6}
\end{figure}

\end{document}

The error is

! Package pgf Error: No shape named pn@1@5@0 is known.

See the pgf package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.134     \polygonnumbers{4}{6}

Final

Here is what I ende up with (after another slight improvement):

\documentclass{article}

\usepackage[margin=2cm]{geometry}
\usepackage[figureposition=bottom]{caption}
\usepackage{tikz}

\DeclareCaptionLabelSeparator{tilpasning}{:\quad}
\captionsetup{%
  font=small,
  labelfont=sc,
  labelsep=tilpasning,
  width=0.7\textwidth
}

\pgfkeys{%
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}
}
\def\polynumset{\pgfqkeys{/polynum}}
\newif\ifpolynumbars
\polynumset{%
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+0.5cm,
  x padding/.initial=+2pt,
  y padding/.initial=+2pt,
  bars/.is if=polynumbars,
  every bar/.tikz={draw=blue, thick, rounded corners=+1pt},
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue!60},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={},
  %
  every corner edge/.code={%
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  }
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\polynumset{%
  bar path/.style={%
    to path={%
      [/utils/exec=%
         \pgfmathanglebetweenpoints{\pgfpointanchor{\tikztostart} {center}}
                                   {\pgfpointanchor{\tikztotarget}{center}}
         \let\polynum@a\pgfmathresult
         \pgftransformrotate{\polynum@a}
         \pgfpointdiff{\pgfpointanchor{\tikztostart}{center}}
                      {\pgfpointshapeborder{\tikztostart}{\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}{\pgfpointpolar{90}{1pt}}}}
         \pgfmathveclen{\pgf@x}{\pgf@y}
         \edef\polynum@ydistance{\pgfmathresult pt}
         \pgfcoordinate{pn@aux1}
                       {\pgfpointshapeborder
                         {\tikztostart}
                         {\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}
                                      {\pgfpointpolar{180}{1pt}}}}
         \pgfcoordinate{pn@aux2}
                       {\pgfpointshapeborder
                         {\tikztotarget}
                         {\pgfpointadd{\pgfpointanchor{\tikztotarget}{center}}
                                      {\pgfpointpolar{0}{1pt}}}}
       ]
             ([shift=(left:\pgfkeysvalueof{/polynum/x padding})]pn@aux1) coordinate (pn@aux)
       -- ++ (up:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})
       -|    ([shift=(right:\pgfkeysvalueof{/polynum/x padding})] pn@aux2)
       |-    ([shift=(down:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})] pn@aux)
       -- cycle
    }
  }}
\tikzset{%
  polynum/.default=,
  polynum/.style={%
    insert path={%
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}-1}
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {%
          % Get to the next corner;
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level.
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % It is only a coordinate because it is used to place everything else,
          % including the node at the exact same position.
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % All other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {%
            (pn@\polynumcorner @1@0.center)
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % The edges between the corner nodes (blue -- blue).
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % Now the sublevels (except for the first corner because it has no previous corner).
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{%
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % The edges between sublevel nodes (blue -- yellow and yellow -- yellow).
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % The edge between the last sublevel node and the next corner node (yellow -- blue).
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % The edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue).
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @1@0.center)
        }
        % The last edge (blue -- red).
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
        % The bars are drawn in an extra loop to make sure they are on top.
        [/utils/exec=%
          \ifpolynumbars\expandafter\polynumutil@firstofone\else\expandafter\pgfutil@gobble\fi
            {\foreach \polynumcorner in {1,...,\polynumcorners} {%
            (pn@\polynumcorner @1@0) edge[/polynum/bar path/.try, /polynum/every bar/.try] (pn@\polynumcorner @\polynum@levels @0)}}
        ]
      }
    }
  }
}
\makeatother
\polynumset{bars}
\newcommand*\polynum[4][1]{%
  \foreach \sides in {#3,...,#4}{%
    \begin{tikzpicture}[scale=#1,/polynum/levels=#2]
      \path [/tikz/rotate=360/\sides/2,polynum={sides=\sides}];
    \end{tikzpicture}
  }
 \caption{Illustration of the polygonal numbers~$f_{#3}(#2)$--$f_{#4}(#2)$.}
}

\pagestyle{empty}

\begin{document}

\begin{figure}[htbp]
 \centering
  \polynum[1.5]{5}{3}{8}
\end{figure}

\end{document}
share|improve this question
    
You want this exact representation? There are others. –  Werner Aug 11 '13 at 18:46
    
@Werner Yes, please. :) Then I can also use the intuitive proof on mathandmultimedia.com/2012/08/01/polygonal-number-formula in my notes. (See also update.) –  Svend Tveskæg Aug 11 '13 at 18:48
    
When you have a two-argument macro simply do {1,...,#2} in the loop and \path [polynum={/tikz/rotate=360/\sides/2,levels=#1,sides=\sides}];. Then you can do \polygonnumbers{5}{6} which creates diagrams with 3, 4, 5 and 6 corners and 5 levels which is your question’s examples including the triangles. –  Qrrbrbirlbel Aug 12 '13 at 2:21
    
@Qrrbrbirlbel See third update. :( –  Svend Tveskæg Aug 12 '13 at 2:50
    
Ah, yes. I see the problem. The \pgfkeysvalueof{/polynum/levels} that draws the blue bars expands to the initial value and not the set value. This can be resolved by setting /polynum/levels as an option to the tikzpicture (instead of the path) or by implementing the bar-drawing in it. Let me update my answer in a bit which does this (if I get it to work). –  Qrrbrbirlbel Aug 12 '13 at 2:57

3 Answers 3

up vote 14 down vote accepted

Here is a solution using TikZ.

There exist a few keys that change the graphics parameter:

  • sides: the number of sides/corners in the polygon;
  • level: the number of repetitions of the polygon;
  • side length: the length of one side of the polygon;
  • for the “bars”:
    • x padding and
    • y padding as well as
    • the switch bars that can be used to turn off/on the drawing of the bars.

The polygon is drawn with the center node at the point where the path currently is where you use the polynum key. The “polynum” can be rotated by rotating the path. The polygons stand on their center corner if you rotate the path about 360/<corners>/2.

The bar is drawn with an active rotation in mind (that is the reason for the \pgfpointshapeborder), this makes it possible to include the nodes as they are without the need to rotate them or to use transform shape. The bar-drawing algorithm though will create a bad result if the nodes are not of the same size.

The macros

  • \polynumcorner,
  • \polynumlevel,
  • \polynumsublevel and
  • \polynumcorners (i.e. the total number of corners)

can be used to affect the styles, this is used inside the every corner edge style (actually a .code key) that turns the drawing of the edge between certain corner nodes explicitly off.

The nodes are named: pn@<corner>@<level>@<sublevel>. The red center node is named pn@0@1@0, it is the only 0th corner node.

Code

\documentclass[tikz,png={size=315,density=600},convert=false]{standalone}
\pgfkeys{% http://tex.stackexchange.com/a/125700/16595
  /handlers/.tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.code=\tikzset{#1}},%
  /handlers/.append tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.append code=\tikzset{#1}},%
  /handlers/.prefix tikz/.code=\pgfkeys{\pgfkeyscurrentpath/.prefix code=\tikzset{#1}}}
\def\polynumset{\pgfqkeys{/polynum}}
\newif\ifpolynumbars
\polynumset{
  sides/.initial=4,
  levels/.initial=5,
  side length/.initial=+.5cm,
  x padding/.initial=+2pt,
  y padding/.initial=+2pt,
  bars/.is if=polynumbars,
  every bar/.tikz={draw=blue, thick, rounded corners=+1pt},
  %
  every node/.tikz={shape=circle,draw,inner sep=+0pt,minimum size=+4pt},
  center node/.tikz={fill=red},
  level nodes/.tikz={fill=blue},
  sublevel nodes/.tikz={fill=yellow},
  %
  every edge/.tikz={},
  %
  every corner edge/.code={
    \ifnum\polynumcorner>1\relax
      \ifnum\polynumcorner<\polynumcorners\relax
        \tikzset{draw=none}
      \fi
    \fi
  },
}
\makeatletter
\def\polynumutil@firstofone#1{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@firstoftwo#1#2{\tikz@scan@next@command#1\pgf@stop}
\def\polynumutil@secondoftwo#1#2{\tikz@scan@next@command#2\pgf@stop}
\polynumset{
  bar path/.style={
    to path={
      [/utils/exec=%
         \pgfmathanglebetweenpoints{\pgfpointanchor{\tikztostart} {center}}
                                   {\pgfpointanchor{\tikztotarget}{center}}%
         \let\polynum@a\pgfmathresult
         \pgftransformrotate{\polynum@a}%
         \pgfpointdiff{\pgfpointanchor{\tikztostart}{center}}
                      {\pgfpointshapeborder{\tikztostart}{\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}{\pgfpointpolar{90}{1pt}}}}%
         \pgfmathveclen{\pgf@x}{\pgf@y}%
         \edef\polynum@ydistance{\pgfmathresult pt}%
         \pgfcoordinate{pn@aux1}
                       {\pgfpointshapeborder
                         {\tikztostart}
                         {\pgfpointadd{\pgfpointanchor{\tikztostart}{center}}
                                      {\pgfpointpolar{180}{1pt}}}}%
         \pgfcoordinate{pn@aux2}
                       {\pgfpointshapeborder
                         {\tikztotarget}
                         {\pgfpointadd{\pgfpointanchor{\tikztotarget}{center}}
                                      {\pgfpointpolar{0}{1pt}}}}%
       ]
             ([shift=(left:\pgfkeysvalueof{/polynum/x padding})]pn@aux1) coordinate (pn@aux)
       -- ++ (up:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})
       -|    ([shift=(right:\pgfkeysvalueof{/polynum/x padding})] pn@aux2)
       |-    ([shift=(down:\polynum@ydistance+\pgfkeysvalueof{/polynum/y padding})] pn@aux)
       -- cycle
    }
  }}
\tikzset{
  polynum/.default=,
  polynum/.style={
    insert path={
      node[/polynum/every node/.try, /polynum/inner nodes/.try, /polynum/center node/.try] (pn@0@1@0) {}
      { [/polynum/.cd,#1]
        [/utils/exec=%
          \pgfmathtruncatemacro\polynumcorners{\pgfkeysvalueof{/polynum/sides}-1}%
          \pgfmathtruncatemacro\polynum@levels{\pgfkeysvalueof{/polynum/levels}}%
          \pgfmathsetlengthmacro\polynum@sidelength{\pgfkeysvalueof{/polynum/side length}}%
          \pgfmathsetmacro\polynum@angle{360/(\the\numexpr\polynumcorners+1\relax)}%
        ]
        \foreach \polynumcorner[evaluate={\polynum@@angle={(\polynumcorner-1)*\polynum@angle}}] in {1,...,\polynumcorners} {
          % get to the next corner,
          % level 1
          ++ (\polynum@@angle:\polynum@sidelength)
            node[/polynum/every node/.try, /polynum/level nodes/.try, /polynum/level 1 nodes/.try] (pn@\polynumcorner @1@0) {}
          % last level
          [/utils/exec={%
            \ifnum\polynumcorner=1\relax
              \expandafter\polynumutil@firstoftwo
            \else
              \expandafter\polynumutil@secondoftwo
            \fi
              {+(\polynum@@angle:\the\numexpr\polynum@levels-1\relax*\polynum@sidelength)}
              {   (pn@\the\numexpr\polynumcorner-1\relax @\polynum@levels @0.center)
               ++ (\polynum@@angle:\polynum@levels*\polynum@sidelength)}}]
          % it's only a coordinate because it is used to place everything else
          % including the node at the exact same position
          node[shape=coordinate, alias=pn@\polynumcorner @last] (pn@\polynumcorner @\polynum@levels @0) {}
          % all other levels
          \foreach \polynumlevel[count=\polynum@level from 1, evaluate={\polynum@pos=\polynum@level/\the\numexpr\polynum@levels-1\relax}] in {2,...,\polynum@levels} {
            (pn@\polynumcorner @1@0.center)
              edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/level nodes/.try, style/.expanded={/polynum/level \polynumlevel\space nodes/.try}] (pn@\polynumcorner @\polynumlevel @0) {}
            (pn@\polynumcorner @last.center)
            % the edges between the corner nodes (blue -- blue)
            (pn@\polynumcorner @\the\numexpr\polynumlevel-1\relax @0) edge[/polynum/every edge/.try, /polynum/every corner edge/.try] (pn@\polynumcorner @\polynumlevel @0)
            % now the sublevels (except for the first corner because it has no previous corner)
            [/utils/exec={%
              \ifnum\polynumcorner>1\relax
                \expandafter\polynumutil@firstofone
              \else
                \expandafter\pgfutil@gobble
              \fi
              {\foreach \polynumsublevel[evaluate={\polynum@pos=\polynumsublevel/\polynumlevel}] in {1,...,\the\numexpr\polynumlevel-1\relax}{
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @0.center)
                   edge[draw=none] node[pos=\polynum@pos, /polynum/every node/.try, /polynum/sublevel nodes/.try, style/.expanded={/polynum/sublevel \polynumsublevel\space nodes/.try}] (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel) {}
                 (pn@\polynumcorner @\polynumlevel @0.center)
                 % the edges between sublevel nodes (blue -- yellow and yellow -- yellow)
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumsublevel-1\relax)
                   edge[/polynum/every edge/.try]
                 (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\polynumsublevel)
               }
               % the edge between the last sublevel node and the next corner node (yellow -- blue)
               (pn@\the\numexpr\polynumcorner-1\relax @\polynumlevel @\the\numexpr\polynumlevel-1\relax)
                 edge[/polynum/every edge/.try]
               (pn@\polynumcorner @\polynumlevel @0)
              }}]
          }
          % the edges between corner nodes (level 1, the smallest polygon: red -- blue and blue -- blue)
           (pn@\the\numexpr\polynumcorner-1\relax @1@0) edge[/polynum/every edge/.try] (pn@\polynumcorner @1@0)
           (pn@\polynumcorner @1@0.center)
        }
        % the last edge (blue -- red)
        (pn@\polynumcorners @1@0) edge[/polynum/every edge/.try] (pn@0@1@0)
        % the bars are drawn in an extra loop to make sure they are on top
        [/utils/exec=%
          \ifpolynumbars\expandafter\polynumutil@firstofone\else\expandafter\pgfutil@gobble\fi
            {\foreach \polynumcorner in {1,...,\polynumcorners} {
            (pn@\polynumcorner @1@0) edge[/polynum/bar path/.try, /polynum/every bar/.try] (pn@\polynumcorner @\polynum@levels @0)}}
        ]
      }
    }
  }
}
\makeatother
\polynumset{bars}
\begin{document}
\foreach \sides in {3,...,6}{
\begin{tikzpicture}[/polynum/levels=3]
\path [polynum={/tikz/rotate=360/\sides/2,sides=\sides}];
\end{tikzpicture}}
\foreach \level in {2,...,5,5,4,3,2}{
\begin{tikzpicture}
\path [polynum={levels=\level}];
\useasboundingbox (-8pt,-8pt) rectangle (2.5cm+8pt,2.5cm+8pt);
\end{tikzpicture}}
\end{document}

Output

enter image description hereenter image description hereenter image description hereenter image description herePicture for <code>sides=7</code>enter image description here

share|improve this answer
    
Really nice. Any change I can make you (1) draw the bars around the blue dots and (2) connect the dots as on the picture, too? –  Svend Tveskæg Aug 11 '13 at 22:10
    
Furthermore, I would like to control the distance between the triangle figure and the square figure and so on; not bewteen the individual triangles and so on. –  Svend Tveskæg Aug 11 '13 at 22:17
    
@SvendTveskæg I have updated my answer with a revised version of the polynum key. The loops are now more efficient. The edges are all drawn with the every edge style. The edges in the blue bars also use the style every corner edge where it is checked whether it is the first or the last corner. One could add similar to the nodes edge styles for different corners/levels/sublevels. But it doesn’t look like that is needed so I left it out. Can you elaborate on your last comment? The only length input is the side length. Everything else is up to you: placement, position, rotation. –  Qrrbrbirlbel Aug 12 '13 at 0:02
    
Seriously nice! Never mind the last comment. ;) Assume I want to change levels/.initial to something != 5. Can the length of the bars be set automatically to the value of levels/.initial? –  Svend Tveskæg Aug 12 '13 at 0:27
1  
@texenthusiast Okay; sorry. I'll do that from now on. –  Svend Tveskæg Aug 12 '13 at 17:38

enter image description here

This solution is based on the object-oriented feature of the Asymptote. The basic structure struct PolygonalNumber is defined in asydef environment, and can be used later in asy pictures to create and draw objects of this kind. For example, a triangular object named P3 with 5 layers is defined as PolygonalNumber P3=PolygonalNumber(3,5); and command draw(P3); will draw it. PolygonalNumber objects can be transformed as usual, for example draw(shift(6,0)*P4); draws a P4 object shifted to the right. Or they can be used directly in the draw commands: the code to produce the image above was just

size(400);
for(int i=3;i<=7;++i){
  draw(shift((i-3)*(5+i-3),0)*PolygonalNumber(i,5));
};

A complete MWE polynum.tex:

\documentclass{article}
\usepackage[inline]{asymptote}
\begin{asydef}
struct PolygonalNumber{
  int n,m;
  real unitStep;
  real boxW;
  transform t;
  pair O=(0,0);
  pair[][] dots;

  pen originPen=red;
  pen sideLinePen=darkblue;
  pen cornerDotPen=blue;
  pen sideDotPen=orange;
  pen boxPen=blue;

  void drawSides(){
    guide g; 
    pair center,p;
    pair[] skin;    
    for(int i=1;i<=m;++i){
      p=(i*unitStep,0);
      g=O;
      center=i*unitStep/2*(1,1/Tan(180/n));
      for(int j=0;j<n-1;++j){
        g=g--(rotate(j*360.0/n,center)*p);
      }
      g=g--cycle;
      draw(t*g,sideLinePen);
      skin=new pair[];      
      for(int j=0;j<size(g);++j){
        skin.push(point(g,j));  
      }
      dots.push(skin);
    }
  }

  void drawCornerDots(){
    for(int i=0;i<dots.length;++i){
      for(int j=1;j<dots[i].length;++j){
        dot(t*dots[i][j],cornerDotPen);
      }
    }
  }

  void drawSideDots(){
    pair p,q;
    real s;
    for(int i=1;i<dots.length;++i){
      for(int j=1;j<dots[i].length-1;++j){
        p=dots[i][j];
        q=dots[i][j+1];
        for(int k=1;k<i+1;++k){
          s=k/(i+1);
          dot(t*(p*(1-s)+q*s),sideDotPen);
        }  
      }
    }
  }

  void drawOriginDots(){
    for(int i=0;i<dots.length;++i){
      dot(t*O,originPen);      
    }    
  }

  guide buildBox(pair a, pair b){
    pair d,p,q,ds;
    d=dir(b-a);
    ds=boxW*d;
    p=a-ds; q=b+ds; 
    guide[] g=strokepath(p--q,red+boxW);
    return g[0];
  }

  void drawBoxes(){
    pair a,b;
    for(int j=1;j<n;++j){
      a=dots[0][j];
      b=dots[m-1][j];
      draw(t*buildBox(a,b),boxPen);      
    }
  }

  void draw(){
    drawSides();
    drawCornerDots();
    drawSideDots();
    drawOriginDots();
    drawBoxes();
  }

  void operator init(int n=3,int m=6,real unitStep=1,transform t=identity(),real boxW=0.4){
    assert(n>2 && m>0);
    this.n=n; this.m=m; 
    this.unitStep=unitStep;
    this.boxW=boxW;
    this.t=t;
  }
}
PolygonalNumber operator*(transform t=identity(),PolygonalNumber p){p.t=t; return p;}; 
void draw(PolygonalNumber p){p.draw();};
\end{asydef}

\begin{document}
\begin{figure}
\begin{asy}
size(400);
for(int i=3;i<=7;++i){
  draw(shift((i-3)*(5+i-3),0)*PolygonalNumber(i,5));
};
\end{asy}
\end{figure}
\end{document}

To process it with latexmk, create file latexmkrc:

sub asy {return system("asy '$_[0]'");}
add_cus_dep("asy","eps",0,"asy");
add_cus_dep("asy","pdf",0,"asy");
add_cus_dep("asy","tex",0,"asy");

and run latexmk -pdf polynum.tex.

share|improve this answer
    
Really cool! Thank you for the solution. –  Svend Tveskæg Aug 12 '13 at 5:17

I started with this but then I got bored :) Always nice to steal Jake's ncbarfrom Is there a TikZ equivalent to the PSTricks \ncbar command?

\numofsides and \numofiters define the polygon shape and how many times it is repeated. I don't have Qrrbrbirlbel's patience. So it's just for fun.

\documentclass[tikz,border=4mm]{standalone}
\usetikzlibrary{calc,shapes.geometric,backgrounds}
\begin{document}
\tikzset{
    ncbar angle/.initial=90,
    ncbar/.style={to path=(\tikztostart)--($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
        -- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
        -- (\tikztotarget)},
    ncbar/.default=0.5cm,
}
\begin{tikzpicture}[
bluedot/.style={circle,fill=blue,draw,inner sep=0,minimum size=3pt,anchor=center},
yellowdot/.style={bluedot,fill=yellow},
]
\def\numofsides{10} %Change these
\def\numofiters{10} %Change these
\foreach \x in {1,...,\numofiters}{
\begin{scope}[on background layer]\node[rotate={floor(\numofsides/2)*360/\numofsides}, 
      inner sep=0,anchor=corner 1,
      draw,minimum size=\x*8mm,
      blue,regular polygon,regular polygon sides=\numofsides] (n\x) {};\end{scope}
    \foreach \y[count=\yi,count=\yj from 0,remember=\y as \lasty] in {corner 2,corner 3,corner ...,corner \numofsides} {
    \node[bluedot,rotate={((1-(1-(2/\numofsides)))*90)*\yj-90}] (n\x c\yi) at (n\x.\y) {};
    \ifnum\x>1\ifnum\yi>1\foreach\z in{1,...,\numexpr\x-1\relax}{
        \node[yellowdot] at ($(n\x.\lasty)!\z/\x!(n\x.\y)$){};}\fi\fi
    }
}
\foreach \x[count=\xi from 0] in {1,...,\numexpr\numofsides-1}{
\pgfmathsetmacro\myangle{((1-(1-(2/\numofsides)))*90)*\xi+180}
\draw[rounded corners=1pt,blue] ([shift={(\myangle:1pt)}]n1c\x.south) to[ncbar=2pt] 
                           ([shift={(\myangle:-1pt)}]n\numofiters c\x.north) to[ncbar=2pt]
                           ([shift={(\myangle:1pt)}]n1c\x.south);
}

\end{tikzpicture}

\end{document}

A truly ridiculous image

enter image description here

With \def\numofsides{24} and \def\numofiters{24}:

output

Awesome! :)

share|improve this answer
    
Dammit, I forgot the red node at the corner. –  percusse Aug 12 '13 at 21:12
    
Nice drawing! :) –  Svend Tveskæg Aug 12 '13 at 21:15
    
@SvendTveskæg Try 20,20 it gets weirder :) –  percusse Aug 12 '13 at 21:21
    
See update to your post. :) –  Svend Tveskæg Aug 12 '13 at 22:19
    
Come to think of it; can I make you draw the red dot too? Your example is useful if only a single type of number is required. –  Svend Tveskæg Aug 13 '13 at 0:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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