[Tex/LaTex] Tikz Nodes Positions and Shapes with a General Number of Nodes

tikz-pgftikz-styles

My purpose is rather simple: use tikzpictures to draw tables of numbers, where the numbers are drawn inside colored boxes with fancy shapes, with different shapes and colors for different numbers. Below I boxed numbers according to whether they were odd, even, or prime (and treated 1 as a special number).

The idea is to use the colors and shapes to spot patterns. My original plan was to use this to teach prime numbers, but I have since thought of other things that could be fun to do.

As I'm new to tikz (a few days on it only), there are still some basic things that are eluding me. Here are the improvements and alterations I'd like to make on the basic table displayed below.

  1. Resize the shapes to approximately the same "size"

    There are several interpretations of what that might mean, any reasonable one will be fine. Right now, the boxes adapt to the size of the numbers, with single-digit numbers having small boxes, two-digit numbers larger boxes, and three-digit numbers even larger. I'd like the numbers to shrink rather than the boxes. You can also see that I had trouble getting the star shape to align with the other shapes. I did fool around with anchor, inner sep and outer sep, but that's all I know of at this time.

  2. Control the direction in which the numbers are running

I am asking this as a separate question, by popular demand: Tikz Nodes Order and Shapes with a General Number of Nodes

To be clear, I will be generating tables of different sizes, some with 10 numbers, some with 100 numbers, possibly more, some with longer rows, some with longer columns, and I'd like the shapes to resize automatically and proportionately.

I haven't thought through the choice of shapes and colors, it's a first pass. Feel free to beautify 😉

This is the code so far:

\RequirePackage[svgnames,x11names]{xcolor}
\documentclass[tikz,convert=false,margin=0pt]{standalone}%
\usetikzlibrary{shapes.geometric}% polygon, ellipse, star, diamond, etc.
\usepackage{tkz-euclide}% \pgfmathisprime command
\usepackage{rotating}% sideways environment

\begin{document}%
\begin{tikzpicture}[%
  every node/.style = {
    shape = circle
    , align = center
    , scale = 2
    , anchor = base
    , font = \fontfamily{pzc}\selectfont% common font
  } ,
  % Prime Numbers
  PrimeStyle/.style = {
    regular polygon
    , regular polygon sides = 3
    , rounded corners = .5em
    , inner sep = 0pt 
    , outer sep = 0pt
    , draw = DarkGreen, thick
    , fill = green!70!black
    , text = white
  } ,
  % Even Numbers 
  EvenStyle/.style = {
    shape = circle
    , inner sep = 2pt
    , draw = DarkRed, thick
    , fill = red!70!black
    , text = white
  } ,
  % Non-Prime Odd Numbers
  OddStyle/.style = {
    shape = diamond
    , rounded corners = .5em
    , inner sep = 1pt
    , draw = DarkBlue, thick
    , fill = blue!70!black
    , text = white
  } , 
  % Number One
  OneStyle/.style = {
    shape = star
    , rounded corners = .5em
    , inner sep = 2pt
    , scale = 0.9
    , draw = white!70!black, thick
    , fill = blue!50!green!50!
    , text = black
  }
]%
%
  % Set Grid Dimensions 
  \newcommand{\xa}{1}
  \newcommand{\xb}{10}
  \newcommand{\ya}{1}
  \newcommand{\yb}{10}
  \pgfmathsetmacro{\yc}{\yb-1}% \yb minus one
% 
  % Change styles of numbers according to set membership
  \foreach \x in {\xa,...,\xb}
    \foreach \y in {\ya,...,\yb} 
       {\pgfmathtruncatemacro{\label}{\x - \xb * (\y - \yb) }
         \pgfmathparse{int(mod(\label,2))}
         \let \r \pgfmathresult
         \ifnum \r = 1
           \tikzset{EvenStyle/.style = {OddStyle}}
         \fi
         \pgfmathisprime{int(\label)}
         \let \s \pgfmathresult
         \ifnum \s = 1
           \tikzset{EvenStyle/.style = {PrimeStyle}}
         \fi
         \pgfmathparse{int(\label)}
         \let \t \pgfmathresult
         \ifnum \t = 1
           \tikzset{EvenStyle/.style = {OneStyle}}
         \fi
         \node [EvenStyle]  (\x\y) at (1.5*\x, -1.5*\y) {\label};} 
  \foreach \x in {\xa,...,\xb}
    \foreach \y [count = \yi] in {\ya,...,\yc}
      \draw (\x\y)(\x\yi) (\y\x)(\yi\x) ;
\end{tikzpicture}%
\end{document}%

% doesn't work, why?
% \foreach \k in {1,2,3,5,7,11,13}
%  \tikzset{EvenStyle/.style = {PrimeStyle}} ;

This is the immediate predecessor to this question:
Looking for Elegance and Convenience in Code with Many Numbers
where Harish Kumar showed me how to write general code using foreach loops.

This is where I learned of a slightly different way of defining the grid:
Selecting specific nodes and changing style (for those nodes)

This is where I learned about the \pgfmathisprime command from the tikz-euler package:
How to produce a list of prime numbers in LaTeX

Here I saw one of several examples where I learned how to use ifnum with int and mod and \pgfmathparse :
How to use mod operation in latex with tikz

enter image description here

Best Answer

I'm not sure if it's answering all your questions, but I think the following (although not perfect) shows some ways in which your code could be simplified. I think there will always be some manual adjustment involved though (e.g., setting appropriate inner sep).

\documentclass[tikz,border=0.125cm]{standalone}
\usetikzlibrary{shapes.geometric}
\begin{document}
\tikzset{%
  set color/.style={
    fill=#1,
    draw=#1!50!black
  },
  every number/.style={
    text=white,
    rounded corners=0.125cm,
    font=\fontfamily{pzc}\selectfont,
    text width=3ex,
    align=center,
    scale=2
  },
  every prime number/.style={
    shape=diamond,
    set color=blue!70!black,
    inner sep=0.25ex,
  },
  every even number/.style={
    shape=circle,
    set color=red!70!black,
    inner sep=0.5ex
  },
  every odd number/.style={
    shape=regular polygon,
    regular polygon sides=3,
    set color=green!70!black,
    inner sep=-0.375ex
  },
  number 1/.style={
    shape=star,
    set color=green!50!blue,
    inner sep=-.25ex
  }
}%
\begin{tikzpicture}[x=2cm, y=2cm]
\foreach \n [evaluate={%
    \x=mod(\n-1,10); 
    \y=floor((\n-1)/10);
    \p=isprime(\n);
    \e=mod(\n,2)==0;
    \style=(\p || \n==2) ? "prime" : (\e ? "even" : "odd");}] in {1,...,100}
  \node [every number/.try, every \style\space number/.try, number \n/.try]
     at (\x,\y) {\n};
\end{tikzpicture}

\end{document}

enter image description here