# Using TikZ to depict intonation

I am looking into using TikZ to represent pitch patterns over a phrase or sentence (intonation).

I've got it to produce some useful results, already, as in the attached MWE (although in 1.1 the baselines don't seem to level up).

%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
\documentclass[a4paper,12pt, oneside]{article}

\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text, Scale=MatchLowercase}
\setmainfont{Charis SIL}

\usepackage{tikz}

\begin{document}

\section{Marking intonation using TikZ}

\subsection{Setting words on different levels}

\begin{table}[hbtp]
\begin{tabular}{ll}
\cline{1-1} \noalign{\smallskip}
\tikz[x=1mm,y=1mm,baseline=12] \draw (0,10) node {\underline{Where}} (10,2) node {are} (20,2) node {you} (30,6) node {\underline{go}} (40,0) node{ing?}; & \textit{neutral/default - stress represented by underlining}\\
\cline{1-1} \noalign{\smallskip}
\tikz[x=1mm,y=1mm,baseline=12] \draw (0,0) node {Where} (10,10) node {\underline{are}} (20,5) node {you} (30,2) node {go} (40,0) node{ing?}; & \textit{ e.g. in response to I'm not going to the shops after all.''}\\
\cline{1-1}
\end{tabular}
\end{table}

Why do are'' and you'' in the first example appear on slightly
different levels, even though they are both set to 1mm on the y axis?
Likewise for where'' and ing'' in the second example.

I'm not sure I'm using baseline'' properly here!

\subsection{As above, but boxed}

\begin{tikzpicture}
\node[draw] at (0,1) {\underline{Where}};
\node[draw] at (1,0.1) {are};
\node[draw] at (2,0.1) {you};
\node[draw] at (3,0.6) {\underline{go}};
\node[draw] at (4,0) {ing?};
\end{tikzpicture}\\

Still have to figure out the difference between \textbackslash draw node'' and \textbackslash node[draw]''!

\subsection{Graphical contour}

\begin{table}[hbtp]
\begin{tabular}{l}
\tikz[x=1mm,y=1mm,rounded corners=2mm] \draw[very thick, gray](0,10)--(10,2)--(20,2){[red]--(30,6)--(40,0)}; \\
Where are you~~~going?
\end{tabular}
\end{table}

\begin{table}[hbtp]
\begin{tabular}{l}
\tikz[x=1mm,y=1mm,rounded corners=2mm] \draw[very thick, gray](0,10)--(12,2)--(23,2){[red]--(26,6)--(35,0)}; \\
Where are you going?
\end{tabular}
\end{table}

This is preferable to setting the individual words on different levels, but
requires trial and error in (i) matching the length of the whole contour to
the utterance, and (ii) spreading the parts of the contour to match the words
of the utterance, either by spacing the words (first example) or adjusting the
contour points (second example).

\end{document}


However, my main query is whether anyone has a method for dealing with the issue in 1.3. This involves trial-and-error in fitting the contour to the words, and I was wondering if there is any way to somehow anchor particular contour coordinates to particular syllables. I know that lines can be attached to nodes, but I haven't been able to find a way of getting the lines to "float" above the nodes. Any suggestions for allowing a line of text to be marked with anchor points as it is typed, with the contour then being drawn between these?

-
+1 and fav from me. Not for being a good technical question (which it is, too, of course) but for being one great example of LaTeX use cases. :) – Foo Bar Apr 10 '13 at 16:12
Wow, guys - so much brilliance out there! Sorry I'm slow to respond, but I'm trying to test all of these in depth (and understand at least some of the code!). – donnek Apr 11 '13 at 9:01
Note that mwibrow's code below has been extended to allow pitchlevels as well as contours to be depicted - see the question on pitchlevels. – donnek Apr 16 '13 at 22:35

Following up on Matthew Leingang's answer, here's the same approach tied up with some syntactic sugar. It messes around with \catcode stuff, so care needs to be taken.

\documentclass{standalone}
\usepackage{tikz}

\newcount\contourmarkcount
\newdimen\contourraise

{\catcode\|=13
\gdef\installbarmark#1\ignorespaces{%
#1\ignorespaces%
\catcode\|=13%
\global\contourmarkcount=0\relax%
\global\def\lastmarkshift{0}%
\let|=\marktext}%
}

\def\star{*}
\newcommand\marktext[1][*]{%
\def\markshift{#1}%
% When not followed by the optional argument
% the contour mark is set at the previous height.
\ifx\markshift\star
\let\markshift=\lastmarkshift%
\fi
\xdef\tmpmark{\the\contourmarkcount}%
\tikz[remember picture, overlay, y=\pgfkeysvalueof{/tikz/contour scale}]
\path [yshift=\contourraise, shift={(0,\markshift)}]
coordinate (\contourmarkprefix-\tmpmark);%
\global\contourmarkcount=\tmpmark\relax%
\global\let\lastmarkshift=\markshift%
}

\tikzset{
intonation contour/.style={%
execute at begin node={%
\installbarmark%
},
append after command={%
\pgfextra{%
\ifnum\contourmarkcount>1
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ -- (\contourmarkprefix-\y) };
\fi
}
}
},
% How far above the base line of the text,
raise contour/.code=\pgfmathsetlength\contourraise{#1},
% The scale' for the values in the contour height specification
contour scale/.initial=3pt,
% The prefix for the contour marks.
contour mark prefix/.code=\xdef\contourmarkprefix{#1},
contour mark prefix=intonation contour,
contour/.style={
draw,
rounded corners=1ex,
}
}

\begin{document}

\begin{tikzpicture}[remember picture]

\node [intonation contour, raise contour=0.5cm]
{|[10]Where |[3]are |[3]you |[5]go|[2]ing|[0]?};

\end{tikzpicture}

\begin{tikzpicture}[remember picture]

\node [intonation contour, raise contour=0.5cm, contour mark prefix=my contour]
{|[2]I  |am  |[7]fina|lly |[4]go|ing |[2]home|[0].};

\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my contour-3)
node [midway, left] {\tiny rising};

\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my contour-5)
node [midway, right] {\tiny falling};
\end{tikzpicture}

\end{document}


And just for fun, here's a version that doesn't use remember picture so doesn't need two compilations. Also there is no fooling around with category codes. It is, unfortunately, a bit more involved, and the letters are not typeset ideally as they are all in separate boxes.

EDIT A bit more versatility has been implemented, but as a result it is a bit more complex.

\documentclass{standalone}
\usepackage{tikz}

\newdimen\contourraise

\tikzset{
% How far above the base line of the text,
raise contour/.code=\pgfmathsetlength\contourraise{#1},
% The scale' for the values in the contour height specification
contour scale/.initial=3pt,
% The prefix for the contour marks.
contour mark prefix/.code=\xdef\contourmarkprefix{#1},
contour mark prefix=contour,
% The style for the contour path
contour/.style={
draw,
rounded corners=1ex,
},
% The style for the token nodes
contour token/.style={
anchor=base west,
inner sep=0pt,
text depth=0.6ex, % controls underline depth
},
contour underline/.style={
draw
},
% The character to insert a mark (use with care)
contour mark character/.store in=\contourmarkchar,
contour mark character=|
}

\makeatletter

\def\at@{@}

\newcount\lasttokennumber
\newcount\currenttokennumber
\newcount\contourmarkcount
\newcount\contourtokenunderlinestate
\newcommand\contour[2][]{%
\begin{scope}[#1]
\coordinate (token-0);
\currenttokennumber=0\relax%
\lasttokennumber=0\relax%
\contourmarkcount=0\relax%
\def\lastcontourheight{0}%
\contourtokenunderlinestate=0\relax%
\@contour#2@%
}

% Must check for a spaces
\def\@contour{\futurelet\@token\@checkforspace}

\def\@uscore{_}
\def\@checkforspace{%
\ifx\@token\@sptoken%
\let\@next=\@replacespace%
\else%
\if\@token\contourmarkchar%
\let\@next=\@contour@insertmark
\else%
\if\@token\@uscore
\let\@next=\@contourtoggleunderline%
\else%
\let\@next=\@@contour%
\fi%
\fi%
\fi%
\@next%
}

\def\@contourtoggleunderline#1{%
\ifnum\contourtokenunderlinestate>3\relax%
\contourtokenunderlinestate=0\relax%
\fi%
\@contour%
}

\def\@contour@insertmark{%
\afterassignment\@@contour@insertmark\let\@token=%
}

\def\@@contour@insertmark{%
\futurelet\@token\@@@contour@insertmark}%

\def\@@@contour@insertmark{%
\if\@token[%
\let\@next=\@@@@contour@insertmark%
\else%
\let\currentcontourheight=\lastcontourheight%
\let\@next=\@@@@@contour@insertmark%
\fi%
\@next%
}

\def\@@@@contour@insertmark[#1]{%
\def\@tmp{#1}%
\ifx\@tmp\@empty%
\let\currentcontourheight=\lastcontourheight%
\else%
\def\currentcontourheight{#1}%
\fi%
\@@@@@contour@insertmark}

\def\@@@@@contour@insertmark{%
% Code for inserting mark
\coordinate (\contourmarkprefix-\the\contourmarkcount)
at ([yshift=\contourraise, y=\pgfkeysvalueof{/tikz/contour scale},
shift={(0,\currentcontourheight)}]token-\the\currenttokennumber.base east);
%
\let\lastcontourheight=\currentcontourheight
\@contour}

\def\customspace{{\hbox to 1ex{\hfill}}}

\def\@replacespace#1{%
\@contour\customspace#1%
}

\def\@@contour#1{%
\def\@token{#1}%
\if\@token\at@
\let\@next=\@@@contour%
\else%
\lasttokennumber=\currenttokennumber%
% Code for typesetting token
\node [contour token/.try] at (token-\the\lasttokennumber.base east) (token-\the\currenttokennumber) {\@token};
% Manage underline state
\ifnum\contourtokenunderlinestate=1\relax%
\coordinate (underline start) at (token-\the\currenttokennumber.south west);
\contourtokenunderlinestate=2\relax%
\else
\ifnum\contourtokenunderlinestate=3\relax%
\coordinate (underline end) at (token-\the\currenttokennumber.south west);
\draw (underline start) -- (underline end);
\contourtokenunderlinestate=0\relax
\fi%
\fi%
\let\@next=\@contour
%
\fi%
\@next%
}
\def\@@@contour{%
\ifnum\contourmarkcount>1
% Code for drawing contour
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ -- (\contourmarkprefix-\y) };
%
\fi%
\end{scope}%
}

\makeatother

\begin{document}

\begin{tikzpicture}[baseline={(0,-0.25)}]

\contour[raise contour=0.5cm]
{|[10]Where |[3]are |[3]_you_ |[5]go|[2]ing|[0]?}

\end{tikzpicture}

\begin{tikzpicture}[baseline={(0,-0.25)}]

\contour[
raise contour=0.5cm,
contour mark prefix=my contour,
contour/.style={
thick,
rounded corners=1mm,
line cap=round,
dotted},
contour mark character=*]
{*[2]I *am  *[7]_{fi}na*lly_ *[4]go*ing *[2]home*[0].};

\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my contour-3)
node [midway, left] {\tiny rising};

\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my contour-5)
node [midway, right] {\tiny falling};

\path (0,-0.25);
\end{tikzpicture}

\end{document}


EDIT: enhanced version which hopefully covers all the use cases given above.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fit}

\newdimen\contourraise
\newdimen\contourspacetokenwidth
\newcount\lasttokennumber
\newcount\currenttokennumber
\newcount\contourmarkcount
\newcount\contourtokenunderlinestate
\newbox\contourbox

\tikzset{
tight fit/.style={
inner sep=0pt,
outer sep=0pt,
},
%
%
% How far above the reference anchor of the text,
contour raise/.code=\pgfmathsetlength\contourraise{#1},
contour reference anchor/.store in=\contourreferenceanchor,
contour reference anchor=base east,
% The scale' for the values in the contour height specification
contour scale/.store in=\contourscale,
contour scale=3pt,
% The prefix for the contour marks.
contour mark prefix/.store in=\contourmarkprefix,
contour mark prefix=contour,
% The style for the contour path
contour/.style={
draw,
rounded corners=1ex,
},
% The style for the token nodes
every contour token/.style={
anchor=base west,
inner sep=0pt,
},
contour underline/.style={
draw
},
% The character to insert a mark (use with care)
contour mark character/.store in=\contourmarkchar,
contour mark character=|,
% Want to change the code for contour marks? Use this key.
contour mark code/.store in=\contourmarkcode,
% Want to change the code for tokens? Use this key.
contour token code/.store in=\contourtokencode,
% Want to change the code for drawing the contour? Use this  key.
contour code/.store in=\contourcode,
%
% Default stuff
contour mark code={%
\coordinate (\contourmarkprefix-\the\contourmarkcount)
at ([yshift=\contourraise, y=\contourscale,
shift={(0,\currentcontourheight)}]token-\the\currenttokennumber.\contourreferenceanchor);
},
contour token code={%
\node [every contour token/.try] at
(token-\the\lasttokennumber.base east)
(token-\the\currenttokennumber) {\token};
},
contour code={
\draw [contour] (\contourmarkprefix-1)
\foreach \y in {2,...,\the\contourmarkcount}{ --
(\contourmarkprefix-\y) };
},
%
% Don't draw the contour.
tokens only/.style={
contour code={}
},
%
% Only draw the contour (but the space is still used for the tokens)
contour only/.style={
every contour token/.append style={
execute at begin node={\setbox\contourbox=\hbox\bgroup},
execute at end node=\egroup\phantom{\box\contourbox}%
},
underline/.style={
draw=none
}
},
%
% Make tokens follow the contour marks.
tokens only,
contour token code={%
\node [every contour token/.try, y=\contourscale] at
(token-\the\lasttokennumber.base east |-
0,\currentcontourheight)
(token-\the\currenttokennumber) {\token};
},
},
% What style to use when drawing underline
underline/.style={
draw
},
% The underline is drawn along the south side of a node which
% takes this style.
underline token/.style={
inner ysep=1pt
},
% When grouping tokens (e.g., for putting box around)
% this style is applied to a node that is fitted around the group
token group/.style={
inner xsep=1pt,
inner ysep=2pt,
rounded corners=2pt
},
% Draw boxes around tokens groups.
box tokens/.style={
token group/.append style={
draw
}
},
% Change the width of the spaces.
space token width/.code=\pgfmathsetlength\contourspacetokenwidth{#1},
space token width=0.125cm
}

\makeatletter

\def\at@{@}

\newcommand\contour[2][]{%
\begin{scope}[#1]
\coordinate (token-0);
\currenttokennumber=0\relax%
\lasttokennumber=0\relax%
\contourmarkcount=0\relax%
\def\lastcontourheight{0}%
\contourtokenunderlinestate=0\relax%
\@contour#2@%
}

% Must check for a spaces
\def\@contour{\futurelet\@token\@checkforspace}

\def\@uscore{_}
\def\@checkforspace{%
\ifx\@token\@sptoken%
\let\@next=\@replacespace%
\else%
\if\@token\contourmarkchar%
\let\@next=\@contour@insertmark
\else%
\if\@token\@uscore
\let\@next=\@contourtoggleunderline%
\else%
\let\@next=\@@contour%
\fi%
\fi%
\fi%
\@next%
}

\def\@contourtoggleunderline#1{%
\ifnum\contourtokenunderlinestate>3\relax%
\contourtokenunderlinestate=0\relax%
\fi%
\@contour%
}

\def\@contour@insertmark{%
\afterassignment\@@contour@insertmark\let\@token=%
}

\def\@@contour@insertmark{%
\futurelet\@token\@@@contour@insertmark}%

\def\@@@contour@insertmark{%
\if\@token[%
\let\@next=\@@@@contour@insertmark%
\else%
\let\currentcontourheight=\lastcontourheight%
\let\@next=\@@@@@contour@insertmark%
\fi%
\@next%
}

\def\@@@@contour@insertmark[#1]{%
\def\@tmp{#1}%
\ifx\@tmp\@empty%
\let\currentcontourheight=\lastcontourheight%
\else%
\def\currentcontourheight{#1}%
\fi%
\@@@@@contour@insertmark}

\def\@@@@@contour@insertmark{%
% Code for inserting mark
\contourmarkcode%
\let\lastcontourheight=\currentcontourheight%
\@contour}

\def\contourspacetoken{{\hbox to \contourspacetokenwidth{\hfill}}}

\def\@replacespace#1{%
\@contour\contourspacetoken#1%
}

\def\@@contour#1{%
\def\@token{#1}%
\if\@token\at@%
\@contourdounderline%
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
}%
\let\@next=\@@@contour%
\else%
\lasttokennumber=\currenttokennumber%
\let\token=\@token%
% Code for typesetting token
\contourtokencode%
% Manage underline state
\@contourdounderline%
\def\@@token{\contourspacetoken}%
\ifx\@token\@@token%
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\pgfutil@ifundefined{pgf@sh@ns@underline}{}{%
\node [tight fit, fit={(tokengroup) (underline)}]
(tokengroup)
{};}%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
}%
\else
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{%
\node [tight fit,
fit={(token-\the\currenttokennumber)}]
(tokengroup) {};
}{%
\node [tight fit,
fit={(token-\the\currenttokennumber)
(tokengroup)}]
(tokengroup){};
}%
\fi%
\let\@next=\@contour
%
\fi%
\@next%
}

\def\@contourdounderline{%
\ifcase\contourtokenunderlinestate%
\or
\node [tight fit, fit={(token-\the\currenttokennumber)}]
(underline) {};
\contourtokenunderlinestate=2\relax%
\or%
\node [tight fit,fit={(token-\the\currenttokennumber) (underline)}]
(underline) {};
\or%
\node [tight fit, fit={(underline)}, underline token/.try]
(underline) {};
\draw [underline/.try]
(underline.south west) -- (underline.south east);
\pgfutil@ifundefined{pgf@sh@ns@tokengroup}{}{%
\node [tight fit, fit={(tokengroup) (underline)}]
(tokengroup) {};%
\node [tight fit, fit={(tokengroup)}, token group/.try] {};
\global\let\pgf@sh@ns@tokengroup=\relax%
\global\let\pgf@sh@ns@underline=\relax%
}
\contourtokenunderlinestate=0\relax
\fi%
}
\def\@@@contour{%
\ifnum\contourmarkcount>1
% Code for drawing contour
\contourcode%
\fi%
\end{scope}%
}

\makeatother

\begin{document}

\begin{tabular}{c}
\\
\begin{tikzpicture}
{|[10]_Where_ |[3]are you |[6]_go_|[1]ing?|[0]}
\end{tikzpicture}

\\[0.5cm]

\begin{tikzpicture}
\contour[tokens follow contour, box tokens, space token width=0.2cm]
{|[10]_Where_ |[3]are you |[6]_go_ |[1]ing?|[0]}
\end{tikzpicture}

\\[0.5cm]

\begin{tikzpicture}
\contour[contour raise=0.5cm]
{|[10]_Where_ |[3]are you |[6]_go_|[1]ing?|[0]}
\end{tikzpicture}

\\[0.5cm]

\begin{tikzpicture}
\contour[contour raise=0.5cm]
{|[10]Where |[3]are |[3]_you_ |[5]go|[2]ing?|[0]}

\contour[contour raise=0.5cm, contour only, contour/.append style={dashed}]
{|[0]Where |[2]are |[8]you |[2]go|[2]ing?|[1]}

\end{tikzpicture}

\\[1cm]

\begin{tikzpicture}
contour mark character=*]
{*[2]I *am  *[7]_{fi}na*lly_ *[4]go*ing *[2]_home_*[0]};
\end{tikzpicture}
\\[0.5cm]
\begin{tikzpicture}
\contour[
contour raise=0.5cm,
contour mark prefix=my contour,
contour/.style={
thick,
rounded corners=1mm,
line cap=round,
dotted},
contour mark character=*]
{*[2]I *am  *[7]_{fi}na*lly_ *[4]go*ing *[2]home*[0].};

\path [draw=red, ->] ([yshift=0.25cm]my contour-2) -- ([yshift=0.25cm]my
contour-3)
node [midway, left] {\tiny rising};

\path [draw=red, ->] ([yshift=0.25cm]my contour-4) -- ([yshift=0.25cm]my
contour-5)
node [midway, right] {\tiny falling};

\end{tikzpicture}

\end{tabular}
\end{document}


-
Marvelous. I was thinking of a \foreach implementation but this is cleaner. – Matthew Leingang Apr 10 '13 at 20:54
remember picture does not work with xetex driver used in the question or perhaps i'm wrong ... – Alain Matthes Apr 10 '13 at 22:20
@AlainMatthes it compiles fine with xelatex, lualatex, and pdflatex (using the CVS version at least). – Mark Wibrow Apr 11 '13 at 5:43
Yes today the code compiles and I don't understand why yesterday I got an error : Your driver pgfsys-xetex.def does not support marking the current position ... TL2012 pgf_cvs march 2013 – Alain Matthes Apr 11 '13 at 5:57
+1: absolutely fantastic! – Claudio Fiandrino Apr 11 '13 at 7:55

I would use the famous \tikzmark macro and combine it with intersection coordinates. Here is the code:

\documentclass{standalone}
\usepackage{tikz}
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {};}%
\tikzstyle{intonation}=[rounded corners=2mm,yshift=1.5ex]
\begin{document}

\begin{tikzpicture}[remember picture]
\node{\tikzmark{w}Where \tikzmark{a}are \tikzmark{y}you \tikzmark{g}go\tikzmark{i}ing\tikzmark{q}?};
\draw[intonation] (w |- 0,1) -- (a |- 0,0.2) -- (y |- 0,0.2) -- (g |- 0,0.6) -- (q |- 0,0);
\end{tikzpicture}

\end{document}


The \tikzmark macro saves the coordinates of the point of the document at which it is called. So the node text \tikzmark{w}Where \tikzmark{a}are... saves coordinates called w, a, etc., at various points in the sentence.

If A and B are TikZ nodes or coordinates, then (A |- B) is the intersection of a vertical line through A and a horizontal line through B. So (w |- 0,1) has as its x coordinate the baseline-left point of the w in where, and y coordinate 1. You can change this y coordinate as you wish for the other coordinate names.

Here is the result:

You might be able to design a macro that specifies/marks the text and defines the y-values in the same argument. But this is a possible implementation.

-
+1 (although I think knowing what the tikz syntax means is giving you an unfair advantage:-) – David Carlisle Apr 10 '13 at 15:55
@DavidCarlisle: and you have the advantage of remembering \sbox, \strip@pt, and \wd :-D – Matthew Leingang Apr 10 '13 at 15:57
The driver pgfsys-xetex.def does not support marking the current position. – Alain Matthes Apr 10 '13 at 20:56
Sorry! Yes today the code compiles and I don't understand why yesterday I got an error : Your driver pgfsys-xetex.def does not support marking the current position ... TL2012 pgf_cvs march 2013 – Alain Matthes Apr 11 '13 at 5:57
This is elegant, and also simple, since it only needs the \newcommand definition. I've tested it a lot, and it's robust. The minor drawback is that the \tikzmark{x} makes the text more difficult to read. The first 0 in each coordinate is also redundant. I think this solution is probably the best option if additional decorations are not needed (mwibrow's annotations, Alain's embedded contour). – donnek Apr 11 '13 at 16:19

I'm not sure I put the coordinates on the right places (and reused \zzb in two points) but something like

%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode

\documentclass[a4paper,12pt, oneside]{article}

\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text, Scale=MatchLowercase}
\setmainfont{Charis SIL}

\makeatletter
\def\savecoordinate#1#2{\sbox0{#2}\edef#1{\strip@pt\wd0}}
\makeatother

\usepackage{tikz}

\begin{document}

\savecoordinate\zza{Where }
\savecoordinate\zzb{Where are you}
\savecoordinate\zzc{Where are you going?}

\begin{table}[hbtp]
\begin{tabular}{l}
\tikz[x=1pt,y=1mm,rounded corners=2mm] \draw[very thick, gray](0,10)--(\zza,2)--(\zzb,2)--(\zzb,6)--(\zzc,0); \\
\mbox{Where are you going?}
\end{tabular}
\end{table}

\end{document}

-
David, is the Charis SIL font the original font used in the picture commands? – Yiannis Lazarides Apr 10 '13 at 18:09
{[red]...} you can't change the color inside a path. This works only with edge the line is added after the main path. This is a mistake in the question. – Alain Matthes Apr 10 '13 at 21:24
@AlainMatthes I did wonder if that was intended to be a colour but it didn't generate an error and I had no idea what any of the syntax means so I left it in. (Can I just delete the [red] ?) – David Carlisle Apr 10 '13 at 21:28
Yes you remove [red] and the group. If you remove only the group then the line is red because it's the last option in the main path. In the group, the lines are drawn but the color is fixed and it's black. – Alain Matthes Apr 10 '13 at 21:39
@AlainMatthes thanks, fixed. – David Carlisle Apr 10 '13 at 21:41

With PSTricks.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node,graphicx}

\newsavebox\IBox
\savebox\IBox{\scalebox{15}{\raisebox{\depth}{Where are you going?}}}

\psset
{
algebraic,
xunit=\dimexpr\wd\IBox/10,
yunit=\dimexpr\ht\IBox/10,
}

\begin{document}
\begin{pspicture}[showgrid=false](10,20)
\psline[linearc=25pt,linewidth=5pt]{->}(0,20)(2.5,11)(6.5,11)(7.2,18)(9.5,11)
\rput[bl](0,0){\usebox\IBox}
\end{pspicture}
\end{document}

-
Thanks a lot for this. However, it uses pstricks, and it doesn't get around the issue of having to use trail-and-error to position the contour. – donnek Apr 11 '13 at 7:41

1.1

The problem is not baseline. A tikzpicture environment defines a box ( a tex's box). This box has depth and heigth. By default the depth is null and height is the height of the box. It is because the lower left point defines the baseline. In the next code, I wrote baseline=(current bounding box.east) because I don't want to use a tabular. I think it's very easy to place objects with tikz. The text \textit{neutral/default - stress represented by underlining} is aligned with the middle of the box.

Remark : I need to place the text in \mbox because there is an \overful box with the next text.

The problem with are and you is avoided with every node/.style={anchor=base}. It's a problem of box and depth. The box with the letter y has a big depth. With anchor=base all the nodes have the same baseline.

Last remark : To get the same result than with tabular, I used show background bottom etc.

\begin{table}[hbtp]
\begin{tikzpicture}[baseline=(current bounding box.east),every node/.style={anchor=base},show background top,show background bottom]
\path (0,1) node {\underline{Where}} (1,.2) node {are} (2,.2) node {you} (3,.6) node {\underline{go}} (4,0) node{ing?};
\end{tikzpicture}%
\mbox{\textit{neutral/default - stress represented by underlining}}%

\begin{tikzpicture}[baseline=(current bounding box.east),every node/.style={anchor=base},show background bottom]
\draw (0,0) node {Where} (1,1) node {\underline{are}} (2,.5) node {you} (3,.2) node {go} (4,0) node{ing?};
\end{tikzpicture}%
\mbox{\textit{e.g. in response to I'm not going to the shops after all.''}}%
\end{table}


1.2

When you add a node in a path, this node is not exactly a part of the path. It's an object attach to the path but some options of the path are not used for the node

\draw node ..., signifies \path[draw] node ... ; you decide to draw the path but the drawoption of the path is not the draw option of node. If you want to draw the path and the node, you need to write \path[draw] node[draw] ... ;

1.3

Complete code and result

%!TEX TS-program = xelatex
%!TEX encoding = UTF-8 Unicode
\documentclass[a4paper,12pt, oneside]{article}

\usepackage{fontspec}
\defaultfontfeatures{Mapping=tex-text, Scale=MatchLowercase}
\setmainfont{Charis SIL}

\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}

\section{Marking intonation using TikZ}

\subsection{Setting words on different levels}

\begin{table}[hbtp]
\begin{tikzpicture}[baseline=(current bounding box.east),every node/.style={anchor=base},show background top,show background bottom]
\path (0,1) node {\underline{Where}} (1,.2) node {are} (2,.2) node {you} (3,.6) node {\underline{go}} (4,0) node{ing?};
\end{tikzpicture}%
\mbox{\textit{neutral/default - stress represented by underlining}}%

\begin{tikzpicture}[baseline=(current bounding box.east),every node/.style={anchor=base},show background bottom]
\draw (0,0) node {Where} (1,1) node {\underline{are}} (2,.5) node {you} (3,.2) node {go} (4,0) node{ing?};
\end{tikzpicture}%
\mbox{\textit{e.g. in response to I'm not going to the shops after all.''}}%
\end{table}

\subsection{Final attempt}

\makeatletter
\xdef\tmp{}

\def\MarkWord(#1/#2){%
\node[anchor=base west,inner sep=0pt] (a) at (\xa,#2) {#1};
\path (a.west);\pgfgetlastxy{\xa}{\ya}
\xdef\tmp{\tmp(\xa,#2)}%
\path (a.base east) -- ++(1 ex,0) coordinate (a);
\path (a);
\pgfgetlastxy{\xa}{\ya}
\global\let\xa\xa
}

\def\util@empty{}

\def\multiwords#1 #2\@nil{%
\protected@edef\@temp{%
\noexpand\MarkWord(#1)}\@temp
\def\@nextArg{#2}%
\ifx\util@empty\@nextArg
\let\next\@gobble
\fi
\next#2\@nil
}

\def\MarkWords#1{%
\begingroup
\path (0,0) coordinate (a);
\xdef\xa{0}
\let\next\multiwords
\next#1 \@nil %
\endgroup
}
\makeatother

\begin{tikzpicture}
\MarkWords{Where/1 are/.2 you/.2 go/.6 ing?/0}
\path[draw,red] (0,0) plot[smooth] coordinates{\tmp};
\end{tikzpicture}
\end{document}


-
Thanks for these. 1.1: anchor=base - terrific! 1.2: Thanks for explaining that - I can now see that if I use \draw node[draw] in the `words on different levels'' code, I get a box. This would actually be useful for highlighting particular words. 1.3: The new version is a great way of combining the contour and the text, which I hadn't thought of before. After testing, it's quite versatile and looks good. – donnek Apr 11 '13 at 16:12