Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

How do I draw a triangle in tikz with "point colours" so that every point in the triangle is coloured according to the weighted (by distance) average colour of the corners.

share|improve this question
    
This sounds like a very difficult problem. What you want is to basically recreate the RGB triangle for aribtrary vertex colours. This sounds very tricky. Could you explain why you want to do this? –  Seamus Mar 30 '11 at 22:07
    
I am nothing close to a pro, so please bear with me. But actually it might not be such a difficult problem if any pro guys here can address the color mixing problem. There is some hint in Tikz manual about \pgfdeclarefunctionalshading . What I have in mind is to apply clipping a triangle and and a gradient shading simultaneously. Then this can be rendered pretty fast compared to pointwise coloring. There is this section about fading in the manual but I am not sure about the availability. –  percusse Mar 30 '11 at 23:58
    
@Seamus: I just want the RGB triangle (with some other stuff overlayed.) I thought there might be some way of defining point colours in tikz, but I guess not.... –  Neil G Mar 31 '11 at 0:00
    
@percusse: sounds really cool. –  Neil G Mar 31 '11 at 0:00
1  
If tikz had a way to generate PDF type 4 shadings (free-form Gouraud-shaded triangle mesh), described in section 8.7.4.5.5 of the PDF spec, then this would be extremely simple. Getting the same result using type 1 (function-based) shading, as you get with \pgfdeclarefunctionalshading is possible, but more tricky (and harder for the PDF viewer to render). –  Lev Bishop Mar 31 '11 at 14:56
add comment

5 Answers 5

up vote 18 down vote accepted

I feel that the other answers given are perhaps a little overcomplicated! If you want the triangle exact then maybe they are the best way to go. But if you want something that just looks about right, then there is a much simpler way to do this using ordinary fadings.

(Added in edit: I've updated this a little to try to correct the colour bias. The red colour is now correct and the green/blue are relatively correct. That is, the green and blue are correct at the bottom of the triangle, but as you move up the sides then some blue gets mixed in with the green and vice-versa. However, before it gets too noticeable, the red swamps the picture so it's actually quite close to the Real Thing.)

Here's the result:

RGB triangle in TikZ

Here's the code:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fadings}
\begin{document}
\begin{tikzpicture}
\fill[green] (90:4) -- (210:4) -- (-30:4) -- cycle;
\fill[blue,path fading=west] (90:4) -- (210:4) -- (-30:4) -- cycle;
\fill[red,path fading=south] (90:4) -- (210:4) -- (-30:4) -- cycle;
\end{tikzpicture}
\end{document}
share|improve this answer
    
Good idea! Note however, that this also renders incorrectly with Evince (and probably anything else based on Poppler). –  Caramdir Mar 31 '11 at 16:28
    
This is really nice. But that's exactly what I meant by color mixing problem in my original comment. Above all, looks good enough. –  percusse Mar 31 '11 at 19:19
    
@percusse: I think that Caramdir's answer is more what you had in mind. Note that my answer was posted after the other ones and is very definitely intended as a "if you want something that just looks about right" answer, not a perfect one. –  Loop Space Mar 31 '11 at 19:25
    
Very nice example! I added it to the TikZ example gallery, I hope that's ok for you: texample.net/tikz/examples/rgb-triangle –  Stefan Kottwitz Dec 22 '11 at 0:14
add comment

PGF provides functional shadings. The following works by calculating the barycentric coordinates of a equilateral triangle from the Cartesian coordinates (see Wikipedia) and using those as the RGB color.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shadings}
\begin{document}
\begin{tikzpicture}
\pgfdeclarefunctionalshading{rgbtriangle}
{\pgfpointorigin}{\pgfpoint{100bp}{86.60bp}}{}{
    % y coordinate is on top of the stack, x below it
    % divide both by 100 to get numbers in [0,1]
    100 div exch 100 div exch
    % save a copy of the coordinates
    2 copy
    % calculate red amount
    0.5774 mul add neg 1 add
    % bring copy of the coordinates to the top
    3 1 roll
    % calculate green amount
    0.5774 mul neg add 
    % calculate blue as (1-red-green)
    2 copy
    add 1 sub neg
}
\clip[shift={(-50bp,{-25bp*sqrt(3)})}] (0,0) -- (50bp,{50bp*sqrt(3)}) -- (100bp,0) -- cycle;
\pgfuseshading{rgbtriangle}
\end{tikzpicture}
\end{document}

result in Adobe

The PGF manual has a warning:

These shadings are the least portable of all and they put the heaviest burden of the renderer. They are slow and, possibly, will not print correctly!

In fact, Evince (and probably most Linux pdf viewers) renders the above document as

result in Evince


I keep playing around with this. The most portable solution seems to be the one by Altermundus. Here it is encapsulated into a macro and with some optimizations

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document} 

% arguments:
%   number of subdivision (optional)
%   side length
\newcommand\colortriangle[2][50]{
    \begin{scope}[shift={({-#2/2},{-sqrt(3)/6*#2})}]
        \coordinate(A) at (0, 0);
        \coordinate(B) at (#2, 0);
        \coordinate(C) at (60:#2);
        \clip (A) -- (B) -- (C) -- cycle;
        \pgfmathsetmacro\delta{1/#1}
        \pgfmathsetmacro\r{\delta*1.2*#2}
        \edef\r{\r pt}
        \foreach \x in {0,\delta,...,1} {
            \pgfmathsetmacro\t{1-\x}
            \foreach \y in {0,\delta,...,\t} {
                \pgfmathsetmacro\z{1-\x-\y}
                \definecolor{mycolor}{rgb}{\x, \y, \z}      
                \coordinate (mypoint) at (barycentric cs:A=\x,B=\y,C=\z); 
                \path[fill=mycolor] (mypoint) rectangle ($(mypoint)+(\r,\r)$);
            }
        }
    \end{scope}
}

\begin{tikzpicture}
    \colortriangle[40]{4cm}
\end{tikzpicture}
\end{document}

For sufficiently small many subdivision, the triangle looks passably smooth and should render correctly in most PDF viewers. It does however draw O(subdivisions²) rectangles and compilation time scales accordingly. So you might want to use the externalization library of TikZ. The above example compiles in about 2.9s on my computer and produces

result

share|improve this answer
    
Amazing! Thank you. –  Neil G Mar 31 '11 at 3:08
    
@Neil: Be aware of the warning: This will possibly not render and print correctly, in particular when not using Adobe Acrobat. –  Caramdir Mar 31 '11 at 3:10
add comment

Only for the fun but perhaps it's possible with postcript macros 84.2.3 General (Functional) Shadings of pgfmanual cvs. The code is very slow to compile a better will be to draw triangles (node) instead of circles. The Caramdir's answer proves that my idea was fine. I use the comment to change my answer, always for the fun ...This is perhaps always wrong but it's a more correct answer than my first one.

\documentclass{scrartcl}
\usepackage[usenames,dvipsnames]{xcolor}  
\usepackage{tikz}

\begin{document} 

\begin{tikzpicture}
\coordinate(A) at (0, 0);
\coordinate(B) at (1, 0);
\coordinate(C) at (60:1);

\foreach \x in {0.05,0.1,...,.95} 
\foreach \y in {0.05,0.1,...,.95}
\foreach \z in {0.05,0.1,...,.95}
{\definecolor{mycolor}{rgb}{\x, \y, \z}      
\coordinate (mypoint) at (barycentric cs:A=\x,B=\y,C=\z);
\path[fill=mycolor] (mypoint) circle (.04); }

\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
According to the problem description, the center should be RGB(0.33,0.33,0.33). You should have y ∈ [0,1-x] and z=1-x-y. –  Caramdir Mar 31 '11 at 2:58
    
I would like to make something like your answer but I don't know the postscript functions. Bravo for your answer!! –  Alain Matthes Mar 31 '11 at 5:12
    
@Caramdir I changed the code to give a solution better than the first one, perhaps it's possible to find something correct with this idea ? –  Alain Matthes Mar 31 '11 at 7:22
add comment

I am fully aware that this post is quite old.

However, due to the remark of Lev Bishop that this would be very simple if TikZ would support "PDF type 4 shadings (free-form Gouraud-shaded triangle mesh)", I wanted to add a matching example.

pgfplots can generate type 4 shadings, and since version 1.8, it can do so for both colormaps and explicit colors (the latter has been added after pgfplots: color a (3D) surf using arbitrary RGB colors).

Here is a type 4 shading with explicitly colored vertices:

\documentclass{standalone}

\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}[title=RGB shading]
    \addplot[
        patch,
        shader=interp,
        mesh/color input=explicit,
        data cs=polar,
    ]
    coordinates {
        (90,4) [color=red]
        (210,4) [color=green]
        (-30,4) [color=blue]
    };
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

The example above is a patch plot with interpolated shading. The coordinates are given in polar coordinates due to data cs=polar.

This example can be generalized easily to more than one triangle (or other primitive forms like rectangles or bezier shapes). Here is an example with different color specifiers which results in three triangular patches:

\documentclass{standalone}

\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\begin{axis}[minor x tick num=1]
    \addplot[
        patch,
        shader=interp,
        mesh/color input=explicit,
    ]
    table[meta=c] {
        x y c
        0 0 color=green
    % default color model is rgb:
        1 1 1,0,0
        2 0 1,1,0
        1.5 1 cmyk=1,0,0,0
        2.5 0 gray=0.5
        3.5 1 color=red!80!black
        3 0 1,0,1
        4 1 0,0,1
        5 0 rgb255=0,128,128
    };
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

Finally, this kind of shading is sometimes quite useful if you have scalar color values which are mapped into a colormap. In this scenario, the smallest scalar values gets the first color of the colormap, the largest the last color. Everything else is interpolated accordingly. A colormap typically has more than one color which participates. Here is also an example:

\documentclass{standalone}

\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}[title=RGB shading with colormap,colorbar]
    \addplot[
        patch,
        shader=interp,
        point meta=explicit,
        data cs=polar,
    ]
    coordinates {
        (90,4) [0]
        (210,4) [1]
        (-30,4) [2]
    };
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

This last example makes it very clear that triangle interpolation is linear.

share|improve this answer
    
This is a solution which is very useful for data visualization. If someone wants to use my solution in order to insert such shadings neatlessly in a pure tikz picture without the rescaling applied by pgfplots (i.e. not data visualization), one would need extra steps which are discussed in the pgfplots manual, Section "TikZ Interoperability" –  Christian Feuersänger Aug 11 '13 at 6:41
add comment

enter image description here

Just one more way to get a Gouraud-shaded triangle: tri.asy:

size(400);
pen[] p={red,green,blue};
pair[] z={(0,1),rotate(120)*(0,1),rotate(-120)*(0,1)};
int[] edges={0,1,2};
gouraudshade(z[0]--z[1]--z[2]--cycle,p,z,edges);

To get a standalone tri.pdf, run asy -f pdf tri.asy.

Edit (suggested by Andrew Stacey): Here asy is the command that invokes Asymptote.

share|improve this answer
1  
For those, like myself, who've never used it, I'd like to add that asy is the command that invokes Asymptote. –  Loop Space Aug 10 '13 at 19:10
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.