7

Ok, this is probably an incredibly trivial question for anyone who knows more about xcolor or pgf or TikZ or whatever really. I tried to use a hue scale for a heat map/color matrix with values 0<=x<=1. I based this heavily on this answer by adn:

\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}

\usepackage{xstring}

\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}\IfDecimal{##1}{%
                \cellcolor[hsb]{##1,.7,1.}}{}##1}%
                },
        columns/x/.style={
            column name={},
            postproc cell content/.code={}
        }
    }
}

\begin{document}
\begin{table}\caption{Correlation or something}
\centering
\pgfplotstabletypeset[color cells]{
x,a,b,c,d
a,0.9,0.3,-.1,0
b,0,.8,.6,.4
c,1,0.2,.95,.5
d,0,.1,.7,.85
}
\end{table}
\end{document}

This looks like this:

very colorful table

Colorful, but it does what it's supposed to do, even for small negative numbers which aren't supposed to exist ... except:

0 and 1 yield the same color

For a value of 1 the hue wraps around and is back to 0/red again. I tried to subtract a tiny value or multiply the cell content internally by .99 or something but I simply failed to do any arithmetic here.


PS: If you can recommend any good documentation for xcolor, pgf and the like, that'd be great, too. Maybe next time I won't have to ask such stupid questions then.


Edit:

Ok, I didn't do my homework very well. The HSB color space doesn't suddenly wrap around. It is actually circular. This means that purple (RGB [1, 0, 1]) is at 300° which according to my calculations is the very handy number .8333... in decimal. So one would have to map one interval to another which in this case should be rather simple: just multiply the value by .8333.

Christian
  • 19,238
  • 1
    Note that changing only hue value is usually a bad idea when presenting colored values. See http://www.research.ibm.com/people/l/lloydt/color/color.HTM – liori Nov 22 '12 at 21:32
  • @liori Hm, interesting. But varying the luminance would require some stunts in order not to make the text in the cells illegible, would it not? Do you have any experience what gradient works best for such an application as a color matrix? – Christian Nov 22 '12 at 21:46
  • 1
    In my cases I just limited the variability so that the text was still legible. The easiest is when you keep the same hue and keep value at maximum, and use saturation… so basically you get a color-to-white gradient. As the article says, it's always about what you really want to expose: minima, maxima, some values in the middle? – liori Nov 22 '12 at 23:01
  • 1
    It seems as if you are bound to HSB colorspace... if not, you may be interested in my recent answer to the related question http://tex.stackexchange.com/questions/44868/drawing-heatmaps-using-tikz/83865#83865 – Christian Feuersänger Nov 23 '12 at 09:14
  • @ChristianFeuersänger No, HSB/HSV is just the easiest way to do a rainbow map. Doing that with a custom defined gradient is a bit cumbersome. But since I learned that rainbow maps should be avoided anyway, your solution seems very flexible and powerful. Thanks for pointing me to it! – Christian Nov 23 '12 at 10:21
  • @liori I think I kinda like the Red-LightYellow-Green scale, so I'm currently using the slightly unwieldy \pgfmathtruncatemacro\mymixture{min(100,max(0,##1*100))}\pgfmathparse{min(100,max(0,abs(##1-.5)*100+50))}\edef\x{\noexpand\cellcolor{green!\mymixture!red!\pgfmathresult!yellow!80!gray!\pgfmathresult!white}}\x##1. The solution Christian just proposed might make this a bit more legible. – Christian Nov 23 '12 at 10:25
  • @liori It's been a while but I'd like to thank you again for the link you provided. It was quite a revelation and at the same time it made my tables a million times more beautiful and much more comprehensible at the same time. I can now use a nice color scheme and have an esthesiophysiological reason why it's a good idea. If all had been rainbow-colored ... I dare not think of it. Thanks a million! – Christian Mar 07 '13 at 20:07
  • @liori Sorry, can't get over this. Ever since you sent me that link, I'm getting pissed when I see those representations of the cosmic microwave background where you can only see big color blobs: http://sci.esa.int/planck/52886-cosmic-microwave-background-seen-by-planck-equirectangular-projection/ – Christian Mar 23 '14 at 03:11
  • 1
    @Christian: always happy to help! ;-) – liori Mar 23 '14 at 12:57

2 Answers2

6

I'm pretty sure I don't understand the question but this forces things that are >=1 to 0.99 and things that are <= 0 to 0.01.

\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}\IfDecimal{##1}{%
      \edef\tmp{\noexpand\cellcolor[hsb]{%
       \ifdim##1pt>0pt  \ifdim##1pt<1pt ##1 \else 0.99 \fi \else 0.01\fi,.7,1.}}%
                \tmp}{}##1}%
                },
        columns/x/.style={
            column name={},
            postproc cell content/.code={}
        }
    }
}
David Carlisle
  • 757,742
  • You didn't really have a good chance of understanding my question because it was nonsense without me realizing. I should have understood the HSB color space before messing with it. I updated my question. Your solution does exactly what I wanted it to. It just doesn't look any different from my version. I'm very sorry for the confusion :/ – Christian Nov 22 '12 at 21:11
  • For the record, going from red to blue instead of red to purple might actually be a good idea if you have such a chaotic map (unless @liori comes up with something completely different and even better that is). The magic factor is 0.66667 then. – Christian Nov 22 '12 at 21:59
6

For the arithmetics, you can check if the argument is negative to see whether a max or min should be performed and then you can use the \pgfmathresult in the \cellcolor. But it's value should be expanded before \cellcolor see it as a macro. Hence along the lines of David's answer you can hide it into a expanding definition, expand it and then execute it.

\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}

\usepackage{xstring}

\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}%
                         \pgfmathparse{##1<0?max(0,##1):min(0.99,##1)}%
                         \edef\x{\noexpand\cellcolor[hsb]{\pgfmathresult,0.7,1.0}}\x##1%
            }
        },
        columns/x/.style={
            column name={},
            postproc cell content/.code={}
        }
    }
}

\begin{document}
\begin{table}\caption{Correlation or something}
\centering
\pgfplotstabletypeset[color cells]{
x,a,b,c,d
a,0.9,0.3,-.1,0
b,0,.8,.6,.4
c,1,0.2,.95,.5
d,0,.1,.7,.85
}
\end{table}
\end{document}

Then the result is hopefully correct (Colorblind here). There is nothing wrong with the question by the way. Here are the manuals for all packages :-) TeXdoc.net

enter image description here


Edit

The code can easily be adapted to fit the changed question like this:

\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}%
                         \pgfmathparse{0.8333*##1}%
                         \edef\x{\noexpand\cellcolor[hsb]{\pgfmathresult,0.7,1.0}}\x##1%
            }
        },
        columns/x/.style={
            column name={},
            postproc cell content/.code={}
        }
    }
}

The result then looks like this:

fixed matrix

Christian
  • 19,238
percusse
  • 157,807
  • That's a useful link. texdoc xcolor for example doesn't find anything for me but this site does. Thanks to both of you for the answer. I should have understood the HSB color space better though. What you actually want for such a color matrix is to map [0, 1] to [0, .8333]. The hue doesn't suddenly wrap around between .999 and 1, it's rather that the whole thing is circular. I will adapt the question accordingly, sorry :/ – Christian Nov 22 '12 at 21:02
  • @Christian So then replacing the operation with 0.8333*##1 fix it no? – percusse Nov 22 '12 at 21:20
  • Yep, that works perfectly :) – Christian Nov 22 '12 at 21:48