4

I’m attempting to define a command to build several similar tikz nodes. These nodes differ only by one parameter (#2 below). Here are the main questions I’ve referenced so far:

I feel like I’m so close, but I have no idea where to go beyond what I’ve detailed below. The left part of this diagram is pretty much the expected result:

Expected result

Here’s the current command definition:

\documentclass[11pt,a4paper]{article}

\usepackage{siunitx}
\usepackage{tikz}
\usepackage{xparse}

\begin{document}

\tikzstyle{ht_num} = [draw, semithick]
\tikzstyle{ht_hash} = [draw, semithick, minimum width=2em]

\NewDocumentCommand \HashTable { m m } {%
    \def\MatrixContent{\empty}
    \pgfmathtruncatemacro\nn{2^#2-1}
    \foreach \n in {0,...,\nn}{%
        \edef\MatrixContent{\unexpanded\expandafter{\MatrixContent}\unexpanded\expandafter{%
            \node[ht_hash] (#1-\n) {\num[minimum-integer-digits=#2]{\pgfmathbin{\n}\pgfmathresult}}; \\
        }}
    }

    \matrix [outer sep=0pt,every node/.style={anchor=west}] (#1) {
        \node[ht_num] (#1-a) {#2}; \\
        \MatrixContent
    };
}

\begin{tikzpicture}
    \HashTable{table1}{2}
    % Other tikz nodes...
\end{tikzpicture}

\end{document}

And finally, the error message:

./Diagrams.tex:398: Missing } inserted.
<inserted text> 
                }
l.398 ^^I^^I\end{tikzpicture}
                             \end{center}

Which isn’t very helpful.


I tried removing the code from a command and placing it directly in the document with hardcoded values:

\def\MatrixContent{\empty}
\pgfmathtruncatemacro\nn{2^2-1}
\foreach \n in {0,...,\nn}{%
    \edef\MatrixContent{\unexpanded\expandafter{\MatrixContent}\unexpanded\expandafter{%
        \node[ht_hash] (table-\n) {\n};
    }}
}

\begin{tikzpicture}
    \matrix [outer sep=0pt,every node/.style={anchor=west}] (table) {
        \MatrixContent
    };
\end{tikzpicture}

Which produced a new error:

./Diagrams.tex:403: Undefined control sequence.
\pgffor@body ... }\unexpanded \expandafter {\node 
                                                  [ht_hash] (table-\n ) {...
l.403 ^^I^^I}

And finally, I tried using a different method for building \MatrixContent:

\let\MatrixContent\empty
\pgfmathtruncatemacro\nn{2^2-1}
\foreach \n in {0,...,\nn}{%
    \expandafter\gappto\expandafter\MatrixContent\expandafter{%
        \node[ht_hash] (table-\n) {\n};
    }
}

\begin{tikzpicture} ...

Producing yet another error:

./Diagrams.tex:413: Undefined control sequence.
\pgffor@body ...MatrixContent \expandafter {\node 
                                                  [ht_hash] (table-\n ) {...
l.413 ^^I^^I}
  • Welcome! You are just posting fragments. Even though one can infer the required packages from the commands you use, it is not clear what the styles ht_num and ht_hash do. Please provide us with a complete yet minimal document that starts with \documentclass and ends with \end{document}. – Schrödinger's cat Nov 11 at 18:48
  • 1
    BTW, your first example works if you add \\ after \MatrixContent, i.e. \matrix [outer sep=0pt,every node/.style={anchor=west}] (#1) { \node[ht_num] (#1-a) {#2}; \\ \MatrixContent \\ };. (It is true, though, that the error message does not immediately tell you that.) – Schrödinger's cat Nov 11 at 18:49
  • @Schrödinger'scat Thanks for the tip, I’ve updated the first example to be a mcve. I’m thoroughly confused why adding that additional \\ allows the document to compile okay, but it doesn’t appear to output anything in place of \MatrixContent – MTCoster Nov 11 at 19:03
  • This is because you use \edef and \foreach starts a group, so the definitions are local and get forgotten. (Replacing \edef by \xdef yields an error, though, and I need still to figure out what you wish to do.) BTW, which package does \num[minimum-integer-digits=#2] come from? – Schrödinger's cat Nov 11 at 19:21
  • @Schrödinger'scat It’s from siunitx, updated to include in mcve & link to source – MTCoster Nov 11 at 19:29
5

I had to speculate what you want to do, so my guess it is something like this:

\documentclass[11pt,a4paper]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage{siunitx}
\tikzset{ht_num/.style={draw, semithick},
ht_hash/.style={draw, semithick, minimum width=2em}}
\begin{document}

\NewDocumentCommand \HashTable { m m } {%
    \def\MatrixContent{\empty}
    \pgfmathtruncatemacro\nn{2^#2-1}
    \foreach \n in {0,...,\nn}{%
        \pgfmathbin{\n}%
        \edef\myresult{|[ht_hash]| 
        \num[minimum-integer-digits=#2]{\pgfmathresult}}%
        \xappto\MatrixContent{\expandonce{\myresult\\}}%
    }
    \matrix [outer sep=0pt,matrix of nodes] (#1) {
        |[ht_num,name=#1-a]|  #2 \\
        \MatrixContent %\\
    };
}

\begin{tikzpicture}
    \HashTable{table1}{2}
\end{tikzpicture}
\end{document}

enter image description here

Comments:

  1. You were loading but not using the matrix library. I think using it makes things much simpler here.
  2. \tikzstyle is deprecated.
  3. I basically used the commented out solution in Martin Scharrer's answer.
  4. A TikZ matrix has counts \pgfmatrixcurrentrow and \pgfmatrixcurrentcolumn which, when used, may allow you to make this whole enterprise much simpler. Yet I am not sure I am on the right track.
  • Thank you for this! I thought I’d tried everything from my linked questions, but I guess not. – MTCoster Nov 11 at 20:15
  • @MTCoster Probably there is. In any case, from the TikZ point of view the correct syntax is ht_hash/.style={draw, semithick, minimum width=2em,font=\ttfamily}, i.e. add the font information to the definition of the style. Probably this will not have an effect because you use siunitx. So you probably need to look up in its manual how you change the font in \num, or ask a new question. I personally do not use siunitx. – Schrödinger's cat Nov 11 at 20:19
  • 1
    I tried that after posting my comment, and it did work through \num. Thanks again – MTCoster Nov 11 at 20:23
  • BTW, if you want to left-align the cells, you only need to add cells={nodes={anchor=west}} to the matrix option. In general a matrix of nodes is easier to deal with because you can steer more things with keys. – Schrödinger's cat Nov 11 at 22:17
4

There are several problems in your code.

  1. \foreach executes each cycle in a group, so any definition made inside it is forgotten as soon as the group ends, unless it is done globally; thus not \edef, but \xdef (global expanded definition)

  2. The code \unexpanded\expandafter{\MatrixContent} is meant to access the previous value of \MatrixContents (but with no further expansion). You don't want to expand \node..., so that should be the argument of a simple \unexpanded; however it is the only token that should be protected from expansion, together with \\, so a couple of \noexpand suffice; \num is by itself protected from expanding in \edef or \xdef.

  3. Further problem: \num wants to see a number, not the set of instruction to produce it, so \pgfmathbin{\n} should be done before updating \MatrixContent; and \pgfmathresult should not be hidden in \unexpanded.

  4. \tikzstyle has been deprecated for a few years.

Here's the amended code:

\documentclass{article}

\usepackage{siunitx}
\usepackage{tikz}

\begin{document}

\tikzset{
  ht_num/.style={draw, semithick},
  ht_hash/.style={draw, semithick, minimum width=2em},
}

\newcommand\HashTable[2]{%
  \def\MatrixContent{}% not \empty
  \pgfmathtruncatemacro\nn{2^(#2)-1}
  \foreach \n in {0,...,\nn}{%
    \pgfmathbin{\n}% the current value in binary format
    \xdef\MatrixContent{%
      \unexpanded\expandafter{\MatrixContent}% the previous value
      \noexpand\node[ht_hash] (#1-\n) {\num[minimum-integer-digits=#2]{\pgfmathresult}};
      \noexpand\\%
    }%
  }%
  \matrix [outer sep=0pt,every node/.style={anchor=west}] (#1) {
        \node[ht_num] (#1-a) {#2}; \\
        \MatrixContent
  };
}

\begin{tikzpicture}
    \HashTable{table1}{2}
    % Other tikz nodes...
\end{tikzpicture}
\qquad
\begin{tikzpicture}
    \HashTable{table1}{3}
    % Other tikz nodes...
\end{tikzpicture}

\end{document}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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