# How to more easily generate a normalized eigenvalue spectrum?

I'm trying to generate a normalized eigenvalue spectrum like this one:

In the above example, the normalized eigenvalues are like the following:

0.8332
0.0433
0.0310
0.0152
0.0061
0.0047
0.0035
0.0022
0.0018
0.0014
0.0013
0.0011
0.0010
0.0008
0.0007
...
and more small ones


The accumulated eigenvalues are:

0.8332
0.8765
0.9074
0.9227
0.9287
0.9334
0.9369
0.9392
0.9410
0.9424
0.9437
0.9448
0.9458
0.9467
0.9474
... and more
1


The above spectra is generated by the following (with accumulated eigenvalues):

\begin{tikzpicture}[scale=10]

\draw[ xstep=.1, ystep=0.1]  (0,0) grid (1,0.1);

\fill [red!50]               ( 0,0.008)      rectangle ( 0.8332,0.1);
\fill [purple!60]            ( 0.8332,0.008) rectangle ( 0.8765,0.1);
\fill [blue!70]              ( 0.8765,0.008) rectangle ( 0.9074,0.1);
\fill [green]             ( 0.9074,0.008) rectangle ( 0.9227,0.1);
\fill [orange]            ( 0.9227,0.008) rectangle ( 0.9287,0.1);
\fill [purple!!50!!red]   ( 0.9287,0.008) rectangle ( 0.9334,0.1);
\fill [yellow]            ( 0.9334,0.008) rectangle ( 0.9369,0.1);
\fill [purple!!50!!green] ( 0.9369,0.008) rectangle ( 0.9392,0.1);
\fill [lime]              ( 0.9392,0.008) rectangle ( 0.9410,0.1);
\fill [teal]              ( 0.9410,0.008) rectangle ( 0.9424,0.1);
\fill [teal!!20!!white]   ( 0.9424,0.008) rectangle ( 0.9437, 0.1);

%\fill [gray]              ( 0.9437,0.008) rectangle ( 1, 0.1);

\fill  [teal!!20!!white]   (0.9437,0.008) rectangle ( 0.9448,0.1);
\fill  [gray]              (0.9448,0.008) rectangle ( 0.9458,0.1);
\fill  [red]               (0.9458,0.008) rectangle ( 0.9467,0.1);
\fill  [purple]            (0.9467,0.008) rectangle ( 0.9474,0.1);
\fill  [blue]              (0.9474,0.008) rectangle ( 0.9480,0.1);
% and more ...

\draw[|<->|] (0,0.032) -- node [left, fill=red!50] {0.84} (0.5,0.032)  -- (0.8332,0.032);
\draw[|<->|] (0,0.055) -- node [fill=red!50] {0.88} (0.7, 0.055) -- (0.8765,0.055);
\draw[|<->|] (0,0.078) -- node [right, fill=red!50] {0.91} (0.9, 0.078) -- (0.9074,0.078);

\end{tikzpicture}


In the above I just choose colours manually, and copy-paste colours in visual block in Vim.

1. Here I'm wondering, how can I assign colours automatically? And then maybe I can draw the above in a for loop.

2. Is there a better way than drawing rectangles ?

EDIT. July 8 2013

The following colors seem OK for generating eigenvalue spectrum. Welcome suggestions and modifications on the color list.

\begin{filecontents}{eigenvaluesA}
% 20 value-color pairs
Values Colors
0.0500    red!50
0.1000    purple!60
0.1500    blue!70
0.2000    green
0.2500    orange
0.3000    purple!!50!!red
0.3500    yellow
0.4000    purple!!50!!green
0.4500    lime
0.5000    teal
0.5500    blue
0.6000    purple!!50!!red
0.6500    yellow
0.7000    purple!!50!!green
0.7500    lime
0.8000    teal
0.8500    yellow!!20!!white
0.9000    blue
0.9500    red
1.0000    green
\end{filecontents}


-

## 1 Answer

Starting from an input file containing values and colors, by means of a \drawspectrum macro it is possible to draw the spectrum completely automatic. There is an automatic tool also to deploy the arrowed paths with the values selected (it is automatic because it allows to both draw the lines towards the desired value and each line is vertically aligned) and the aspect can be customized with specific keys.

The code:

\documentclass[png,border=10pt,tikz]{standalone}
\usepackage{filecontents}
\usepackage{tikz,pgfplotstable}
\usetikzlibrary{calc}

\pgfkeys{/tikz/.cd,
value fill color/.get=\valfillcol, % the background color for values
value fill color=red!50,
value precision/.get=\valprintprec, % the precision of the values
value precision=2,
diagram height/.get=\diagramheight, % the height of the diagram
diagram height=1,
}

% The file should containt values and colors
\begin{filecontents}{eigenvalues.dat}
Values Colors
0.8332 red!50
0.8765 purple!60
0.9 blue!70
0.9227 green
0.9287 orange
0.9334 purple!!50!!red
0.9369 yellow
0.9392 purple!!50!!green
0.9410 lime
0.9424 teal
0.9437 teal!!20!!white
0.9448 gray
0.9458 red
0.9467 purple
0.9474 blue
1      black
\end{filecontents}

% Argument: file
\newcommand{\drawspectrum}[1]{
\pgfplotstableread{#1}{\eigenvaltab}

\pgfplotstablegetrowsof{\eigenvaltab} % Number of rows
\pgfmathsetmacro{\numrows}{\pgfplotsretval-1}

\draw (0,0) -- (10,0);

\foreach \x[evaluate=\x as \printx using \x*0.1] in {0,1,...,10}{
\pgfkeys{/pgf/number format/.cd,fixed,precision=2}
\draw (\x,0.08) -- (\x,0) node[below,font=\footnotesize]{\pgfmathprintnumber{\printx}};
}

\foreach \x[count=\xi,evaluate=\x as \prevx using int(\x-1)] in {0,1,...,\numrows}{
% value
\pgfplotstablegetelem{\x}{[index]0}\of\eigenvaltab
\pgfmathsetmacro\newval{\pgfplotsretval*10}
\ifnum\xi=1
\pgfmathsetmacro\initval{0}
\else
% prev value
\pgfplotstablegetelem{\prevx}{[index]0}\of\eigenvaltab
\pgfmathsetmacro\initval{\pgfplotsretval*10}
\fi

% color
\pgfplotstablegetelem{\x}{[index]1}\of\eigenvaltab
\def\rowcol{\pgfplotsretval}
\fill [\rowcol] ( \initval,0.08) rectangle ( \newval,\diagramheight);
}
}

\newcommand{\drawspectrumvalue}[3]{
\draw[|<->|] (0,#2) -- node[fill=\valfillcol,
inner sep=2pt,
rounded corners] {#3} (#1,#2);
}

\newcommand{\drawspectrumvaluelist}[2][font=\scriptsize]{
\foreach \value [count=\xi] in {#2}  {\global\let\maxnumvalues\xi}

\pgfmathsetmacro\valuesdistance{\diagramheight/(\maxnumvalues+0.5)}
\begin{scope}[#1]
\foreach \x[count=\xi] in {#2}{
\pgfmathsetmacro\xval{\x*10}
\pgfkeys{/pgf/number format/.cd,fixed,precision=\valprintprec,zerofill}
\drawspectrumvalue{\xval}{\xi*\valuesdistance}{\pgfmathprintnumber{\x}}
}
\end{scope}

}

\begin{document}

\begin{tikzpicture}
\drawspectrum{eigenvalues.dat}

\drawspectrumvaluelist{0.8322,0.8765,0.90}
\end{tikzpicture}

\begin{tikzpicture}[diagram height=2,value precision=3,value fill color=red!20]
\drawspectrum{eigenvalues.dat}

\drawspectrumvaluelist[font=\footnotesize]{0.8322,0.8765,0.90,0.9227,0.9287}
\end{tikzpicture}

\end{document}


The first image represents the picture provided by the OP:

A customized example:

-
Thank you! Then maybe we can make a \drawspectra{list-of-eig-values}{list-of-color-values}{colormap-name}. And we will just need to tune the list-of-color-values to make a proper spectrum! –  Hongying Jun 28 '13 at 11:12
You're welcome :). The problem that I see in that kind of macro is that, although it could be very useful at the user-side, it's very difficult to be implemented. In the sense that it brings some issues: we have to merge two different lists so this process has to be consistent (same number of elements, be sure of access the right value-color pair), for high number of values this is not efficient. Later I will improve the current version and I try to think on that macro, but without any guarantee. –  Claudio Fiandrino Jun 28 '13 at 11:44
How about we give user the freedom to choose colours for the big eigenvalues, and make it pick random colours for small ones? (Or maybe we can provide two or three static lists of colours, and always use one of them for small eigenvalues ? I'll think about a list of colours! :) ) –  Hongying Jun 28 '13 at 19:48
Of course could be possible, but if you derive your values via simulation, I think the best is the solution already here. You just have to create a file with the pair value-color and automatically it will be dispayed. –  Claudio Fiandrino Jun 29 '13 at 11:47
By the way, do you know how to make it shows up "0.90" rather than "0.9", when there is a "0" at the end? –  Hongying Jul 4 '13 at 14:02