# How to draw an arrow with two colors?

I want to draw arrow with two colors, the resulted arrow should be filled by one color at the top and by other color at the bottom, like the following code do to a rectangle:

\draw[top color=blue,bottom color=green] (0,0) rectangle (2,1);


What should I do?

• Related Question/Possible Duplicate: Arrow with two colors with TikZ – Peter Grill Oct 11 '13 at 7:15
• @percusse I had changed my question to make it clear. – windy Oct 11 '13 at 7:28
• @PeterGrill that is an interesting question but with a little difference to mine – windy Oct 11 '13 at 7:29
• Could you make your question a bit clear? With arbitrary paths, top and bottom might confuse the reader: is bottom the bottom of the whole path or just the line bottom part? Having an image might be great. – Claudio Fiandrino Oct 11 '13 at 8:12
• How the transition between colors should be? If a gradient would suffice, this question might be a good starting point. – Pouya Oct 11 '13 at 9:09

Hmm, so I'm the only one who thought the requirement was to shade an arrowhead on a path. Oh well...

Decorations can be used, but are slow. The following is far from perfect, but is basically usable. In the first two versions transformations like scaling and rotation will ruin everything, this is (mostly) corrected in the third version.

The approach involves creating a fading from the required path, which in principle is easy, but to reduce the amount of typing involved I've tried to automate it using a key. Some fooling around has to be done to stop the arrowheads getting cut off.

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}

\makeatletter
\tikzset{
% Need this for the bounding box calculation of the
% If set to zero things (e.g., arrows) may get cut off.
% Prevent this stuff happning recursively.
\else%
% Interrupt the picture to create a fading.
\pgfinterruptpicture%
% Need to set the bounding box manually. Include the \fadingsep border.
\endpgfinterruptpicture%
}%
\fi%
}
}
\begin{document}

\begin{tikzpicture}[line cap=round, line join=round]

\path[top color=blue, bottom color=green, line cap=rect, fading sep=1cm,
[draw=transparent!0, line width=1cm, -stealth] (-1.5,3) -- (1.5,3)
}];

\path [left color=red, right color=blue, shaded path={
[draw=transparent!0, ultra thick, -stealth] (2,-1.5) .. controls ++(0,2) and ++(0,-2) .. (-2,1.5)
}];

\path [top color=green, bottom color=yellow,
[draw=transparent!25,   ultra thick, dashed,    stealth-stealth] (-2,-1.5) -- (2,1.5)
}];

\path [left color=orange, right color=purple,
[draw=transparent!0, very thick, loosely dotted, stealth-stealth] (240:2 and 1.5) arc (240:-60:2 and 1.5)
}];

\path [left color=black!5, right color=black,
[draw=transparent!20, very thick, <->,
decoration={zigzag, segment length=0.125cm, amplitude=0.0625cm, pre length=0.25cm, post length=0.25cm},
decorate] (-3, 0) -- (3,0)
}];

\end{tikzpicture}

\end{document}


OK, so here is a version in which the path can be specified in the usual way. A bit more fooling around has to be done to get the bounding boxes right. The result is the same as above.

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}

\makeatletter

\tikzset{
% There are three circumstances in which the fading sep is needed:
% 1. Arrows which do not update the bounding box (which is most of them).
% 2. Line caps/joins and mitres that extend outside the natural bounding
%    box of the path (these are not calculated by PGF).
% 3. Other reasons that haven't been anticipated.
% Prevent this stuff happning recursively.
\else%
% \tikz@addmode installs the modes' (e.g., fill, draw, shade)
% to be applied to the path. It isn't usualy for doing more
% changes to the path's construction.
% Get the boudning box of the current path size including the fading sep
% Clear the path
\pgfsetpath\pgfutil@empty%
% Interrupt the path and picture to create a fading.
\pgfinterruptpath%
\pgfinterruptpicture%
% Set the softpath. Any transformations in #1 will have no effect.
% This will *not* update the bounding box...
% ...so it is done manually.
\expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
\expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
};
% Now get the bounding of the picture.
%
\endpgfinterruptpicture%
\endpgfinterruptpath%
% Shift the fading to the mid point of the rectangle
}%
\fi%
}
}

\begin{document}

\begin{tikzpicture}[line cap=round, line join=round]

\path[top color=blue, bottom color=green, line cap=rect, fading ysep=.75cm,
(-1.5cm,3cm) -- (1.5cm, 3cm);

\path [left color=red, right color=blue, shading path={draw=transparent!0, ultra thick, Stealth-Stealth}]
(2,-1.5) .. controls ++(0,2) and ++(0,-2) .. (-2,1.5);

\path [top color=green, bottom color=yellow,
shading path={draw=transparent!25,  ultra thick, dashed,    stealth-stealth}]
(-2,-1.5) -- (2,1.5);

\path [left color=orange, right color=purple,
shading path={draw=transparent!0, very thick, loosely dotted, stealth-stealth}]
(240:2 and 1.5) arc (240:-60:2 and 1.5);

\path [left color=black!5, right color=black,
decoration={zigzag, segment length=0.125cm, amplitude=0.0625cm, pre length=0.25cm, post length=0.25cm},
decorate}]
(-3, 0) -- (3,0);

\end{tikzpicture}

\end{document}


So, version 3. This one enables everything to be specified in the 'usual' way and the shade path key sorts everything else out. Unlike the previous versions this version should take care of transformations like rotation, shifting, scaling and so on. Like the previous versions however, it is basically a colossal hack: all sorts of tortuous coding is used to make things work, and may break in some circumstances. The result is the same as the first picture.

Note also, that it is possible to say draw=white rather than draw=transparent!0.

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}

\makeatletter

\tikzset{
% There are three circumstances in which the fading sep is needed:
% 1. Arrows which do not update the bounding box (which is most of them).
% 2. Line caps/joins and mitres that extend outside the natural bounding
%    box of the path (these are not calculated by PGF).
% 3. Other reasons that haven't been anticipated.
}

% to be applied to the path. It isn't usualy for doing more
% changes to the path's construction.
\else%
% Get the current path.
% Get the shading sep without setting any other keys.
\begingroup%
\pgfsys@beginscope% <- may not be necessary
\tikzset{#1}%
\pgfsys@endscope%
\endgroup
\tikz@tmp%
% Get the boudning box of the current path size including the shading sep
% Clear the path
\pgfsetpath\pgfutil@empty%
% Save the current drawing mode and options.
\let\tikz@options@saved=\tikz@options%
\let\tikz@mode@saved=\tikz@mode%
\let\tikz@options=\pgfutil@empty%
\let\tikz@mode=\pgfutil@empty%
% \tikz@options are processed later on.
\pgfinterruptpath%
\pgfinterruptpicture%
\pgfscope%
\path \pgfextra{%
% Set the softpath. Any transformations,draw=none} in #1 will have no effect.
% This will *not* update the bounding box...
% ...so it is done manually.
\expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
\expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
% Install the drawing modes and options.
\let\tikz@options=\tikz@options@saved%
\let\tikz@mode=\tikz@mode@saved%
};
% Now get the bounding box of the picture.
\endpgfscope
\endpgfinterruptpicture%
\endpgfinterruptpath%
\pgftransformreset%
%
% Reset all modes.
\let\tikz@path@picture=\pgfutil@empty%
\tikz@mode@fillfalse%
\tikz@mode@drawfalse%
%\tikz@mode@tipsfalse%   <- To have successful compilation with pgf-tikz v3.0.1a
\tikz@mode@doublefalse%
\tikz@mode@clipfalse%
\tikz@mode@boundaryfalse%
\tikzset{#1}%
\tikz@mode%
% Shift the fading to the mid point of the rectangle
}%
\fi%
}
\tikzset{
}
}
\makeatother % <- To close the \makeatletter call

\begin{document}

\begin{tikzpicture}[line cap=round, line join=round]

\path[draw=transparent!0, line width=1cm, line cap=butt, -stealth,
(-1.5,3) -- (1.5, 3);

ultra thick, -stealth]
(2,-1.5) .. controls ++(0,2) and ++(0,-2) .. (-2,1.5);

\path [rotate=90, scale=0.5, draw=transparent!25,   ultra thick, dashed, stealth-stealth,
(-1.5,-2) -- (1.5,2);

\path [draw=transparent!0, very thick, loosely dotted, stealth-stealth,
(240:2 and 1.5) arc (240:-60:2 and 1.5);

\path [shade path={left color=black!5, right color=black}, draw=transparent!20, very thick, <->,
decoration={zigzag, segment length=0.125cm, amplitude=0.0625cm, pre length=0.25cm, post length=0.25cm},
decorate,]
(-3, 0) -- (3,0);

\end{tikzpicture}

\end{document}

• Related question: Tikz: Shading a path without any filling – Qrrbrbirlbel Oct 11 '13 at 18:44
• Can’t we use the soft path so that we don’t need to give the path as a value to a key but as usual? – Qrrbrbirlbel Oct 11 '13 at 18:53
• @Qrrbrbirlbel, it is (sort of) possible as I show above. The principle problem is that setting the softpath directly does not update the bounding box which is required for the fading definition. This must, therefore be saved before creating the fading and manually adjusted for line width etc. – Mark Wibrow Oct 11 '13 at 19:53
• Also there is the question of whether it is logical to separate the fading path specification and the options (i.e., line width, arrows etc) for the fading path (which as far as I can see cannot be specified in the 'usual' way). – Mark Wibrow Oct 11 '13 at 19:56
• @MarkWibrow I think this is a more scalable solution to my problem, though I don't quite understand how it works ^^, thanks a lot! – windy Oct 12 '13 at 7:30

Here is a solution using single arrow shape (from the shapes.arrows library).

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.arrows}
\begin{document}
\begin{tikzpicture}
\node[single arrow,top color=blue,bottom color=green]{example};
\end{tikzpicture}
\end{document}


• @Jake Very good advice! ;-) – Paul Gaborit Oct 12 '13 at 6:21

With Tikz (no pgflibrary), this alternative yields

where any shape can be drawn via coordinates (Arrow is an example here).

\documentclass[]{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\filldraw[top color=blue, bottom color=green]
(0,-0.5)-- (1,-0.5)--(1,-1)--(2,0)--(1,1)--(1,0.5)--(0,0.5)--cycle;
\end{tikzpicture}
\end{document}