3

It would be nice to have a simple way to avoid having to type (or copy) the string "nameofthenewcommand" in the following code fragment

\newcommand{\nameofthenewcommand}{%
\node (nameofthenewcommand) [] {etc};
}

whose purpose is to be used in a large tikzpicture elsewhere in the code.

It would be nice to have something like

\newcommand{\nameofthenewcommand}{%
\node (rocn) [] {etc};
}

where rocn is a string I have just made up and which should be recognized by tikz as having the meaning "reflexion of the command-name", prompting it to substitute the string "nameofthenewcommand" in its stead.

What do you recommend to achieve this?

  • Welcome to TeX.SE. Macros have no idea of their name, actually. See this question of mine, for example: tex.stackexchange.com/questions/195056/…. You can use a command -defining macro to track of the name – user31729 Apr 2 '17 at 15:40
  • You are missing some % characters in your command – user31729 Apr 2 '17 at 15:41
  • Thank you. Would you please clarify how in your opinion the "minimal" example I gave should be augmented by % characters? I will then edit the question accordingly. – writer Apr 2 '17 at 15:48
  • Or feel free to edit my question accordingly. – writer Apr 2 '17 at 15:51
  • I've added the % right after the { of the \newcommand definitions – user31729 Apr 2 '17 at 15:52
2

The command \nodestuff macro defines a wrapper command for a node definition and names the node like the macro.

However, this may not catch any of the possible \node calls and the usage is limited, in my point of view, since it is still necessary to remember the node name afterwards.

\documentclass{article}

\usepackage{tikz}

\newcommand{\nodestuff}[3][]{%
  \expandafter\newcommand\csname #2\endcsname{%
    \node[#1] (#2) #3;
  }%
}
\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{foo}{{$E=mc^{2}$}}
  \nodestuff[blue]{foobar}{ at (3,4) {$E=(mc^{2})^{2} + (pc)^{2}$}}
  \foo
  \foobar
  \draw  (foo) -- (foobar) node[midway,right] {A};
\end{tikzpicture}

\end{document}

enter image description here

| improve this answer | |
  • Many thanks. I also appreciate that you added more options than what was being asked for. However, the motivation for the question is to keep the actual "front-end" of the tikzpicture as concise and humanly-readable as possible. I will therefore try to condense your example to a minimal approximation to my intial specification. Currently I do not have time to concentrate on this, but will come back to this question in a few days, and will delay accepting your answer until then. – writer Apr 2 '17 at 18:48
  • @Christian +1 for your excellent work. – Sebastiano Apr 2 '17 at 19:36
0

The \definenode command takes as argument the node name, which makes a command from. See the examples; the new command will take as argument the coordinates for the node.

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn
% syntactic sugar
\NewDocumentCommand{\newnamecommand}{m}
 {
  \exp_args:Nc \newcommand{#1}
 }
\ExplSyntaxOff

\NewDocumentCommand{\definenode}{mom}{%
  % #1 = command (no backslash)
  % #2 (optional) = optional argument to \node
  % #3 = replacement text
  \IfNoValueTF{#2}
   {\newnamecommand{#1}[1]{\node (#1) at ##1 {#3};}}
   {\newnamecommand{#1}[1]{\node[#2] (#1) at ##1 {#3};}}%
}

% \foo will expand to "\node (foo) at #1 {$E=mc^2$};"
\definenode{foo}{$E=mc^2$}
% \baz will expand to "\node[blue] at #1 {Energy};"
\definenode{baz}[blue]{Energy}


\begin{document}

\begin{tikzpicture}
  \foo{(0,0)}
  \baz{(3,4)}
  \draw  (foo) -- (baz) node[midway,right] {A};
\end{tikzpicture}

\end{document}

enter image description here

| improve this answer | |
0

In case you often face the task of creating a control sequence token via \csname..\endcsname, you can use TeX' #{-notation for defining a macro \name where tokens before the first opening brace are taken for an argument and where tokens nested into the first opening brace and the corresponding closing brace are taken for another/a second argument and where a control sequence token is formed from the second argument before TeX processes the tokens from the first argument.

I elaborated on the \name-macro in the thread Define a control sequence after that a space matters which was started at TeX - LaTeX StackExchange in November 10, 2016.

\documentclass{article}

\usepackage{tikz}

\makeatletter
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother

\newcommand{\nodestuff}[3][]{%
  \name\newcommand{#2}{%
    \node[#1] (#2) #3;
  }%
}

\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{foonode}{{text at foonode}}
  \nodestuff[blue]{barnode}{ at (2,3) {text at barnode}}
  \foonode
  \barnode
  \draw  (foonode) -- (barnode);
\end{tikzpicture}

\end{document}

enter image description here

In case you prefer to go the other direction, i.e., obtain the name from the control-sequence-token, you can have TeX apply \string and remove the preceding escape character if present. Be aware of edge cases like the value of the integer parameter \escapechar being 32/denoting a space.
Also the range of possible values where the integer parameter \escapechar yields producing a character token depends on the engine, i.e., depends on whether LuaTeX/XeTeX or "ordinary" TeX is in use.

\documentclass{article}
\usepackage{tikz}
\usepackage{ifxetex, ifluatex}

\makeatletter

\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%

\newcommand\stringifysecond[2]{%
  \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral0\innerstringifysecond#2}{#1}%
}%

\newcommand\innerstringifysecond{%
  \ifnum\escapechar=32 \expandafter\@gobble\else\expandafter\@firstofone\fi
  % In case escapechar is 32, you get a space as escapechar, thus do nothing
  % and have the space removed as terminator of the \romannumeral-expansion
  % that currently is in progress.
  {%
    \ifnum\escapechar<0 \expandafter\@secondoftwo\else\expandafter\@firstofone\fi
    {%
      \ifnum\escapechar>\ifxetex 1114111 \else\ifluatex 1114111 \else 255 \fi\fi
        \expandafter\@secondoftwo        
      \else
        \expandafter\@firstoftwo
      \fi
      {%
        % There is a non-space escapechar, thus gobble that escapechar 
        % as undelimited argument and insert space for terminating \romannumeral:      
        \@firstofone{\expandafter\expandafter\expandafter} \expandafter\@gobble
      }%
    }{%
      % There is no escapechar, thus just insert space for terminating \romannumeral:
      \@firstofone{\expandafter} %
    }%
  }%
  \string
}%
%
\newcommand{\nodestuff}[2][]{%
  \stringifysecond\innernodestuff{#2}{#1}{#2}%
}%
\newcommand\innernodestuff[4]{%
  \newcommand#3{%
    \node[#2] (#1) #4;
  }%
}%

\makeatother

\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{\foonode}{{text at foonode}}
  \nodestuff[blue]{\barnode}{ at (2,3) {text at barnode}}
  \foonode
  \barnode
  \draw  (foonode) -- (barnode);
\end{tikzpicture}

\end{document}

enter image description here

Let's look at the special case of the nameless node/nameless macro:

Stringifying the nameless control sequence token which in turn can come into being as the result of the expansion of the expression \csname\endcsname or can come into being due to tokenizing a backslash character/a character of category code 0 at the end of a line while the value of the integer parameter \endlinechar is negative or larger than 255 (ordinary TeX and XeTeX; with LuaTeX attempts of assigning values larger than 127 to \endlinechar yield error messages and don't get carried out) yields a sequence of character tokens of catcode 12(other) \csname\endcsname.

| improve this answer | |

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.