24 Arrow Tips

24.1 Overview

24.1.1 When Does PGF Draw Arrow Tips?

PGF offers an interface for placing arrow tips at the end of lines. The interface works as follows:

  1. You (or someone else) assigns a name to a certain kind of arrow tips. For example, the arrow tip latex is the arrow tip used by the standard LATEX picture environment; the arrow tip to looks like the tip of the arrow in TEX’s \to command; and so on.

    This is done once at the beginning of the document.

  2. Inside some picture, at some point you specify that in the current scope from now on you would like tips of, say, kind to to be added at the end and/or beginning of all paths.

    When an arrow kind has been installed and when PGF is about to stroke a path, the following things happen:

    1. The beginning and/or end of the path is shortened appropriately.
    2. The path is stroked.
    3. The arrow tip is drawn at the beginning and/or end of the path, appropriately rotated and appropriately resized.

In the above description, there are a number of “appropriately.” The exact details are not quite trivial and described later on.

24.1.2 Meta-Arrow Tips

In PGF, arrows are “meta-arrows” in the same way that fonts in TEX are “meta-fonts.” When a meta-arrow is resized, it is not simply scaled, but a possibly complicated transformation is applied to the size.

A meta-font is not one particular font at a specific size with a specific stroke width (and with a large number of other parameters being fixed). Rather, it is a “blueprint” (actually, more like a program) for generating such a font at a particular size and width. This allows the designer of a meta-font to make sure that, say, the font is somewhat thicker and wider at very small sizes. To appreciate the difference: Compare the following texts: “Berlin” and “

SVG-Viewer needed.

”. The first is a “normal” text, the second is the tiny version scaled by a factor of two. Obviously, the first look better. Now, compare “

SVG-Viewer needed.

” and “Berlin”. This time, the normal text was scaled down, while the second text is a “normal” tiny text. The second text is easier to read.

PGF’s meta-arrows work in a similar fashion: The shape of an arrow tip can vary according to the line width of the arrow tip is used. Thus, an arrow tip drawn at a line width of 5pt will typically not be five times as large as an arrow tip of line width 1pt. Instead, the size of the arrow will get bigger only slowly as the line width increases.

To appreciate the difference, here are the latex and to arrows, as drawn by PGF at four different sizes:

SVG-Viewer needed.

Here, by comparison, is the same arrow when it is simply “resized” (as done by most programs):

SVG-Viewer needed.

As can be seen, simple scaling produces arrow tips that are way too large at larger sizes and way too small at smaller sizes.

24.2 Declaring an Arrow Tip Kind

To declare an arrow kind “from scratch,” the following command is used:

\pgfarrowsdeclare{<start name>}{<end name>}{<extend code>}{<arrow tip code>}

This command declares a new arrow kind. An arrow kind has two names, which will typically be the same. When the arrow tip needs to be drawn, the <arrow tip code> will be invoked, but the canvas transformation is setup beforehand to a rotation such that when an arrow tip pointing right is specified, the arrow tip that is actually drawn points in the direction of the line.

Naming the arrow kind. The <start name> is the name used for the arrow tip when it is at the start of a path, the <end name> is the name used at the end of a path. For example, the arrow kind that looks like a parenthesis has the <start name>( and the <end name>) so that you can say \pgfsetarrows{(-)} to specify that you want parenthesis arrows and both ends.

The <end name> and <start name> can be quite arbitrary and may contain spaces.

Basics of the arrow tip code. Let us next have a look at the <arrow tip code>. This code will be used to draw the arrow tip when PGF thinks this is necessary. The code should draw an arrow that “points right,” which means that is should draw an arrow at the end of a line coming from the left and ending at the origin.

As an example, suppose we wanted to declare an arrow tip consisting of two arcs, that is, we want the arrow tip to look more or less like the red part of the following picture:

 

SVG-Viewer needed.

 

\begin{tikzpicture}[line width=3pt]
  \draw (-2,0) -- (0,0);
  \draw[red,join=round,cap=round]
        (-10pt,10pt) arc (180:270:10pt) arc (90:180:10pt);
\end{tikzpicture}

We could use the following as <arrow tip code> for this:


\pgfarrowsdeclare{arcs}{arcs}{...}
{
  \pgfsetdash{}{0pt} % do not dash
  \pgfsetroundjoin   % fix join
  \pgfsetroundcap    % fix cap
  \pgfpathmoveto{\pgfpoint{-10pt}{10pt}}
  \pgfpatharc{180}{270}{10pt}
  \pgfpatharc{90}{180}{10pt}
  \pgfusepathqstroke
}

Indeed, when the ... is set appropriately (in a moment), we can write the following:

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \draw[-arcs,line width=3pt] (-2,0)  -- (0,0);
  \draw[arcs-arcs,line width=1pt] (-2,-1.5) -- (0,-1);
  \useasboundingbox (-2,-2) rectangle (0,0.75);
\end{tikzpicture}

As can be seen in the second example, the arrow tip is automatically rotated as needed when the arrow is drawn. This is achieved by a canvas rotation.

Special considerations about the arrow tip code. There are several things you need to be aware of when designing arrow tip code:

Designing meta-arrows. The <arrow tip code> should adjust the size of the arrow in accordance with the line width. For a small line width, the arrow tip should be small, for a large line width, it should be larger. However, the size of the arrow typically should not grow in direct proportion to the line width. On the other hand, the size of the arrow head typically should grow “a bit” with the line width.

For these reasons, PGF will not simply executed your arrow code within a scaled scope, where the scaling depends on the line width. Instead, your <arrow tip code> is reexecuted again for each different line width.

In our example, we could use the following code for the new arrow tip kind arc' (note the prime):


\newdimen\arrowsize
\pgfarrowsdeclare{arcs'}{arcs'}{...}
{
  \arrowsize=0.2pt
  \advance\arrowsize by .5\pgflinewidth
  \pgfsetdash{}{0pt} % do not dash
  \pgfsetroundjoin   % fix join
  \pgfsetroundcap    % fix cap
  \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}}
  \pgfpatharc{180}{270}{4\arrowsize}
  \pgfpatharc{90}{180}{4\arrowsize}
  \pgfusepathqstroke
}

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \draw[-arcs',line width=3pt] (-2,0)  -- (0,0);
  \draw[arcs'-arcs',line width=1pt] (-2,-1.5) -- (0,-1);
  \useasboundingbox (-2,-1.75) rectangle (0,0.5);
\end{tikzpicture}

However, sometimes, it can also be useful to have arrows that do not resize at all when the line width changes. This can be achieved by giving absolute size coordinates in the code, as done for arc. On the other hand, you can also have the arrow resize linearly with the line width by specifying all coordinates as multiples of \pgflinewidth.

The left and right extend. Let us have another look at the exact left and right “ends” of our arrow tip. Let us draw the arrow tip arc' at a very large size:

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \draw[help lines] (-2,-1) grid (1,1);
  \draw[line width=10pt,-arcs'] (-2,0) -- (0,0);
  \draw[line width=2pt,white] (-2,0) -- (0,0);
\end{tikzpicture}

As one can see, the arrow tip does not “touch” the origin as it should, but protrudes a little over the origin. One remedy to this undesirable effect is to change the code of the arrow tip such that everything is shifted half an \arrowsize to the left. While this will cause the arrow tip to touch the origin, the line itself will then interfere with the arrow: The arrow tip will be partly “hidden” by the line itself.

PGF uses a different approach to solving the problem: The <extend code> argument can be used to “tell” PGF how much the arrow protrudes over the origin. The argument is also used to tell PGF where the “left” end of the arrow is. However, this number is important only when the arrow is being reversed or composed with other arrow tips.

Once PGF knows the right extend of an arrow kind, it can shorten lines by this amount when drawing arrows.

Here is a picture that shows what the visualizes the extends. The arrow tip itself is shown in red once more:

SVG-Viewer needed.

The <extend code> is normal TEX code that is executed whenever PGF wants to know how far the arrow tip will protrude to the right and left. The code should call the following two commands: \pgfarrowsrightextend and \pgfarrowsleftextend. Both arguments take one argument that specifies the size. Here is the final code for the arc'' arrow tip:

 

SVG-Viewer needed.

 

\pgfarrowsdeclare{arcs''}{arcs''}
{
  \arrowsize=0.2pt
  \advance\arrowsize by .5\pgflinewidth
  \pgfarrowsleftextend{-4\arrowsize-.5\pgflinewidth}
  \pgfarrowsrightextend{.5\pgflinewidth}
}
{
  \arrowsize=0.2pt
  \advance\arrowsize by .5\pgflinewidth
  \pgfsetdash{}{0pt} % do not dash
  \pgfsetroundjoin   % fix join
  \pgfsetroundcap    % fix cap
  \pgfpathmoveto{\pgfpoint{-4\arrowsize}{4\arrowsize}}
  \pgfpatharc{180}{270}{4\arrowsize}
  \pgfusepathqstroke
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpatharc{90}{180}{4\arrowsize}
  \pgfusepathqstroke
}
\begin{tikzpicture}
  \draw[help lines] (-2,-1) grid (1,1);
  \draw[line width=10pt,-arcs''] (-2,0) -- (0,0);
  \draw[line width=2pt,white] (-2,0) -- (0,0);
\end{tikzpicture}

24.3 Declaring a Derived Arrow Tip Kind

It is possible to declare arrow kinds in terms of existing ones. For these command to work correctly, the left and right extends must be set correctly.

\pgfarrowsdeclarealias{<start name>}{<end name>}{<old start name>}{<old end name>}

This command can be used to create an alias (another name) for an existing arrow kind.

 

SVG-Viewer needed.

 

\pgfarrowsdeclarealias{<}{>}{arcs''}{arcs''}%
\begin{tikzpicture}
  \pgfsetarrows{<->}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

\pgfarrowsdeclarereversed{<start name>}{<end name>}{<old start name>}{<old end name>}

This command creates a new arrow kind that is the “reverse” of an existing arrow kind. The (automatically cerated) code of the new arrow kind will contain a flip of the canvas and the meanings of the left and right extend will be reversed.

 

SVG-Viewer needed.

 

\pgfarrowsdeclarereversed{arcs reversed}{arcs reversed}{arcs''}{arcs''}%
\begin{tikzpicture}
  \pgfsetarrows{arcs reversed-arcs reversed}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

\pgfarrowsdeclarecombine*[<offset>]{<start name>}{<end name>}{<first start name>}{<first end name>}{<second start name>}{<second end name>}

This command creates a new arrow kind that combines two existing arrow kinds. The first arrow kind is the “innermost” arrow kind, the second arrow kind is the “outermost.”

The code for the combined arrow kind will install a canvas translation before the innermost arrow kind in drawn. This translation is calculated such that the right tip of the innermost arrow touches the right end of the outermost arrow. The optional <offset> can be used to increase (or decrease) the distance between the inner and outermost arrow.

 

SVG-Viewer needed.

 

\pgfarrowsdeclarecombine[\pgflinewidth]
  {combined}{combined}{arcs''}{arcs''}{latex}{latex}%
\begin{tikzpicture}
  \pgfsetarrows{combined-combined}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

In the star variant, the end of the line is not in the outermost arrow, but inside the innermost arrow.

 

SVG-Viewer needed.

 

\pgfarrowsdeclarecombine*[\pgflinewidth]
  {combined'}{combined'}{arcs''}{arcs''}{latex}{latex}%
\begin{tikzpicture}
  \pgfsetarrows{combined'-combined'}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

\pgfarrowsdeclaredouble[<offset>]{<start name>}{<end name>}{<old start name>}{<old end name>}

This command is a shortcut for combining an arrow kind with itself.

 

SVG-Viewer needed.

 

\pgfarrowsdeclaredouble{<<}{>>}{arcs''}{arcs''}%
\begin{tikzpicture}
  \pgfsetarrows{<<->>}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

\pgfarrowsdeclaretriple[<offset>]{<start name>}{<end name>}{<old start name>}{<old end name>}

This command is a shortcut for combining an arrow kind with itself and then again.

 

SVG-Viewer needed.

 

\pgfarrowsdeclaretriple{<<<}{>>>}{arcs''}{arcs''}%
\begin{tikzpicture}
  \pgfsetarrows{<<<->>>}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

24.4 Using an Arrow Tip Kind

The following commands install the arrow kind that will be used when stroking is done.

\pgfsetarrowsstart{<start arrow kind>}

Installs the given <start arrow kind> for all subsequent strokes in the in the current TEX-group. If <start arrow kind> is empty, no arrow tips will be drawn at the start of the last segment of paths.

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \pgfsetarrowsstart{latex}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

\pgfsetarrowsend{<start arrow kind>}

Like \pgfsetarrowsstart, only for the end of the arrow.

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \pgfsetarrowsend{latex}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

Warning: If the compatibility mode is active (which is the default), there also exist old commands called \pgfsetstartarrow and \pgfsetendarrow, which are incompatible with the meta-arrow management.

\pgfsetarrows{<start kind>-<end kind>}

Calls \pgfsetarrowsstart for <start kind> and \pgfsetarrowsend for <end kind>.

 

SVG-Viewer needed.

 

\begin{tikzpicture}
  \pgfsetarrows{latex-to}
  \pgfsetlinewidth{1ex}
  \pgfpathmoveto{\pgfpointorigin}
  \pgfpathlineto{\pgfpoint{3.5cm}{2cm}}
  \pgfusepath{stroke}
  \useasboundingbox (-0.25,-0.25) rectangle (3.75,2.25);
\end{tikzpicture}

24.5 Predefined Arrow Tip Kinds

The following arrow tip kinds are always defined:

stealth-stealth yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

stealth reversed-stealth reversed yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

to-to yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

to reversed-to reversed yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

latex-latex yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

latex reversed-latex reversed yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

|-| yields thick

SVG-Viewer needed.

and thin

SVG-Viewer needed.

For further arrow tips, see page 176.