Roux
Roux

Reputation: 475

Gnuplot filledcurves flip axes

There is a style to fill the space between two functions of x. Examples of such plots can be found e.g. at http://gnuplot.sourceforge.net/demo/fillbetween.html Is there any way to make similar plot, but with flipped x and y axes? Here is the desired shape of a curve (without rotated/mirrored labels, titles and legends, of course)...

Approximate desired look

It could be done with closed contour (like last example here http://www.gnuplot.info/demo_svg_cvs/fillcrvs.html), but this would require reshuffling the data file. Any other options?

Thank you!

Upvotes: 2

Views: 1509

Answers (3)

theozh
theozh

Reputation: 25714

Here are two alternative and simpler approaches compared to my first answer. The first one works even with gnuplot 5.0.

The plotting style filledcurves (so far) can only fill between two y-curves with identical x-values. However, gnuplot can fill closed curves. So, make the curve closed. Like in my first answer, you can do this if you reverse one curve and add it to the other one.

The assumption for both scripts is that the data has a common y-column, i.e. is organized in 3 columns, e.g. here: y x1 x2

Data: SO50676753.dat (same as OP's data, from silver.dat in the gnuplot demo directory)

# y    x1    x2     
  10   280   16.7332
  20   191   13.8203
  30   152   12.3288
  40   150   12.2474
  50   104   10.1980
  60    77    8.7750
  70    69    8.3066
  80    60    7.7460
  90    60    7.7460
 100    51    7.1414
 110    41    6.4031
 120    34    5.8310
 130    35    5.9161
 140    34    5.8310
 150    24    4.8990
 160    24    4.8990
 170    19    4.3589
 180    21    4.5826
 190    20    4.4721
 200    18    4.2426
 210    21    4.5826
 220    15    3.8730
 230    19    4.3589
 240    12    3.4641
 250    20    4.4721
 260    20    4.4721
 270    18    4.2426
 280    18    4.2426
 290    20    4.4721
 300    12    3.4641
 310    26    5.0990
 320    17    4.1231
 330     8    2.8284
 340     6    2.4495
 350     8    2.8284
 360    10    3.1623
 370    20    4.4721
 380    14    3.7417
 390     8    2.8284
 400    10    3.1623
 410     9    3.0000
 420     8    2.8284
 430    10    3.1623
 440    13    3.6056
 450     9    3.0000
 460     5    2.2361
 470     7    2.6458
 480    11    3.3166
 500     7    2.6458
 510     9    3.0000
 520    12    3.4641
 530     4    2.0000
 540     7    2.6458
 550    10    3.1623
 560     9    3.0000
 580     8    2.8284
 590     9    3.0000
 600     5    2.2361

Script 1: (works with gnuplot>=5.0.0)

Here you assume that you have monotonic and unique y-values. With this, you can use the option smooth unique (available at least in gnuplot 4.x versions) to reverse one curve. However, since this solution here uses datablocks and plotting style with table it requires at least gnuplot 5.0.0. Maybe with some workarounds and temporary files you can also get it to work with some 4.6 versions.

### fill between vertical curves
reset session

FILE = "SO50676753.dat"

set table $Temp
    plot FILE u 1:2, \
           '' u (-$1):3 smooth unique       # sort data reverse by changing sign
set table $Data
    plot $Temp u 2:1     index 0 w table, \
            '' u 2:(-$1) index 1 w table    # change sign again
unset table

set style fill solid 0.3
set grid x,y

plot $Data u 1:2 w filledcurves
### end of script

Script 2: (works with gnuplot>=5.2.0)

With this solution there are no special assumptions about the data, but since it uses indexing of datablocks it requires gnuplot>=5.2.0.

### fill between vertical curves
reset session

FILE = "SO50676753.dat"

set table $Temp1
    plot FILE u 2:1 w table
set table $Temp2
    plot FILE u 3:1 w table
unset table

set print $Data
    do for [i=|$Temp2|:1:-1] { print $Temp2[i] }  # reverse data
    print $Temp1
set print

set style fill solid 0.3
set grid x,y

plot $Data u 1:2 w filledcurves
### end of script

Script 3: (another variation for gnuplot>=5.2.0 using an array and complex numbers)

### fill between vertical curves
reset session

FILE = "SO50676753.dat"

stats FILE u 0 nooutput      # get number of rows
array DATA[STATS_records*2]  # for setting array size
j = {0,1}                    # imaginary unit
stats FILE u (DATA[$0+1]=$3+j*$1, DATA[|DATA|-$0]=$2+j*$1, 0) nooutput  # data to array

set style fill solid 0.3
set grid x,y

plot DATA u (real(DATA[$0+1])):(imag(DATA[$0+1])) w filledcurves
### end of script

Result: (same for all 3 scripts):

enter image description here

Upvotes: 0

theozh
theozh

Reputation: 25714

With gnuplot >=5.2 it could be tweaked even further because it allows arrays. The following code shows a workaround how filled curves between vertically oriented curves can be realized. You can even use transparency. If you download the attached PNG you will notice that it actually has a transparent background. The basic idea behind this workaround is to make closed areas and fill them. For this, you need to reverse one border, concatenate the borders and plot them filled. Unfortunately, gnuplot has no function to reverse datapoints in a column, so you have to do it in a special procedure yourself.

The code:

### "Vertical" filledcurves
reset session

# create some dummy data
N = 50
set samples N
set xrange [-5:5]
set table $Data
    plot '+' u (sin($1)):1:(rand(0)*0.3+1) with table
unset table

# put Borders into arrays
stats $Data nooutput
RowCount = STATS_records
array BorderX1[RowCount]
array BorderX2[RowCount]
array BorderY[RowCount]
set table $Dummy
    plot $Data u (BorderX1[$0+1]=$1-$3):(BorderX2[$0+1]=$1+$3):(BorderY[$0+1]=$2) with table
unset table

# reverse BorderX2 and merge borders
set samples RowCount
set table $Border
    plot '+' u (BorderX1[$0+1]):(BorderY[$0+1]) with table
    plot '+' u (BorderX2[RowCount-$0]):(BorderY[RowCount-$0]) with table
unset table

# make the plot
set object 1 rect at 0,-3 size 10,0.5 fs solid 1.0 fc rgb "black" back
set yrange[-5:5]
plot \
    $Border u 1:2 w filledcurves fc rgb "#AA00FF00" not,\
    $Border u ($1*1.5):2 w filledcurves fc rgb "#AAFFFF00" not,\
    $Data u ($1+2.5):2 w filledcurves y2 fc rgb "brown" not,\
    $Data u 1:2 w l lw 8 lc rgb "blue" not,\
    '+' u 1:(cos($1)-0.5):(cos($1)+0.5) w filledcurves lc rgb "grey" not,\
    '+' u 1:(cos($1)):(1) w l lw 3 dt 2 lc rgb "white" not
### end of code

The result:

enter image description here

Upvotes: 1

user8153
user8153

Reputation: 4095

You can't do this directly. From help filledcurves:

The third variant fills the area between two curves sampled at the same set of x coordinates. It requires three columns of input data (x, y1, y2).

I don't think you can specify (y, x1, x2) directly. As a workaround you can the area between the y axis and the larger function in some color, and then fill the area between the y axis and the smaller function in white:

x1(y) = cos(y)+1
x2(y) = cos(y)+2
xmax(y) = (x1(y) > x2(y) ? x1(y) : x2(y))
xmin(y) = (x1(y) < x2(y) ? x1(y) : x2(y))

plot '+' using (xmax($1)):1 with filledcurve y1, \
     '+' using (xmin($1)):1 with filledcurve y1 fillcolor rgb "white"

enter image description here

This probably has to be tweaked a little if one or both of the two functions can be negative.

Upvotes: 2

Related Questions