I have been trying to change the fillstyle for the filledcurves option in gnuplot so that the fill colour represents the difference between the two curves on a 2-dimensional
I am playing around with a patch for gnuplot to allow using linecolor rgb variable
for filled curves. Then the following gnuplot code can be used:
max_color=1
# for a datafile one could extract the maximum diffference with e.g.
# stats 'hotcold.dat' using 1:($3-$2)
# max_color = (abs(STATS_min_y) > abs(STATS_max_y)) ? abs(STATS_min_y) : abs(STATS_max_y)
red(val) = (val < 0 ? abs(1+val/max_color) : 1)
green(val) = (1 - abs(val)/max_color)
blue(val) = red(-val)
rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
set yrange[0:1]
set xrange[400:2500]
set samples 200
fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
plot '+' using 1:(fhot($1)):(fcold($1)):(rgb(fhot($1)-fcold($1))) with filledcurves lc rgb var t '',\
'' using 1:(fhot($1)) with lines lw 4 lc rgb rgb(max_color) t 'Hot',\
'' using 1:(fcold($1)) with lines lw 4 lc rgb rgb(-max_color) t 'Cold'
That gives this result:
I haven't submitted the patch, yet, because I don't know if I understood the question correctly and because I don't know if I covered all cases. So some fine-tuning may be required.
The trick is to draw the lines, then fill between them with filledcurves
. Here's how to do it (based on the examples at gnuplot):
set style line 2 lc rgb 'forest-green'
set style line 3 lc rgb 'plum'
set style fill pattern 5 lc 'yellow'
set xrange [0:3000]
set yrange [0:1]
plot 'data.txt' u 1:2:3 w filledcurves notitle, \
'' u 1:2 ls 2 with lines notitle, \
'' u 1:3 ls 3 with lines notitle
The output looks like this:
The data file contains these dummy values (that resemble your second graph):
500 0.90 0.90
1000 0.90 0.75
1500 0.92 0.40
2000 0.95 0.30
2500 0.94 0.23
Another awkward workaround: instead of filledcurves
using thick vertical vector lines.
This will work when you have functions like in the example or equidistant data in x. If you don't have equidistant data in x, you would have to interpolate. Unfortunately, gnuplot does not have a feature for interpolating or resampling. You either can do this with external tools or neverthless with gnuplot which is getting a bit lenghty, see here: Resampling data with gnuplot
For getting a good-looking color gradient you have to adjust the graph/canvas size, the sampling and/or the linewidth in order to find an optimum to eliminate gaps, overhang or aliasing.
Too thin (lw 1
) and too thick (lw 8
) are not good. In the example below lw 3
seems to be a reasonable value. Maybe there are more ways to further optimize.
The example below is using @Christoph's code, slightly modified.
Code:
max_color=1
# for a datafile one could extract the maximum diffference with e.g.
# stats 'hotcold.dat' using 1:($3-$2)
# max_color = (abs(STATS_min_y) > abs(STATS_max_y)) ? abs(STATS_min_y) : abs(STATS_max_y)
red(val) = (val < 0 ? abs(1+val/max_color) : 1)
green(val) = (1 - abs(val)/max_color)
blue(val) = red(-val)
rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
set yrange[0:1]
set xrange[400:2500]
set samples 200
fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
plot \
'+' using 1:(fhot($1)):(0):(fcold($1)-fhot($1)):(rgb(fhot($1)-fcold($1))) with vectors nohead lw 3 lc rgb var t '',\
'' using 1:(fhot($1)) with lines lw 4 lc rgb rgb(max_color) t 'Hot',\
'' using 1:(fcold($1)) with lines lw 4 lc rgb rgb(-max_color) t 'Cold'
Result: (wxt 640x480, lw 1)
Result: (wxt 640x480, lw 3)
Result: (wxt 640x480, lw 8)
AFAIK, this is still not implemented in gnuplot
. You can however have a dirty(*) work around by overlaying several transparent filled curves.
E.g.,
max_color=1
max_diff=0.5
N_col=6
TRSP="E0"
HOTCOL="FF0000"
COLDCOL="0000FF"
RGBA_HOT="#".TRSP.HOTCOL
RGBA_COLD="#".TRSP.COLDCOL
RGB_HOT="#".HOTCOL
RGB_COLD="#".COLDCOL
#red(val) = (val < 0 ? abs(1+val/max_color) : 1)
#green(val) = (1 - abs(val)/max_color)
#blue(val) = red(-val)
#rgb(val) = 65536*int(255*red(val)) + 256*int(255*green(val)) + int(255*blue(val))
fhot(x) = 0.1*exp(-((x-400)/200)**2) + 0.8*exp(-((x-2000)/300)**2)
fcold(x) = 0.25*exp(-((x-700)/100)**6)+ 0.4 - (2e-4*(x-2500))**2
plot [400:2600] for [thr=0:N_col] '+' using (((fhot($1)-fcold($1))/max_diff*N_col>thr)?$1:1/0):(fhot($1)):(fcold($1)) with filledcurves lc rgb RGBA_HOT title '',\
for [thr=0:N_col] '+' using ((-(fhot($1)-fcold($1))/max_diff*N_col>thr)?$1:1/0):(fhot($1)):(fcold($1)) with filledcurves lc rgb RGBA_COLD title '',\
'' using 1:(fhot($1)) with lines lw 4 lc rgb RGB_HOT t 'Hot',\
'' using 1:(fcold($1)) with lines lw 4 lc rgb RGB_COLD t 'Cold'
Adjust N_col
and TRSP
to change the gradient: number of filled curves overlaid and transparency of each (more curves implies to be closer to max transparency FE
).
(*) This is less dirty in case the information you want to plot is a discrete variable, e.g. the number of datasets available at given abscissae.
Try to use filled histograms.
set style fill solid 1.0
plot \
datafile u 1:2:3 lt palette w boxes,\
datafile u 1:2:3 lt palette lw 2 w l
Column 3 defines color filling color according to palette settings, columns 1 and 2 define data points. You can also use background color histogram for clearing parts under graph.
I'd like to add image but I can't because of low reputation.
If the pm3d 2D map is allowed without filledcurves, then the following code could be used to achieve this
In the data processing part, the grid data for splot
is constructed from the original input data. The color of the fill area is determined by the z-value given for splot.
set table $first
plot "test.dat" using 1:2:($3-$2) with table
set table $second
plot "test.dat" using 1:3:($3-$2) with table
unset table
set print $data
do for [i=1:|$first|] {
print $first[i]
print $second[i]
print ""
}
set print
set yrange [-2:2]
set palette define (-1 "skyblue", 0 "gray90", 1 "pink")
splot $data using 1:2:3 with pm3d