11

I want to create the following tikz images:

enter image description here

For now, I've just copy and pasted variations of the code below:

\begin{tikzpicture}[scale=0.5]
     \tikzstyle{vertex}=[circle,draw,minimum size=10pt,inner sep=0pt]
      \node[vertex] (S-8) at (1.34,-2.98) [minimum size=15pt, fill=white] {$*1$};
      \node[vertex] (S-9) at (1.34,-1.34) [minimum size=15pt, fill=gray] {};
      \node[vertex] (S-10) at (2.98,-1.34) [minimum size=15pt, fill=gray] {};
      \node[vertex] (S-11) at (4.61,-1.34) [minimum size=15pt, fill=gray] {};
      \node[vertex] (S-12) at (4.61,-2.98) [minimum size=15pt, fill=white] {$*1$};
      \node[vertex] (S-13) at (4.61,-4.61) [minimum size=5pt, fill=white] {};
      \node[vertex] (S-14) at (2.98,-4.61) [minimum size=5pt, fill=white, label={-90: \Large $0$}] {};
      \node[vertex] (S-15) at (1.34,-4.61) [minimum size=5pt, fill=white] {};
    
    \draw (S-8) -- (S-9);\draw (S-8) -- (S-15);\draw (S-9) -- (S-8);\draw (S-9) -- (S-10);\draw (S-10) -- (S-9);\draw (S-10) -- (S-11);\draw (S-11) -- (S-10);\draw (S-11) -- (S-12);\draw (S-12) -- (S-11);\draw (S-12) -- (S-13);\draw (S-13) -- (S-12);\draw (S-13) -- (S-14);\draw (S-14) -- (S-13);\draw (S-14) -- (S-15);\draw (S-15) -- (S-8);\draw (S-15) -- (S-14);
\end{tikzpicture}

It works, but there has to be a more elegant solution so I can make more of these pictures.

2
  • 9
    Welcome to TeX.SX! \tikzstyle is deprecated, use \tikzset instead. You could make your drawing a \pic or just a regular custom command with arguments to change the relevant parts of the drawing. Commented May 13, 2025 at 5:51
  • 1
    Or you could just use a \for each loop if you need them in the one picture. Commented May 13, 2025 at 6:16

2 Answers 2

12

There are, as always, many ways to skin a cat. The first thing is to decide what kind of logic you want.

Here, I create a newcommand that draws a square with eight vertices, and your chosen caption text, like this:

enter image description here

In this approach, the command eightbox takes as an argument a label prefix, e.g. n1, and the vertices are labelled n1-\i, starting at 1 at the bottom left and going anticlockwise. This numbering is what you need to know which ones to colour and label.

We can then use a list and foreach to colour over the chosen gray nodes. Finally, we write over the labelled nodes. I've done three of your boxes in this way.

The three styles (empty vertex, gray node, labelled vertex) are all set at the beginning. You can of course adjust the styling to get the sizes etc how you like them. You can also adjust the styling/size of the square in the eightbox... etc.

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,decorations.markings}

\tikzset{vertex/.style={circle,draw,minimum size=5pt,fill=white,inner sep=0pt},
  grayvertex/.style={circle,draw,minimum size=10pt,fill=gray,inner sep=0pt},
  vlabel/.style={circle,draw,minimum size=10pt,fill=white,inner sep=0pt},
}
  
\newcommand{\eightbox}[3][(0,0)]{% arguments #1 the centre coordinate (optional),
%                                           % #2 a prefix for the node labels,
%                                           % #3 the caption on this box
\node[draw, minimum size = 1.64cm,
  postaction=decorate,
    decoration={
      name=markings,
      mark=between positions 0 and 1-1/8 step 1/8 with {
        \pgfkeysgetvalue{/pgf/decoration/mark info/sequence number}{\i}
        \node[vertex] ({#2-\i}) {};}}
    ] at #1 (S) {}; % the square, with eight nodes; see https://tex.stackexchange.com/questions/740598/place-equally-spaced-nodes-on-general-pgf-path
    \node[below=0.2cm of #2-2]
    {{#3}};
}
\begin{document}

\begin{tikzpicture}
  \eightbox{def}{basic}
\end{tikzpicture}
\vspace{0.5cm}
\hrule
\vspace{0.5cm}
     
\begin{tikzpicture}
%% the first one
\eightbox{n1}{0}
\def\graynodes{1,2,3,4,5,6,7,8}
\foreach \n  in \graynodes{
   \node[grayvertex] at ({n1-\n}) {};
 }
%% the second one
\eightbox[(3,0)]{n2}{1}
\def\graynodes{1,3,4,5,6,7,8}
\foreach \n  in \graynodes{
   \node[grayvertex] at ({n2-\n}) {};
 }]
 \node[vlabel] at (n2-2) {$*1$};
 %% first one on second row
 \eightbox[(0,-3)]{n4}{1}
\def\graynodes{5,6,7}
\foreach \n  in \graynodes{
   \node[grayvertex] at ({n4-\n}) {};
 }]
\node[vlabel] at (n4-4) {$*1$};
\node[vlabel] at (n4-8) {$*1$};
\end{tikzpicture}

\end{document}
11

Here's a more systematic approach to move from special case to generalization:

  • understanding building blocks
  • draw one specific case
  • generalize
  • outlook

Understanding building blocks

buildingblocks

5 thingies need to be provided:

  • a rectangle (with coordinates)
  • gray circles
  • white circles with content
  • small white circle

Draw one specific case

Let's pick the lower middle one (green), as it provides all needed. Here's the code, with some residual hick-ups, and 3 parameters to pass marked:

\documentclass[10pt,border=0mm,tikz]{standalone}

\begin{document}
 % ~~~ creating 1 specific drawing ~~~~~~
 
 
 \tikzset{
    smallc/.style=  {draw, circle, fill=white,minimum size=5pt},
    grayc/.style=   {draw, circle, fill=gray, minimum size=15pt},
    whitec/.style=  {grayc, fill=white},
 }
 
 \begin{tikzpicture} 
    % ~~~ rectangle ~~~~~~~~~
    \draw (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle;
    
    % ~~~ doing a little more: flood with small circles ~~~
    \foreach \i in {0,1,2}{
        \node[smallc] at (\i,0) {};
        \node[smallc] at (\i,2) {};
    }
    \foreach \i in {0,2}{
        \node[smallc] at (\i,1) {};
    }
    
    % ~~~ drawing the gray nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j in {0/2, 1/2, 2/1}           % <<< 1
        \node[grayc] at (\i,\j) {};
        
    % ~~~ drawing the white nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j/\c in {2/2/$0$, 0/1/$*1$}    % <<< 2
        \node[whitec] at (\i,\j) {\c};
        
    % ~~~ label ~~~~~~~~~~
    \node at (1,-.5) {$*k$};                    % <<< 3
 
 \end{tikzpicture}
\end{document}

step1

Generalize

To do:

  • \newcommand\variant[3]
  • provide 2 test cases

For the newcommand you simply move your code AND replace by \variant{}{}{} in the body. Filling in at least two variants of those lists should show differences.

To put two \variant calls side by side, I used a scope environment, which is shifted AND scaled AND transform shaped. See Chapter "17.7 Transformations" in the manual.

From the various options to reconcile the different circle sizes when content is entered, I opted for simply enlarging them all (gray and white).

% ~~~ REFACTORING ~~~~~~~~~~~~~~~~~~~~~~~~~~~
%  1. moving tikz-code into macro \variant
%  2. using scope environment to test two AND generalize
%  3. generalizing styles AND enlarging circles


\documentclass[10pt,border=0mm,tikz]{standalone}

 \tikzset{
    crc/.style=     {draw, circle},
    smallc/.style=  {crc, fill=white,minimum size=5pt},
    grayc/.style=   {crc, fill=gray, minimum size=20pt},
    whitec/.style=  {grayc, fill=white},
 }
 
 \newcommand\variant[3]{
    % ~~~ rectangle ~~~~~~~~~
    \draw (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle;
    
    % ~~~ doing a little more: flood with small circles ~~~
    \foreach \i in {0,1,2}{
        \node[smallc] at (\i,0) {};
        \node[smallc] at (\i,2) {};
    }
    \foreach \i in {0,2}{
        \node[smallc] at (\i,1) {};
    }
    
    % ~~~ drawing the gray nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j in {#1}          % <<< 1 generalized
        \node[grayc] at (\i,\j) {};
        
    % ~~~ drawing the white nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j/\c in {#2}       % <<< 2 generalized
        \node[whitec] at (\i,\j) {\c};
        
    % ~~~ label ~~~~~~~~~~
    \node at (1,-.5) {#3};          % <<< 3  generalized
 }

% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{document}
 % ~~~ creating 1 specific drawing ~~~~~~
   
 \begin{tikzpicture} 
    \variant{0/2, 1/2, 2/1}
            {2/2/$0$, 0/1/$*1$}
            {$*k$}
    
    \begin{scope}[xshift=3cm,scale=.5, transform shape] % to test two
        \variant{0/2, 2/1}
                {2/2/$0$, 2/0/$*k$}
                {$0$}
    \end{scope}
 \end{tikzpicture}
\end{document}

step2

BTW, you could already outsource \tikzset and \variant into an external file, and \input or \usepackage it. This makes your main code more readable, and opens the path to creating an own library on this subject, if needed.

Outlook

You can already replicate your 6 drawings by now, using a few more scopes.

However, a more versatile next step could be to encapsulate \variant in a \pic element, which accepts said 3 parameters. Though it's not difficult to do, it obscures code, especially for Tikz-novices.

However, if you did, you could simply place a number of \pic statements wherever you like.

Why using standalone, and how to go from there, have a look e.g. here.

P.S.

Here's the simplified code in main.tex:

% ~~~ REFACTORING ~~~~~~~~~~~~~~~~~~~~~~~~~~~
%  1. moving tikz-code into macro \variant
%  2. using scope environment to test two AND generalize
%  3. generalizing styles AND enlarging circles
%  4. moved preamble into variant.sty

\documentclass[10pt,border=0mm,tikz]{standalone}

\usepackage{variant}

% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{document}
 % ~~~ creating 1 specific drawing ~~~~~~
   
 \begin{tikzpicture} 
    \variant{0/2, 1/2, 2/1}
            {2/2/$0$, 0/1/$*1$}
            {$*k$}
    
    \begin{scope}[xshift=3cm,scale=.5, transform shape] % to test two
        \variant{0/2, 2/1}
                {2/2/$0$, 2/0/$*k$}
                {$0$}
    \end{scope}
 \end{tikzpicture}
\end{document}

which compiles once you provide variant.sty in the same folder/directory:

 \tikzset{
    crc/.style=     {draw, circle},
    smallc/.style=  {crc, fill=white,minimum size=5pt},
    grayc/.style=   {crc, fill=gray, minimum size=20pt},
    whitec/.style=  {grayc, fill=white},
 }
 
 \newcommand\variant[3]{
    % ~~~ rectangle ~~~~~~~~~
    \draw (0,0) -- (2,0) -- (2,2) -- (0,2) -- cycle;
    
    % ~~~ doing a little more: flood with small circles ~~~
    \foreach \i in {0,1,2}{
        \node[smallc] at (\i,0) {};
        \node[smallc] at (\i,2) {};
    }
    \foreach \i in {0,2}{
        \node[smallc] at (\i,1) {};
    }
    
    % ~~~ drawing the gray nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j in {#1}          % <<< 1 generalized
        \node[grayc] at (\i,\j) {};
        
    % ~~~ drawing the white nodes (over white small circles) ~~~~~~~~~
    \foreach \i/\j/\c in {#2}       % <<< 2 generalized
        \node[whitec] at (\i,\j) {\c};
        
    % ~~~ label ~~~~~~~~~~
    \node at (1,-.5) {#3};          % <<< 3  generalized
 }

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.