[Tex/LaTex] How to “execute at begin node” be used with special characters like curly braces? (or: how to raise node content)

hookstikz-pgftikz-styles

I'd like to define the following style:

test/.style={
    execute at begin node={\raisebox\{-0.2cm\}\{},
    execute at end node={\}}
}

and use it like

\documentclass{article} 
\usepackage{tikz}

\tikzset{
    test/.style={
        execute at begin node={\raisebox\{-0.2cm\}\{},
        execute at end node={\}}
    }
}

\begin{document}

    \begin{tikzpicture}
        \node[test,circle,draw] {g};    
    \end{tikzpicture}

\end{document}

But it seems to be wrong, as I get errors like "! Extra }, or forgotten \endgroup" or "Missing number, treated as zero".

I guess the problem is due to the braces. How can I escape them properly?

EDIT: From the answers it became clear that \raisebox alone (like I tried in my broken solution) would've somehow worked in my case (because the dimension was so small that it didn't change the node size (at least I can't see it), which is what I wanted). So I consider all answers correct that only handled this specific/simple case. Answers using \smash and \phantom solved the problem I had actually in mind (but which I didn't clearly formulate as a question). Thanks again for all the great answers! 🙂

WARNING: As already said by percusse, if one only wants to align the text baselines, don't use this! Instead, as described in the "Putting a Diagram in Chains" tutorial of the manual, use text height and text depth on all nodes to be aligned, e.g. text height=1.5ex,text depth=.25ex.

Best Answer

If I want to do something with the node’s content (which, to my recollection, cannot be accessed by a key), I collect it in a savebox via the lrbox environment.

In the following example, the text is saved in the savebox \qrrTikzNodeContent and then, still in the execute at end node key, used.

Firstly it is typeset in \phantom so that the node gets re-sized appropriately (as if the content would be typeset as usual). The following \usebox command is firstly \llaped to occupy the same horizontal space like its phantom-ed version, and than \smashed so that it doesn’t occupy any vertical space.

I added some hopefully useful keys, that should help how \raisebox may affect the node:

  • phantom re-sizes the node as if the content would be typeset in the usual way;
  • smash deactivates re-sizing of the node as forced by \raisebox.

This does not work with the keys text width and align as \tikz@atbegin@node is executed after the minipage is applied that is used to realize those keys.

For this special use-case I want to point out that there’s also the text depth key. For <content> without a depth setting this to <value> is like a \raisebox{<value>}{<depth>}.

The following code procudes a matrix of nodes:

  normal        raise            raise + phantom
text depth  raise + smash    raise + phantom + smash

Additionally it shows the baseline of the node.

Code

\documentclass[tikz]{standalone}
\newsavebox\qrrTikzNodeContent
\newif\ifphantom% remove for 'clean' version
\newif\ifsmash  % remove for 'clean' version
\tikzset{
  nodes={draw,circle},
  bl/.style={append after command={\pgfextra{\draw[very thin] (\tikzlastnode.base west) -- (\tikzlastnode.base east);}}},% debug, remove for 'clean' version
  phantom/.is if=phantom,% remove for 'clean' version
  smash/.is if=smash,    % remove for 'clean' version
  raise/.style={
    execute at begin node={\begingroup\begin{lrbox}{\qrrTikzNodeContent}},
    execute at end node={\end{lrbox}% remove for 'clean' version
      \ifphantom
          \phantom{\usebox\qrrTikzNodeContent}%
      \fi
      \ifsmash\smash{\fi
        \ifphantom\llap{\fi
          \raisebox{#1}{\usebox\qrrTikzNodeContent}%
        \ifphantom}\fi
      \ifsmash}\fi
      \endgroup
    },
%    execute at end node={\end{lrbox}% 'clean' version
%      \phantom{\usebox\qrrTikzNodeContent}%
%      \smash{%
%        \llap{%
%          \raisebox{#1}{\usebox\qrrTikzNodeContent}%
%        }%
%      }%
%      \endgroup
%    }
  },
}
\begin{document}
  \begin{tikzpicture}
    \matrix[draw=none, append after command={}, row sep=1ex, column sep=1ex] {
      \node[bl,                            ] {g}; &
      \node[bl, raise=-.2cm,               ] {g}; &  % only raisebox
      \node[bl, raise=-.2cm,        phantom] {g}; \\ % phantom
      \node[bl, text depth=-.2cm           ] {g}; &  % text depth
      \node[bl, raise=-.2cm, smash,        ] {g}; &  % smash
      \node[bl, raise=-.2cm, smash, phantom] {g}; \\ % smash + phantom
    };
  \end{tikzpicture}

  \begin{tikzpicture}
    \matrix[draw=none, append after command={}, row sep=1ex, column sep=1ex] {
      \node[bl,                            ] {h}; &
      \node[bl, raise=-.2cm,               ] {h}; &  % only raisebox
      \node[bl, raise=-.2cm,        phantom] {h}; \\ % phantom
      \node[bl, text depth=-.2cm           ] {h}; &  % text depth
      \node[bl, raise=-.2cm, smash,        ] {h}; &  % smash
      \node[bl, raise=-.2cm, smash, phantom] {h}; \\ % smash + phantom
    };
  \end{tikzpicture}
\end{document}

Output

enter image description here enter image description here