14

I want to create something that somewhat looks like this:

enter image description here

I know about \overbrace but that only applies to math mode. I couldn't find an \overbrace for text. And while I probably could use math mode, it somehow feels wrong to do so.

I tried TikZ as suggested in a few other questions and I came up with the following:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\usetikzlibrary{patterns,arrows,decorations.pathreplacing}

\begin{figure}
\newcommand{\tikzmark}[1]{\tikz[overlay, remember picture] \coordinate (#1);}

\tikzmark{begin}%
http:
\tikzmark{schema}
//user:[email protected]:port/resource
\tikzmark{query}
?query=foo
\tikzmark{fragment}
\#fragment
\tikzmark{end}

\tikz[overlay,remember picture] {
  \draw[decorate,decoration={brace,raise=5mm,amplitude=24pt}] (begin.north west) -- node [above=16mm] {URI} (end.north east) ;
  \draw[decorate,decoration={brace,raise=2mm,amplitude=24pt,mirror}] (schema.south west) -- node[below of=begin, below=6mm] {Schema} (end.south east) ;
  \draw[decorate,decoration={brace,raise=2mm,amplitude=6pt,mirror}] (fragment.south west) -- node[below of=begin, below=6mm] {Fragment} (end.south east) ;
}
\end{figure}
\end{document}

While that looks like it has potential: rendered code it feels awkward having to manually adjust the position of the labels with above=6mm and below.

So I guess I want to not care about the exact positions and do it roughly like this:

\overbrace{URI}{\underbrace{schema}{http:}\underbrace{specific}{//\underbrace{credentials}{user:pass}}}
2
  • You can do $\underbrace{\text{\#fragment}}_{\text{Fragment}$ in math-mode with the amsmath package. Commented Aug 13, 2013 at 17:27
  • This can be done with ease using \overbrace/\underbrace. Are you tied to tikz?
    – Werner
    Commented Aug 13, 2013 at 17:27

2 Answers 2

10

Using a matrix of nodes and then making use of the corners of those nodes (via .north west, .north east, .south west, and .south east) for \drawing the paths, combined with the ability to set nodes along paths, allows you to do this in TikZ. Moreover, you can use \tikzstyle to set some of the options globally, so you don't have to manually adjust the position of the labels continually:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{decorations.pathreplacing}

\tikzstyle{overbrace text style}=[font=\tiny, above, pos=.5, yshift=3mm]
\tikzstyle{overbrace style}=[decorate,decoration={brace,raise=2mm,amplitude=3pt}]
\tikzstyle{underbrace style}=[decorate,decoration={brace,raise=2mm,amplitude=3pt,mirror},color=gray]
\tikzstyle{underbrace text style}=[font=\tiny, below, pos=.5, yshift=-3mm]

\begin{document}

\begin{tikzpicture}

    \matrix[name=M1, matrix of nodes, inner sep=0pt, column sep=0pt]{
      \node (schema) [text=red] {http:\vphantom{/}}; & \node (schema-spezifisch) [text=black] {//}; & \node (nutzerinfo) [text=orange] {user:pass\vphantom{/}}; & @ & \node (host) [text=blue] {www.example.com\vphantom{/}}; & : & \node (port) [text=blue!40] {1234\vphantom{/}}; & \node (pfad) [text=red] {/directory/index.php}; & \node (query) [text=purple] {?key=value\vphantom{/}}; & \node (fragment) [text=green] {\#anchor\vphantom{/}};  \\
    };

    \draw [overbrace style] (schema.north west) -- (schema.north east) node [overbrace text style] {Schema};
    \draw [overbrace style] (schema-spezifisch.north west) -- (fragment.north east) node [overbrace text style] {Schema-Spezifisch};
    \draw [underbrace style] (nutzerinfo.south west) -- (nutzerinfo.south east) node [underbrace text style,text=orange] {Nutzerinfo};
    \draw [underbrace style] (host.south west) -- (host.south east) node [underbrace text style,text=blue] {Host};
    \draw [underbrace style] (port.south west) -- (port.south east) node [underbrace text style,text=blue!40,baseline] {Port};
    \draw [underbrace style] (pfad.south west) -- (pfad.south east) node [underbrace text style,text=red] {Pfad};
    \draw [underbrace style] (query.south west) -- (query.south east) node [underbrace text style,text=purple] {Query};
    \draw [underbrace style] (fragment.south west) -- (fragment.south east) node [underbrace text style,text=green] {Fragment};

\end{tikzpicture}

\begin{tikzpicture}

    \matrix[name=M2, matrix of nodes, inner sep=0pt, column sep=0pt]{
      \node (URI) {http:}; & \node (schema) [text=black] {//user:[email protected]:port/resource?query=foo}; & \node (fragment) {\#fragment};  \\
    };

    \draw [overbrace style] (URI.north west) -- (fragment.north east) node [overbrace text style] {URI};
    \draw [decorate,decoration={brace,raise=6mm,amplitude=3pt,mirror},color=gray] (schema.south west) -- (fragment.south east) node [font=\tiny, below, pos=.5, yshift=-7mm] {Schema};
    \draw [underbrace style] (fragment.south west) -- (fragment.south east) node [underbrace text style] {Fragment};

\end{tikzpicture}

\end{document}

enter image description here

You will just have to make sure that each place where you need to place the beginning or ending of an underbrace or overbrace is set as its own node in its own column of the matrix.

Moreover, if you don't want to have to set the options manually for the lower underbrace in the second tikzpicture, you could set something like an 'under-underbrace \tikzstyle' globally, or something like that.


Additionally, you could also wrap the \draw commands in a macro. For example, you could put this in the preamble:

\usepackage{twoopt}
\newcommandtwoopt{\tikzoverbrace}[5][][]{\draw [overbrace style,#1] (#3.north west) -- (#4.north east) node [overbrace text style,#2] {#5};}
\newcommandtwoopt{\tikzunderbrace}[5][][]{\draw [underbrace style,#1] (#3.south west) -- (#4.south east) node [underbrace text style,#2] {#5};}

And then you could write:

\tikzoverbrace{schema-spezifisch}{fragment}{Schema-Spezifisch}

instead of:

\draw [overbrace style] (schema-spezifisch.north west) -- (fragment.north east) node [overbrace text style] {Schema-Spezifisch};

And you could also write:

\tikzunderbrace[][text=orange]{nutzerinfo}{nutzerinfo}{Nutzerinfo}

instead of:

\draw [underbrace style] (nutzerinfo.south west) -- (nutzerinfo.south east) node [underbrace text style,text=orange] {Nutzerinfo};

You'll still have to set the matrix independently of these new commands, with this solution, however.


Update:

As @FrederickNord points out in the comments, adding nodes={anchor=south}, text height=1.5ex,text depth=.25ex to the matrix style will ensure that the overbraces and underbraces (at least in this particular MWE) are correctly aligned. Another option is to use \vphantom{...} inside the nodes, which is the option used in the MWE above.

4
  • Wow! Awesome. Excellent answer. But somehow the heights seems to differ. If you look closely at the Port portion you will notice that the brace is lower than the Host brace. The effect is very visible when using a different font, i.e. Palatino. Would it be possible to have the braces aligned nicely? Commented Aug 14, 2013 at 9:18
  • I found out that adding nodes={anchor=south}, text height=1.5ex,text depth=.25ex to the style of the matrix makes it look nice. Commented Aug 14, 2013 at 13:47
  • @FrederickNord Yes, I think that should do it. Otherwise, I put some \vphantom{/} commands in some of the nodes, I think, in order to resolve that issue in terms of the alignment for the underbraces of 'port' and 'pfad'. I guess I forgot to do that for all of the nodes; however, I think your solution is probably better.
    – Adam Liter
    Commented Aug 14, 2013 at 16:13
  • @FrederickNord I updated the MWE so all of the nodes that need them have \vphantom{/} commands inside of them, and I've noted your approach as well. Thanks for pointing that out.
    – Adam Liter
    Commented Aug 14, 2013 at 17:01
8

A simple solution I used when I needed to underbrace text was simple to use math mode wrapped inside a new command:

\newcommand{\undertext}[2] {$\underbrace{\textrm{#1}}_{\textrm{#2}}$}

Then you just \undertext{any text}{like this}

You must log in to answer this question.

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