21

I'm trying to create a smooth gradient between cyan and blue connecting two shapes, one drawn in cyan and one in blue. For that I use a simple mix of the two colors in a \foreach loop.

However, in the first step of the mix, despite having only 0.5% blue mixed with (presumably) 99.5% cyan, the resulting color differs drastically from pure cyan.

What am I missing and how can the effect be properly achieved? To be clear: what colors and in what ratios should be mixed to achieve the first step from pure cyan towards pure blue?

MWE:

\documentclass[tikz]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \draw[cyan,fill=cyan] (0,0) rectangle (1,1);
    \draw[blue!0.5!cyan,fill=blue!0.5!cyan] (1,0) rectangle (2,1);
\end{tikzpicture}
\end{document}

and the output:

color mix example

Here is the problem presented while using \shade:

\documentclass[tikz]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
  \shade[left color=blue,right color=cyan] (0,0) rectangle (2,1);
  \draw[cyan,fill=cyan] (2,0) rectangle (3,1);
\end{tikzpicture}
\end{document}

and the result:

problem when using shade

The problem was solved by @PaulGaborit and @percusse as can be seen in the comments below by setting:

\colorlet{cyan}[rgb]{cyan}

If I understand correctly, xcolor decides what color scheme to use (rgb/cym) according to the default scheme of the first color in the mix, and uses the predefined name of the second color (in this case 'cyan') under the first color's scheme. Therefore, when using basic colors from differing schemes, the higher boundary of the mix (when the second color is dominant) may differ from the default, 'pure' color.

Section 2.3.2 on page 15 of the xcolor manual (V2.11) kind of suggests that this is what happens, in retrospect.

5
  • 1
    @Rmano, I don't think so, the manual states percentages are used. moreover, replacing 0.5 by 1, 1.5, or 0.05 all result in the same large difference in colors. May 10, 2016 at 11:40
  • 7
    With xcolor, blue is defined as a RGB color and cyan is defined as a CMY color. Add \colorlet{cyan}[rgb]{cyan} in your preamble to get the correct result. May 10, 2016 at 11:48
  • 1
    @PaulGaborit Thanks Paul, that solves the issue. Can you please post it as an answer so I can mark it as the correct one? May 10, 2016 at 11:49
  • Ah seconds late :D What @PaulGaborit said
    – percusse
    May 10, 2016 at 11:49
  • @PaulGaborit Wow. That is a very subtle answer, which would not be the first thing to pop into minds. May 10, 2016 at 11:56

3 Answers 3

22

The xcolor package defines blue as a RGB color and cyan as a CMY color.

To make a mix, xcolor uses the color model of the first color and, if necessary, converts the second color.

To convert the CMY cyan to RGB cyan, you may add \colorlet{cyan}[rgb]{cyan} in your preamble.

\documentclass[tikz]{standalone}
\usepackage{tikz}
\colorlet{cyan}[rgb]{cyan}
\begin{document}
\begin{tikzpicture}
    \draw[cyan,fill=cyan] (0,0) rectangle (1,1);
    \draw[blue!0.5!cyan,fill=blue!0.5!cyan] (1,0) rectangle (2,1);
\end{tikzpicture}
\end{document}

Extract from xcolor manual (section 2.3.2 "Meaning of standard color expressions", p. 15, v2.11):

In general, the second color is transformed into the model of the first color then the mix is calculated within that model. Thus, name1!<percent>!name2 and name2!<100-percent>!name1 which should be equivalent theoretically, will not necessarily yield identical visual results.

Here is an example with three rows: default models, pure rgb model and pure cmy model.

enter image description here

\documentclass[tikz,margin=1mm]{standalone}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{tikz}
\usetikzlibrary{positioning}

\colorlet{cmycyan}{cyan}
\colorlet{rgbcyan}[rgb]{cyan}

\colorlet{cmyblue}[cmy]{blue}
\colorlet{rgbblue}{blue}

\begin{document}
\begin{tikzpicture}
  \tikzset{
    block/.style 2 args={
      draw,right=-.5\pgflinewidth of a,
      fill=#1,text=#2,
      text height=.8em,text depth=.2em,text width=3.5cm,
      font=\ttfamily\bfseries,align=center,
    },
  }
  \node[anchor=base east] (a) {default models};
  \foreach \col/\txtcol in {blue/white,blue!1!cyan/black,cyan!99!blue/white,cyan/white}{
    \node[block={\col}{\txtcol}](a){\col};
  }

  \node[anchor=base east] (a) at (0,-1) {rgb model};
  \foreach \col/\txtcol in {rgbblue/white,rgbblue!1!rgbcyan/black,rgbcyan!99!rgbblue/black,rgbcyan/black}{
    \node[block={\col}{\txtcol}](a){\col};
  }

  \node[anchor=base east] (a) at (0,-2) {cmy model};
  \foreach \col/\txtcol in {cmyblue/white,cmyblue!1!cmycyan/white,cmycyan!99!cmyblue/white,cmycyan/white}{
    \node[block={\col}{\txtcol}](a){\col};
  }
\end{tikzpicture}
\end{document}
8

I don't know the details behind this, but blue!1!cyan is not the same as cyan!99!blue.

enter image description here

\documentclass[tikz]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
    \filldraw[blue!1!cyan] (0,0) rectangle (-1,1);
    \filldraw[cyan] (0,0) rectangle (1,1);
    \filldraw[cyan!99!blue] (1,0) rectangle (2,1);
\end{tikzpicture}
\end{document}
2
  • I removed some extraneous ! signs from your text. You make an astute observation. LaTeX colors are indeed an interesting thing. May 10, 2016 at 11:34
  • 1
    @StevenB.Segletes I think the comments to the original question, and my edits to it, explain what is going on. Thanks! May 10, 2016 at 12:19
8

No need to use \colorlet. You can also specify directly the color model of the mix ... but anyway macho programmers use only wavelengths. :)

enter image description here

\documentclass{article}
\usepackage{xcolor}
\begin{document}
\colorbox{rgb:blue!1!cyan,1}{}
\colorbox{rgb:cyan!99!blue,1}{}
\colorbox[wave]{480}{}
\colorbox{cmy:blue!1!cyan,1}{}
\colorbox{cmy:cyan!99!blue,1}{}
\end{document}
1

You must log in to answer this question.

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