5

I am trying to generate a sort of heat map. I have a set of zones (rectangles) and each of these zones has a given density. I want to color now these zones according to a predefined heatmap and maybe also add a legend. Currently I'm just drawing recantgles without adding color and just writing the value inside the rectangle.

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes}
\begin{document}
    \begin{tikzpicture}
    \draw [fill=black!15,opacity=.5] (2,11) rectangle (6,7);
    \draw node at (4,9)  {(91.4)};       
    \draw [fill=black!25,opacity=.5] (2,7) rectangle (6,2);
    \draw node at (4,5)  {(44.6)};       
    \draw [fill=black!35,opacity=.5] (6,11) rectangle (10,9);
    \draw node at (8,10)  {(87.3)};      
    \end{tikzpicture}
\end{document}

But I would prefer a visualization like that, which means taking the value of the rectangle and calculating the heat according to something like that: Gradient heat color zones with density

As this is only a small example a generation from a table, which contains all the information, would be interesting too. Below is the table of excel tex example. I normaly have the data in excel. but copy paste the data into the tex file would be still a very good solution for me.

Zone  X1  Y1  X2  Y2  value
   1   2  11   6   7   91.4
   2   2   7   6   2   44.6
   3   6  11  10   9   87.3

Does anybody have an idea. All examples I found where mostly coloring normal tables but not rectangles with different sizes. This is something I ment for the the table: Heat Map Example

  • Welcome! You can optimize your code: \draw [fill=black!15,opacity=.5] (2,11) rectangle node {(91.4)} (6,7);. You can do something like what you want with e.g. \fill[inner color=<color>, outer color=<color>]. Where does this table come from, would it be possible to generate LaTeX code at the source of this data and write it to a file? – Tom Bombadil Dec 15 '15 at 16:23
  • 1
    Please post a complete minimal example as this is much more useful (copy-paste-compile). If you want to generate them from data, sample from the table is also essential. – cfr Dec 15 '15 at 17:08
  • 2
    Thank you for your advise. As this was my first question. I was maybe a bit unprecise. I updated my post and added a full example now in the code. So would I'm looking for is, that the color is calculated according the values in the recantangle (first recangle for example 91.4) like in a classical heat map. – Paul Dec 15 '15 at 20:22
  • 1
    What are the colors based on? For yellow/orange/red, the outer color is white, while the fourth appears to be dark blue to grayish blue. Do you want the color to change based on the value, or do you simply want to know how to get a radial shading? – Tom Bombadil Dec 15 '15 at 20:29
  • 1
    So the shading should be smoothly, or abruptly (for instance 6 intervals, all values in one interval get the same color)? While both are possible to compute in LaTeX, have you considered doing the computations in Excel? There you have for instance the CONCATENATE() function which you can use to produce LaTeX code that you then can copy. On the topic of varying color smoothly: have you had a look at the xcolor manual? It has nice facilities like colorA!percentage!colorB for nice color transitions. – Tom Bombadil Dec 15 '15 at 21:04
2

Here's two versions: one for intervals and therefore jumps, the other one with smooth color transitions. You can use the \getincolor and \getoutcolor macros to define colors that the colors should cycle through. For \ColorSteps you'll need to specify as many colors as \ColSteps says, for \ColorGradients you'll need to specify one more than \ColIntervals says, as the colors are the colors of the edges of the interval. To illustrate the differences, both images contain 100 regions with values from 0 to 99. As the commands need to know relative to what they should scale, you'll need to provide \MinVal and \MaxVal, the minimum and maximum values that can occur.

Code

\documentclass[tikz, border=2mm]{standalone}

\newcommand{\ColorSteps}[4][black]%
% [draw color], sw, ne, value
{   \pgfmathsetmacro{\IW}{(\MaxVal-\MinVal)/\ColSteps}
    \pgfmathsetmacro{\IN}{div(#4-\MinVal,\IW)}
    \shade[inner color=\getincolor{\IN}, outer color=\getoutcolor{\IN}, draw=#1] (#2) rectangle (#3);
}

\newcommand{\ColorGradients}[4][black]%
% [draw color], sw, ne, value
{   \pgfmathsetmacro{\IW}{(\MaxVal-\MinVal)/\ColIntervals}% interval width
    \pgfmathsetmacro{\IN}{div(#4-\MinVal,\IW)}% interval number
    \pgfmathsetmacro{\NIN}{\IN+1}% next interval number
    \pgfmathsetmacro{\IP}{mod(#4-\MinVal,\IW)/\IW*100}% interval percentage
    \colorlet{InColorA}{\getincolor{\IN}}
    \colorlet{InColorB}{\getincolor{\NIN}}
    \colorlet{OutColorA}{\getoutcolor{\IN}}
    \colorlet{OutColorB}{\getoutcolor{\NIN}}
    \shade[inner color=InColorB!\IP!InColorA, outer color=OutColorB!\IP!OutColorA, draw=#1] (#2) rectangle (#3);
}

\newcommand{\getincolor}[1]%
{\ifcase#1 black% color 0
    \or blue% color 1
    \or cyan% ...
    \or green%
    \or yellow%
    \or red%
    \or violet%
    \or white% color 7
    \else gray% any number > 7
    \fi
}

\newcommand{\getoutcolor}[1]%
{\ifcase#1 black!30!white%
    \or blue!30!white%
    \or cyan!30!white%
    \or green!30!gray%
    \or yellow!30!gray%
    \or red!30!gray%
    \or violet!30!gray%
    \or white!30!gray%
    \else gray%
    \fi
}

\begin{document}

\pgfmathsetmacro{\MinVal}{0}
\pgfmathsetmacro{\MaxVal}{100}

\pgfmathsetmacro{\ColSteps}{8}

\begin{tikzpicture}
    \foreach \x in {0,...,9}
    {   \foreach \y in {0,...,9}
        {   \ColorSteps{\x,\y}{\x+1,\y+1}{10*\y+\x}
        }
    }
\end{tikzpicture}

\pgfmathsetmacro{\ColIntervals}{7}

\begin{tikzpicture}
    \foreach \x in {0,...,9}
    {   \foreach \y in {0,...,9}
        {   \ColorGradients{\x,\y}{\x+1,\y+1}{10*\y+\x}
        }
    }
\end{tikzpicture}

\end{document}

Output

enter image description here

enter image description here

  • Very nice! I was waiting for your answer... ;). – cfr Dec 15 '15 at 22:26
  • @cfr: Thanks! I admit I might have started working on it a few hours ago ;) – Tom Bombadil Dec 15 '15 at 22:28
  • I know. I saw you here earlier.... – cfr Dec 15 '15 at 22:29
  • wow, cool, thanks, that looks very good. Thanks a lot :) – Paul Dec 15 '15 at 22:50
  • 1
    I hope you won't mind my posting a small supplement. – cfr Dec 15 '15 at 23:10
4

This is a minor extension of Tom Bombadil's answer which demonstrates how to merge values from another file with the format specified in the question. You need to remove the header row so that you have just the values.

The additions are just these

\usepackage{textmerg}

this package will merge the data in for us.

\tikzset{%
  make zone/.code args={#1 #2 #3 #4 #5 #6}{%
    \ColorGradients{#2,#3}{#4,#5}{#6}
  },
}

make zone is a TikZ style which will turn the row of values into the required rectangle. It is just a wrapper for \ColorGradients.

We define the fields in the data file. Each row is a field, so we'll have one field per rectangle with the six values contained in it. We'll use \zone for the field.

\Fields{\zone}

\makezone takes one argument (the row of values) and applies the make zone style.

\newcommand*\makezone[1]{%
  \tikzset{make zone={#1}}}

Start the picture.

\begin{tikzpicture}

Now we merge in data from the file. We assume that if the .tex file is called <filename>.tex, the data file is called <filename>.dat.

  \Merge{\jobname.dat}{

Now we actually create the zone itself. Everything within this second argument of \Merge will be done for each \zone in the data file specified in the first argument. Since our data file has 3 lines, we should get 3 rectangles.

  \expandafter\makezone\expandafter{\zone}

Close out the merge.

  }
\end{tikzpicture}

And we do get the 3:

zones

Complete code (mostly Tom Bombadil's):

\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{textmerg}
% colour coding is all from Tom Bombadil's answer at https://tex.stackexchange.com/a/283270/
\newcommand{\ColorSteps}[4][black]%
% [draw color], sw, ne, value
{   \pgfmathsetmacro{\IW}{(\MaxVal-\MinVal)/\ColSteps}
    \pgfmathsetmacro{\IN}{div(#4-\MinVal,\IW)}
    \shade[inner color=\getincolor{\IN}, outer color=\getoutcolor{\IN}, draw=#1] (#2) rectangle (#3);
}
\newcommand{\ColorGradients}[4][black]%
% [draw color], sw, ne, value
{   \pgfmathsetmacro{\IW}{(\MaxVal-\MinVal)/\ColIntervals}% interval width
    \pgfmathsetmacro{\IN}{div(#4-\MinVal,\IW)}% interval number
    \pgfmathsetmacro{\NIN}{\IN+1}% next interval number
    \pgfmathsetmacro{\IP}{mod(#4-\MinVal,\IW)/\IW*100}% interval percentage
    \colorlet{InColorA}{\getincolor{\IN}}
    \colorlet{InColorB}{\getincolor{\NIN}}
    \colorlet{OutColorA}{\getoutcolor{\IN}}
    \colorlet{OutColorB}{\getoutcolor{\NIN}}
    \shade[inner color=InColorB!\IP!InColorA, outer color=OutColorB!\IP!OutColorA, draw=#1] (#2) rectangle (#3);
}
\newcommand{\getincolor}[1]%
{\ifcase#1 black% color 0
    \or blue% color 1
    \or cyan% ...
    \or green%
    \or yellow%
    \or red%
    \or violet%
    \or white% color 7
    \else gray% any number > 7
    \fi
}
\newcommand{\getoutcolor}[1]%
{\ifcase#1 black!30!white%
    \or blue!30!white%
    \or cyan!30!white%
    \or green!30!gray%
    \or yellow!30!gray%
    \or red!30!gray%
    \or violet!30!gray%
    \or white!30!gray%
    \else gray%
    \fi
}

\begin{document}

\pgfmathsetmacro{\MinVal}{0}
\pgfmathsetmacro{\MaxVal}{100}    
\pgfmathsetmacro{\ColIntervals}{7}

\tikzset{%
  make zone/.code args={#1 #2 #3 #4 #5 #6}{%
    \ColorGradients{#2,#3}{#4,#5}{#6}
  },
}
\Fields{\zone}
\newcommand*\makezone[1]{%
  \tikzset{make zone={#1}}}
\begin{tikzpicture}
  \Merge{\jobname.dat}{
  \expandafter\makezone\expandafter{\zone}
  }
\end{tikzpicture}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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