2

(There are a few related questions, e.g. this and this.)

I want to accomplish the following:

  • enclose some words of the text into boxes,
  • with all those words vertically aligned as they were truly just text,
  • and these boxes should all be the same height, enough to contain all letters of those words, including g, f, ', and so on;
  • furthermore the boxes should be separated by a fixed space with a line running between them.

At first, the closest I've got to the desired solution is this,

enter image description here

obtained with the following code:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calligraphy, positioning, calc}

\tikzset{mystyle/.style={
            rectangle,
            draw,
            inner xsep=2pt,
            inner ysep=2pt,
            %minimum height=height("aaagtaa`a'") + 5pt
        }}

\begin{document}

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
\tikz[node distance=1mm, anchor=text, baseline=(A.base)]{
  \node[mystyle] (A) {a};
  \node[mystyle] (B) [base right=of A.base east] {aa};
  \node[mystyle] (C) [base right=of B.base east] {a};
  \node[mystyle] (D) [base right=of C.base east] {g};
  \node[mystyle] (E) [base right=of D.base east] {t};
  \node[mystyle] (F) [base right=of E.base east] {\phantom{a}};
  \node[mystyle, text=white, fill=black] (G) [base right=of F.base east] {a};
  \node[mystyle, text=white, fill=black] (H) [base right=of G.base east] {`a'};
  \draw[mystyle] ($(A.base east) + (0,.5ex)$) -- ($(B.base west) + (0,.5ex)$);
  \draw[mystyle] ($(B.base east) + (0,.5ex)$) -- ($(C.base west) + (0,.5ex)$);
  \draw[mystyle] ($(C.base east) + (0,.5ex)$) -- ($(D.base west) + (0,.5ex)$);
  \draw[mystyle] ($(D.base east) + (0,.5ex)$) -- ($(E.base west) + (0,.5ex)$);
  \draw[mystyle] ($(E.base east) + (0,.5ex)$) -- ($(F.base west) + (0,.5ex)$);
  \draw[mystyle] ($(F.base east) + (0,.5ex)$) -- ($(G.base west) + (0,.5ex)$);
  \draw[mystyle] ($(G.base east) + (0,.5ex)$) -- ($(H.base west) + (0,.5ex)$);
  \draw[red, very thin] (A.base west) -- (H.base east);
  \draw[red, very thin] (A.west |- D.south) -- (D.south -| H.east);
  \draw[red, very thin] (A.west |- H.north) -- (H.north east);
}
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{document}

As you can see from the commented line, I know how to compute the maximum height of of all the boxes as if they were in isolation, but apparently that's not the height I want

However, while writing the question, I came up with a very ugly hack, which is putting \vphantom{aaagtaaa'}` in every single node:

\tikz[node distance=1mm, anchor=text, baseline=(A.base)]{
  \node[mystyle] (A) {a\vphantom{aaagtaa`a'}};
  \node[mystyle] (B) [base right=of A.base east] {aa\vphantom{aaagtaa`a'}};
  \node[mystyle] (C) [base right=of B.base east] {a\vphantom{aaagtaa`a'}};
  \node[mystyle] (D) [base right=of C.base east] {g\vphantom{aaagtaa`a'}};
  \node[mystyle] (E) [base right=of D.base east] {t\vphantom{aaagtaa`a'}};
  \node[mystyle] (F) [base right=of E.base east] {\phantom{a}\vphantom{aaagtaa`a'}};
  \node[mystyle, text=white, fill=black] (G) [base right=of F.base east] {a\vphantom{aaagtaa`a'}};
  \node[mystyle, text=white, fill=black] (H) [base right=of G.base east] {`a'\vphantom{aaagtaa`a'}};
  \draw[mystyle] ($(A.base east) + (0,.5ex)$) -- ($(B.base west) + (0,.5ex)$);
  \draw[mystyle] ($(B.base east) + (0,.5ex)$) -- ($(C.base west) + (0,.5ex)$);
  \draw[mystyle] ($(C.base east) + (0,.5ex)$) -- ($(D.base west) + (0,.5ex)$);
  \draw[mystyle] ($(D.base east) + (0,.5ex)$) -- ($(E.base west) + (0,.5ex)$);
  \draw[mystyle] ($(E.base east) + (0,.5ex)$) -- ($(F.base west) + (0,.5ex)$);
  \draw[mystyle] ($(F.base east) + (0,.5ex)$) -- ($(G.base west) + (0,.5ex)$);
  \draw[mystyle] ($(G.base east) + (0,.5ex)$) -- ($(H.base west) + (0,.5ex)$);
  \draw[red, very thin] (A.base west) -- (H.base east);
  \draw[red, very thin] (A.west |- D.south) -- (D.south -| H.east);
  \draw[red, very thin] (A.west |- H.north) -- (H.north east);
}

It does work enter image description here

but I challenge you to call it a clean solution.

1
  • Single-line text per node? Either pre-process all contents or post-process through the aux-file. Though, pre should be enough if you allow \rowoftikznodes{a, aa, a, g, t, ~, a, a'}` or something similar. Commented Dec 15, 2022 at 15:55

1 Answer 1

1

You could just pre-process all entries (the PGFMath functions depth and height help) and set text height and text depth appropriately.

Using the mid west and mid east anchors help connect the nodes at the height of .5ex (and not at the vertical center of the nodes).

I'm using xparse's s and the not recommended u argument specifier to parse the list of entries for an optional * at the start which will enable the inverted style.

Since it will not be trivial to detect a literal space between ,, I'm choosing the ~ macro here (usually an unbreakable space) to be \vphantom{a}, a literal space has no height/depth.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{chains}
\usepackage{xparse}
\NewDocumentCommand\tikzrowofnodescheck{s u\STOP}{%
  \IfBooleanT{#1}{\tikzset{tikzrowofnode style'}}%
  \tikzset{node contents={#2}}}
\tikzset{
  tikzrowofnode style/.style={
    rectangle, draw, inner xsep=2pt, inner ysep=2pt},
  tikzrowofnode style'/.style={fill, text=white},
  tikzrowofnode determine height and depth/.style={%
    /utils/exec=\def\tikzrowofnodesheight{0pt}%
                \def\tikzrowofnodesdepth{0pt},%
    /utils/temp/.code=%
      \pgfmathsetlengthmacro\tikzrowofnodesheight{max(\tikzrowofnodesheight,height("##1")}%
      \pgfmathsetlengthmacro\tikzrowofnodesdepth{max(\tikzrowofnodesdepth,depth("##1")},
    /utils/temp/.list={#1},
    tikzrowofnode style/.append style/.expanded={text height=\tikzrowofnodesheight, text depth=\tikzrowofnodesdepth}
  }
}
\newcommand*\tikzrowofnodes[1]{%
 \tikz[
   node distance=1mm,
   baseline=(chain-begin.base),
   start chain=chain going base right,
   every join/.append style={to path={(\tikztostart.mid east) -- (\tikztotarget.mid west)}},
   every on chain/.append style={tikzrowofnode style,join},
   check row of node/.code={\tikzrowofnodescheck##1\STOP},
   tikzrowofnode determine height and depth={#1},
]
   \def~{\phantom{a}}% dirty
   \foreach \t in {#1}
     \node[on chain=chain,check row of node/.expand once=\t];%
}
\begin{document}
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
\tikzrowofnodes{a, aa, a, g, t, ~, *a, *`a'}
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{document}

Output

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .