8

So I have this kind of data

3.500E2 -0.956862
...
10.00E2 -1.95941

in a file.

If I plot it it looks like this:

gnuplot graph with line

Now I want the area under the curve filled with the visible spectrum, like this:

filled curve with visible spectrum

I already found this forum post, which draws me a nice visible spectrum, but I can't further add my own curve into it, as this appears to be a pm3d plot.

What can I do?

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
fsp
  • 515
  • 6
  • 21
  • As mentioned by @OlivierT in a deleted answer: you find nice gnuplot scripts for this at http://www.spectro-aras.com/forum/viewtopic.php?f=8&t=1000 – Christoph Aug 31 '15 at 18:47
  • if you need more precise colors see [real spectral colors](http://stackoverflow.com/a/22681410/2521214) – Spektre Oct 23 '15 at 08:15

3 Answers3

7

The filledcurves plotting style cannot handle such gradient filling, but you can modify your data file to use it with pm3d and splot.

The pm3d style works only for surfaces, so you must edit your data file to actually provide a surface grid.

For this you must add a second data block to your file, which has the same values in the first column, and the minimum of all values of the second column as its second column. Both blocks must be separated by an empty line.

Consider the example data file spectrum.dat:

350 1
400 2
450 5
500 2
550 1
600 3
650 3
700 8
750 4
800 3
850 0

From that you must get a file

350 1
400 2
450 5
500 2
550 1
600 3
650 3
700 8
750 4
800 3
850 0

350 0
400 0
450 0
500 0
550 0
600 0
650 0
700 0
750 0
800 0
850 0

That can be done on-the-fly with awk (the command got much better thanks to @TomFenech) and then plotted with pm3d using the function definitions from the forum post you linked:

lmax = 780; lmin = 380
k=lmax-lmin
set cbrange [lmin:lmax]
r(x)=x<440?-(x-440)/(440-380):x<510?0:x<580?(x-510)/(580-510):x<=780?1:0
g(x)=x<440?0:x<490?(x-440)/(490-440):x<580?1:x<645?-(x-645)/(645-580):0
b(x)=x<490?1:x<510?-(x-510)/(510-490):0
f(x)=x<420?0.3+0.7*(x-380)/(420-380):x<700?1:0.3+0.7*(780-x)/(780-700)
set palette functions f(k*gray+lmin)*r(k*gray+lmin),g(k*gray+lmin),f(k*gray+lmin)*b(k*gray+lmin)

set pm3d map interpolate 0,1
set autoscale xfix
splot '<awk ''NR == FNR {min = !min || $2 < min ? $2 : min; print; next} FNR == 1 {print ""} {$2 = min}1'' spectrum.dat spectrum.dat' using 1:2:(0):1 notitle

enter image description here

Note, that you don't need to interpolate the pm3d palette if you have enough data points. That might only give you strange artifacts (white vertical lines) in that case.

Community
  • 1
  • 1
Christoph
  • 47,569
  • 8
  • 87
  • 187
  • 2
    Nice. You can make the `awk` a bit shorter like this: `'NR == FNR {min = !min || $2 < min ? $2 : min; print; next} FNR == 1 {print ""} {$2 = min}1'` – Tom Fenech Apr 22 '14 at 08:41
  • Hey, thats much shorter :), although I don't completely understand how it works: what is the purpose of the trailing `1`? – Christoph Apr 22 '14 at 08:48
  • 1
    The first block will only run on the first file. The `next` means start again from the next line, so that all the subsequent blocks don't run on the first file. The `1` after the block is the same as putting `print` at the end of the block. – Tom Fenech Apr 22 '14 at 08:56
  • 2
    No problem. It would also make your spectrum look a lot smoother if you did `set pm3d map interpolate 0,0`. – Tom Fenech Apr 22 '14 at 09:01
  • @TomFenech Right again :) If you don't mind, I'll put both of your suggestions in my answer. – Christoph Apr 22 '14 at 09:04
  • 2
    Thanks for all your answers, this is how it looks like. [link](http://pwnhofer.at/screenshots/2014-04-22_13-53-03-J7j3.png) – fsp Apr 22 '14 at 11:54
  • Nice one. As always, I would also suggest to use `set table` before plotting with the `pm3d` method, and then use that data to plot `with image`. This leads to *much* smaller sized figures. When I was writing my thesis I had trouble with its size and the time the pages with `pm3d` figures took to load, because of how heavy this drawing method is. I eventually replotted everything with the `with image` style and loading times and overall document size are much better. – Miguel Apr 22 '14 at 14:21
  • @Miguel `set table` is not supported with `pm3d`, how did you do that? In general, I also use `plot ... with image` instead of `set pm3d map; splot ... with pm3d` (which in the gnuplot CVS version also gives very small images using `set terminal epslatex level3`). In this example that wouldn't look good because you'll have that pixelated border between the colored and white space (unless you overlay a black curve `with lines`). Another thing, which happens with pm3d are some artifacts due to anti aliasing in the viewer: [problematic Moire pattern..](http://stackoverflow.com/q/18927493/2604213) – Christoph Apr 22 '14 at 14:38
  • @Christoph: You're right! I used `set dgrid3d ... splines` to smooth the data. – Miguel Apr 22 '14 at 14:51
2

I regularly hit this question whenever I want to plot the VIS spectrum. I elaborated a bit over the answer by @Christoph and wanted to make the color part simpler. Which is indeed possible, using the HSV space, instead of RGB. In addition, it allows simple calculation of complementary color for absorption spectra.

The hue angle gnuplot must be in range 0:1, in all other sources 0-360. The angle 0 corresponds to red (assumed 780nm). The ultraviolet edge is at 300 degree of hue space.

Gnuplot automatically scales the input data into the cbrange, so we need to put the cbrange maximum deep into the UV and cut off the magenta part of Hue (at 300 degree = 0.83 gnuplot Hue). Finally, the hue is inversely proportional to th wavelength, so the palette function is (1-gray), the Saturation and Value are set to constant 0.5

lmax = 780; lmin = 330
hmax=0.83
cbmax=lmax-((lmax-lmin)/hmax)

set cbrange [lmin:lmax]
h(x)=(x>hmax)?hmax:x
set palette model HSV functions h(1-gray),0.5,0.5

set pm3d map interpolate 0,1
splot '<awk ''NR == FNR {min = !min || $2 < min ? $2 : min; print; next} FNR == 1 {print ""} {$2 = min}1'' spectrum.dat spectrum.dat' using 1:2:(0):1 notitle

The rest of the plot is identical

ssavec
  • 170
  • 5
1

Here is an alternative solution. It uses the colorbox as background (similar to here). The palette can be adapted at will. This solution, however, is cheating a little bit since it covers the uncolored area with a white filledcurve.

Data: SO59238772.dat (taken from Christoph's answer)

 350   1
 400   2
 450   5
 500   2
 550   1
 600   3
 650   3
 700   8
 750   4
 800   3
 850   0

Script: (works with gnuplot 4.6.0, March 2012)

### spectrum with visible colors as background
reset 

FILE = "SO59238772.dat"

set palette defined (380 "black", 400 "dark-violet", 440 "blue",  490 '#00b0c0', \
                     530 "green", 560 "yellow", 620 "red", 780 "black")
unset cblabel
unset cbtics
set colorbox horizontal user origin graph 0, 0 size graph 1, 1 back
unset key
set xtics out
set ytics out
set grid x,y front
set xrange [380:780]

plot FILE u 1:2 w filledcurves x2 lc rgb "white", \
       (NaN) w p palette   # just to get the colorbox
### end of script

Result:

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72