# Adjust placement of commas and periods in TikZ txt style

In the example below, one can see that a comma and a period following a word on the baseline in a TikZ environment is based on how far the node above the word stretches towards the right. How can I change this so that the comma and the period don't care about the node above the word, but only by the word itself?

\documentclass{article}
\usepackage{tikz}
\newlength{\Aheight}
\setlength{\Aheight}{\fontcharht\fontA}

\newcommand{\phraselabel}[2]{%
\begin{tikzpicture}[%
baseline = (word.base),
txt/.style = {inner sep = 0pt, text height = \Aheight, draw},
above/.style = {inner sep = 0pt, text depth = 0pt, draw}%
]
\node[txt] (word) {#1};
\node[above] at (word.north) {\footnotesize{#2}};
\end{tikzpicture}%
}

\begin{document}
\phraselabel{bb}{xxxxx}, \phraselabel{bb}{xxxxx}.
\end{document}


• Do you want the comma just after the bb? – Sigur Apr 10 '15 at 20:53
• @Sigur Right - I'd like the placement of the comma and the period to be exactly as it would be if the nodes above weren't there. – Sverre Apr 10 '15 at 20:54

The following example lets \phraselabel look ahead, whether a comma or period is following. If the punctuation char is found, it is read as argument and put behind the word.

The first line of the example uses the boxed version, but the punctuation char is left outside, because it does not belong to the word. For the case, the punctuation char should be inside the box or the boxes are just for debugging, the second line shows the simplified version without boxes.

Another feature is implemented, the handling of the space factor. In order to add a larger space after full stops with \nonfrenchspacing, TeX keeps track of a space factor. The example saves the space factor after the word inside the node and restores it after the tikzpicture. See the larger space between "cc." and "New".

Full example:

\documentclass{article}
\usepackage{ltxcmds}
\usepackage{tikz}
\newlength{\Aheight}
\setlength{\Aheight}{\fontcharht\fontA}

\makeatletter
\newcommand{\phraselabel}[2]{%
\ltx@ifnextchar@nospace,{\@phraselabel{#1}{#2}}{%
\ltx@ifnextchar@nospace.{\@phraselabel{#1}{#2}}{%
\ltx@ifnextchar@nospace;{\@phraselabel{#1}{#2}}{%
\ltx@ifnextchar@nospace!{\@phraselabel{#1}{#2}}{%
\ltx@ifnextchar@nospace?{\@phraselabel{#1}{#2}}{%
\@phraselabel{#1}{#2}{}%
}}}}}%
}
\newcommand*{\@phraselabel}[3]{%
\begin{tikzpicture}[%
baseline = (word.base),
txt/.style = {inner sep = 0pt, text height = \Aheight, draw},
above/.style = {inner sep = 0pt, text depth = 0pt, draw}%
]
\node[txt] (word) {#1\phrase@save@spacefactor};
\ifx\\#3\\
\else
\node[anchor=base, right, inner sep=0pt]
at (word.base east)
{\phrase@set@spacefactor#3\phrase@save@spacefactor};
\fi
\node[above] at (word.north) {\footnotesize{#2}};
\end{tikzpicture}%
\phrase@set@spacefactor
}
\newcount\phrase@spacefactor
\newcommand*{\phrase@save@spacefactor}{%
\global\phrase@spacefactor=\spacefactor
}
\newcommand*{\phrase@set@spacefactor}{%
\spacefactor=\phrase@spacefactor
}
\makeatother

\begin{document}

% With boxes
\phraselabel{aa}{xxxxx}
\phraselabel{bb}{yyyyy},
\phraselabel{cc}{zzzzz}.
\phraselabel{New}{xxxxx}
\phraselabel{sentence}{yyyyy}.

% Without boxes
\makeatletter
\renewcommand*{\@phraselabel}[3]{%
\begin{tikzpicture}[%
baseline = (word.base),
txt/.style = {inner sep = 0pt, text height = \Aheight},
above/.style = {inner sep = 0pt, text depth = 0pt}%
]
\node[txt] (word) {#1#3\phrase@save@spacefactor};
\node[above] at (word.north) {\footnotesize{#2}};
\end{tikzpicture}%
\phrase@set@spacefactor
}
\makeatother
\phraselabel{aa}{xxxxx}
\phraselabel{bb}{yyyyy},
\phraselabel{cc}{zzzzz}.
\phraselabel{New}{xxxxx}
\phraselabel{sentence}{yyyyy}.
\end{document}


Remark:

• \ltx@ifnextchar@nospace of package ltxcmds is used for the look ahead. In contrary to LaTeX's \@ifnextchar, it does not gobble spaces, when looking ahead.
• I'd like to also do this when the following character is ! or ?. I tried to simply add \ltx@ifnextchar@nospace!{\@phraselabel{#1}{#2}}{% and \ltx@ifnextchar@nospace?{\@phraselabel{#1}{#2}}{% below your other \ltx@ifnextchar@nospace commands, but I get an error Runaway argument? {\ltx@ifnextchar@nospace ,{\@phraselabel {##1}{##2}}{\ltx@ifnextchar@nospace \E TC. Could you please include commands for ! and ? in your code? – Sverre Apr 11 '15 at 13:03
• @Sverre Probably only some closing curly braces were missing. I have now added support for ;, !, and ?. – Heiko Oberdiek Apr 11 '15 at 13:55

You can use \rlap{}:

\documentclass{article}
\usepackage{tikz}
\newlength{\Aheight}
\setlength{\Aheight}{\fontcharht\fontA}

\newcommand{\phraselabel}[2]{%
\begin{tikzpicture}[%
baseline = (word.base),%
txt/.style = {inner sep = 0pt, text height = \Aheight},%
tag/.style = {above=0.75ex, inner sep = 0pt, text depth = 0pt}%
]%
\node[txt] (word) {#1};%
\node[tag] at (word.north) {\footnotesize{#2}};%
\end{tikzpicture}%
}

\begin{document}
\phraselabel{gg}{xxxxx} \phraselabel{aa}{jjjjj} \phraselabel{tt}{xxxxx} \phraselabel{bb\rlap{.}}{xxxxx}
\end{document}


• Relevant links for people wanting to know what \rlap does are here and here. – Sverre Apr 10 '15 at 21:23
• Sorry, yes, I had to run before explaining how it works. – Jason Zentz Apr 10 '15 at 21:54

As a quick hack to remember you could just use \hphantom{}

\documentclass{article}
\usepackage{tikz}
\newlength{\Aheight}
\setlength{\Aheight}{\fontcharht\fontA}

\newcommand{\phraselabel}[2]{%
\begin{tikzpicture}[%
baseline = (word.base),
txt/.style = {inner sep = 0pt, text height = \Aheight, draw},
above/.style = {inner sep = 0pt, text depth = 0pt, draw}%
]
\node[txt] (word) {#1};
\node[above] at (word.north) {\footnotesize{#2}};
\end{tikzpicture}%
}

\begin{document}
\phraselabel{\hphantom{,}bb,}{xxxxx} \phraselabel{\hphantom{.}bb.}{xxxxx}
\end{document}


• Yes, I have, but the problem then is that the node above will no longer be centered with respect to bb, but to bb + comma/period. – Sverre Apr 10 '15 at 21:17
• I have updated my problem with a solution using \hphantom{} to balance the left and the right side. \hphantom{} and \vphantom{} can often be used for stuff like this for quick fixes. (Edit) I just thought I would also mention if you don't like seeing \hphantom{} in \phraselabel{} you can write a macro to auto balance it on either side with something like \newcommand{\bal}[2]{\hphantom{#1} #2 #1} – MrBrightside Apr 10 '15 at 21:18