2

I'm having a problem with using scope if the scope is embedded in a macro. There is an answer, but that relies on a local bounding box: Positioning a tikz scope relative to another tikz scope

If the scope is contained in the macro, it does not work -- a problem with grouping within the macro that I can't solve. I'm sure I'm missing something annoyingly elementary.

\documentclass{article}

\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage[papersize={5.5in,8.5in},margin=0.6in,bottom=0.7in]{geometry}
\usepackage{fontspec}
%% \usepackage{array}
%% \usepackage{multicol}
\usepackage{xparse}

\newlength{\xmove}

\usetikzlibrary{positioning, calc}

\NewDocumentCommand{\makespine}{O{}mm}{%% With scope built in
    \foreach \ingtmp [count=\ingnumtmp from 1] in {#2}{\xdef\maxitems{\ingnumtmp}}
    \begin{scope}[xshift=\xmove]%
        \node at (0,0) {};
        \foreach \N [count=\M from 1] in {#2}
            \node[anchor=west,inner xsep=0pt] at (\M*.125,\M*.5) {$\leftarrow$\N};
        \draw[<-] (0,0) -- (\maxitems*.125,\maxitems*.5)coordinate(head);
        \node[anchor=south,above =2pt of head]{#3};
    \end{scope}%
}

\NewDocumentCommand{\nsmakespine}{O{}mm}{%% Uses external scope 
    \foreach \ingtmp [count=\ingnumtmp from 1] in {#2}{\xdef\maxitems{\ingnumtmp}}
        \node at (0,0) {};
        \foreach \N [count=\M from 1] in {#2}
            \node[anchor=west,inner xsep=0pt] at (\M*.125,\M*.5) {$\leftarrow$\N};
        \draw[<-] (0,0) -- (\maxitems*.125,\maxitems*.5)coordinate(head);
        \node[anchor=south,above =2pt of head]{#3};
}

%% \Setmainfont{}
%% \setsansfont{}
%% \newfontfamily{}{}
%% \newfontinstance{}{}

\begin{document}

This works:

\begin{tikzpicture}[]
    \draw[->] (0,0) -- (2in,0);
    \nsmakespine{1,2,3,4,5,6}{Spine 1}
    \begin{scope}[xshift=1in]
    \nsmakespine{A,B,C,D,E,F, G,H,I}{Spine 2}
    \end{scope}
    \begin{scope}[xshift=2in]
    \nsmakespine{A,B,C,D,E,F, G,H,I,J}{Spine 3}
    \end{scope}
\end{tikzpicture}

This does not:

\begin{tikzpicture}[]
    \draw[->] (0,0) -- (2in,0);
    \makespine[xmove=0in]{1,2,3,4,5,6}{Spine 1}
    \makespine[xmove=1in]{A,B,C,D,E,F, G,H,I}{Spine 2}
    \makespine[xmove=2in]{A,B,C,D,E,F, G,H,I,J}{Spine 3}
\end{tikzpicture}

\end{document}

enter image description here

sgmoye
  • 8,586

2 Answers2

1

I do not really know what goes wrong but I think that, if you are loading pgf, you can use its keys, which are to the best of my knowledge more powerful than other key managements systems. Also you may not introduce a global macro just to count the number of items.

\documentclass{article}

\usepackage{tikz}% tikz loads graphicx and xcolor
\usepackage[papersize={5.5in,8.5in},margin=0.6in,bottom=0.7in]{geometry}
\usepackage{fontspec}
%% \usepackage{array}
%% \usepackage{multicol}
\usepackage{xparse}

\makeatletter
\pgfmathdeclarefunction{Dim}{1}{%
\begingroup%
\pgfutil@tempcnta0%
\@for\pgfutil@tempa:=#1\do{\advance\pgfutil@tempcnta1}%
\edef\pgfmathresult{\the\pgfutil@tempcnta}%
\pgfmathsmuggle\pgfmathresult\endgroup%
}
\makeatother

\tikzset{spine/.cd,xmove/.initial=0pt}

\usetikzlibrary{positioning, calc}

\NewDocumentCommand{\makespine}{O{}mm}{%% With scope built in
    \pgfmathsetmacro{\maxitems}{Dim("{#2}")}
    \tikzset{spine/.cd,#1}
    \begin{scope}[xshift=\pgfkeysvalueof{/tikz/spine/xmove}]%
        \node at (0,0) {};
        \foreach \N [count=\M from 1] in {#2}
            \node[anchor=west,inner xsep=0pt] at (\M*.125,\M*.5) {$\leftarrow$\N};
        \draw[<-] (0,0) -- (\maxitems*.125,\maxitems*.5)coordinate(head);
        \node[anchor=south,above =2pt of head]{#3};
    \end{scope}%
}

\begin{document}

This works:

\begin{tikzpicture}[]
    \draw[->] (0,0) -- (2in,0);
    \makespine[xmove=0in]{1,2,3,4,5,6}{Spine 1}
    \makespine[xmove=1in]{A,B,C,D,E,F, G,H,I}{Spine 2}
    \makespine[xmove=2in]{A,B,C,D,E,F, G,H,I,J}{Spine 3}
\end{tikzpicture}

\end{document}

enter image description here

  • Interesting. Certainly, you have spoken very highly of \pgfmathdeclarefunction in the past so this gives me an opportunity to learn something new... – sgmoye May 20 '20 at 16:57
1

Your optional parameter should be \xmove=1in (instead of xmove=1in) since \xmove is a length (and not a key). Furthermore, you must evaluate this optional parameter in your \makespine macro.

Here is a version that works:

\documentclass{article}

\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage[papersize={5.5in,8.5in},margin=0.6in,bottom=0.7in]{geometry}
% \usepackage{fontspec}
%% \usepackage{array}
%% \usepackage{multicol}
\usepackage{xparse}

\newlength{\xmove}

\usetikzlibrary{positioning, calc}

\NewDocumentCommand{\makespine}{O{}mm}{%% With scope built in
  #1%
  \foreach \ingtmp [count=\ingnumtmp from 1] in {#2}{\xdef\maxitems{\ingnumtmp}}
  \begin{scope}[xshift=\xmove]%
    \node at (0,0) {};
    \foreach \N [count=\M from 1] in {#2}
    \node[anchor=west,inner xsep=0pt] at (\M*.125,\M*.5) {$\leftarrow$\N};
    \draw[<-] (0,0) -- (\maxitems*.125,\maxitems*.5)coordinate(head);
    \node[anchor=south,above =2pt of head]{#3};
  \end{scope}%
}

\NewDocumentCommand{\nsmakespine}{O{}mm}{%% Uses external scope 
  \foreach \ingtmp [count=\ingnumtmp from 1] in {#2}{\xdef\maxitems{\ingnumtmp}}
  \node at (0,0) {};
  \foreach \N [count=\M from 1] in {#2}
  \node[anchor=west,inner xsep=0pt] at (\M*.125,\M*.5) {$\leftarrow$\N};
  \draw[<-] (0,0) -- (\maxitems*.125,\maxitems*.5)coordinate(head);
  \node[anchor=south,above =2pt of head]{#3};
}

%% \Setmainfont{}
%% \setsansfont{}
%% \newfontfamily{}{}
%% \newfontinstance{}{}

\begin{document}

This works:

\begin{tikzpicture}[]
  \draw[->] (0,0) -- (2in,0);
  \nsmakespine{1,2,3,4,5,6}{Spine 1}
  \begin{scope}[xshift=1in]
    \nsmakespine{A,B,C,D,E,F, G,H,I}{Spine 2}
  \end{scope}
  \begin{scope}[xshift=2in]
    \nsmakespine{A,B,C,D,E,F, G,H,I,J}{Spine 3}
  \end{scope}
\end{tikzpicture}

This does not:

\begin{tikzpicture}[]
  \draw[->] (0,0) -- (2in,0);
  \makespine[\xmove=0in]{1,2,3,4,5,6}{Spine 1}
  \makespine[\xmove=1in]{A,B,C,D,E,F, G,H,I}{Spine 2}
  \makespine[\xmove=2in]{A,B,C,D,E,F, G,H,I,J}{Spine 3}
\end{tikzpicture}

\end{document}
Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283