nested do and if statements miss plots - gnuplot

I am using
G N U P L O T
Version 4.6 patchlevel 4 last modified 2013-10-02
Build System: Linux x86_64
which I want to use to plot data from a file that is roughly set up like this
0.0 a1 b1
0.0 a2 b2
...
0.1 a1 b1*
0.1 a2 b2*
...
for each unique value in the first column I want to plot b over a. To do this I have created a do loop which contains conditional plotting
do for [t=0:34] {
print 0.2000*t
plot 'twopi5101/profile.dat' u ($1==0.2000*t ? ($3-7.5) : 1/0):8 notitle w l lt 1 lc 1, \
'twopi5101/profile.dat' u ($1==0.2000*t ? ($3-7.5) : 1/0):9 notitle w l lt 1 lc 2
}
unfortunately this loop (and similar loops for other files) will consistently miss some plots
0.0
0.2
0.4
0.6
warning: Skipping data file with no valid points
warning: Skipping data file with no valid points
more> ;print 0.2000*t;plot 'twopi5101/profile.dat' u ($1==0.2000*t ? ($3-7.5) : 1/0):8 notitle w l lt 1 lc 1, 'twopi5101/profile.dat' u ($1==0.2000*t ? ($3-7.5) : 1/0):9 notitle w l lt 1 lc 2;
^
x range is invalid
however, if I manually input the 0.6 there is no problem at all
gnuplot> plot 'twopi5101/profile.dat' u ($1==0.6 ? ($3-7.5) : 1/0):8 notitle w l lt 1 lc 1, \
'twopi5101/profile.dat' u ($1==0.6 ? ($3-7.5) : 1/0):9 notitle w l lt 1 lc 2
gnuplot>
There seems to be no logical explanation for why this should happen, or even a pattern for points missed.
of the interval [0.0:6.0] gnuplot skipped:
0.6,1.2,1.4,2.4,2.8,3.4,3.8,4.6,4.8,5.6,5.8
and it does so consistently every time I run the loop, even if I run it over just part of that interval (e.g. running from 0.6 to 2.0 will again skil 0.6,1.2 and 1.4).
I've run into the same behavior in a number of other cases for larger intervals/more plots. I have no idea what would even cause something like this or if there is some error in my formatting of the loop to explain it.
(terminals I use are either 'wxt' or postscript enhanced)

That's because testing floating point values on equality is generally not a good idea. Let's consider for example:
gnuplot> print 0.6==0.6
1
gnuplot> print 0.6==3*0.2
0
This is a consequence of the fact that numbers like 0.2 are not represented exactly.
I would suggest to first convert the first column in your data to an integer value by, e.g.,
floor(($1 + 0.05)*10)
Here it is assumed that the column in question contains only multiples of 0.1. The factor 0.05 is present to ensure that possible inaccurate input such as or example 0.1000001 or 0.0999999 gets converted to 1.
This converted value can be then used in the filtering within the plot command, e.g.,
plot 'twopi5101/profile.dat' u (floor(($1+0.05)*10)==2*t?($3-7.5):1/0):8
Alternatively, one could replace the condition $1==0.2000*t with something like abs($1 - 0.2000*t)<5E-2

Related

How to sprintf() last data value in Gnuplot key?

I'm working on a temperature graph and would like to put the last data point in the title. I can use column(2) to kind of do this but I'd like to add some descriptive text as well. I'm trying the code below to concatentate some text with the data value but getting this error: line 0: f_sprintf: attempt to print numeric value with string format
plot "/tmp/data.txt" using 1:2 with lines ls 2 title sprintf('Current :%sF', column(2))
I've tried changing the sprintf modifer to %d along with various flavors of concatenation with the dot character and haven't found the right combination.
Most probably there are various solutions. The first possibility which comes to my mind (I guess requiring gnuplot >5.2) is using keyentry, check help keyentry. While plotting you are asigning column 2 to a variable. After plotting, this variable holds the last value of column 2, which you use later in keyentry, which is a keyentry without plotting anything. There would also be workarounds for older gnuplot versions.
Code:
### last value into key
reset session
$Data <<EOD
1 7.1
2 6.2
3 5.3
4 4.4
5 3.5
6 2.6
7 1.7
8 0.8
EOD
plot $Data u 1:(a=$2) w lp pt 7 lc 1 notitle, \
keyentry w lp pt 7 lc 1 ti sprintf("Last y value: %g",a)
### end of code
Result:
The problem here is that the title string is evaluated by gnuplot before the data is parsed and plot is performed.
A trick is to store the last value of temperature, and plot it afterwards.
T=0
plot "/tmp/data.txt" using 1:(T=column(2)) w l ls 2 notitle, \
1/0 w l ls 2 title sprintf('Current: %.1fF', T)

How to remove line between "jumping" values, in gnuplot?

I would like to draw a line with plots that contain "jumping" values.
Here is an example: when we have plots of sin(x) for several cycles and plot it, unrealistic line will appear that go across from right to left (as shown in following figure).
One idea to avoid this might be using with linespoints (link), but I want to draw it without revising the original data file.
Do we have simple and robust solution for this problem?
Assuming that you are plotting a function, that is, for each x value there exists one and only one corresponding y value, the easiest way to achieve what you want is to use the smooth unique option. This smoothing routine will make the data monotonic in x, then plot it. When several y values exist for the same x value, the average will be used.
Example:
Data file:
0.5 0.5
1.0 1.5
1.5 0.5
0.5 0.5
Plotting without smoothing:
set xrange [0:2]
set yrange [0:2]
plot "data" w l
With smoothing:
plot "data" smooth unique
Edit: points are lost if this solution is used, so I suggest to improve my answer.
Here can be applied "conditional plotting". Suppose we have a file like this:
1 2
2 5
3 3
1 2
2 5
3 3
i.e. there is a backline between 3rd and 4th point.
plot "tmp.dat" u 1:2
Find minimum x value:
stats "tmp.dat" u 1:2
prev=STATS_min_x
Or find first x value:
prev=system("awk 'FNR == 1 {print $1}' tmp.dat")
Plot the line if current x value is greater than previous, or don't plot if it's less:
plot "tmp.dat" u ($0==0? prev:($1>prev? $1:1/0), prev=$1):2 w l
OK, it's not impossible, but the following is a ghastly hack. I really advise you add an empty line in your dataset at the breaks.
$dat << EOD
1 1
2 2
3 3
1 5
2 6
3 7
1 8
2 9
3 10
EOD
plot for [i=0:3] $dat us \
($0==0?j=0:j=j,llx=lx,lx=$1,llx>lx?j=j+1:j=j,i==j?$1:NaN):2 w lp notit
This plots your dataset three times (acually four, there is a small error in there. I guess i have to initialise all variables), counts how often the abscissa values "jump", and only plots datapoints if this counter j is equal to the plot counter i.
Check the help on the serial evaluation operator "a, b" and the ternary operator "a?b:c"
If you have data in a repetitive x-range where the corresponding y-values do not change, then #Miguel's smooth unique solution is certainly the easiest.
In a more general case, what if the x-range is repetitive but y-values are changing, e.g. like a noisy sin(x)?
Then compare two consecutive x-values x0 and x1, if x0>x1 then you have a "jump" and make the linecolor fully transparent, i.e. invisible, e.g. 0xff123456 (scheme 0xaarrggbb, check help colorspec). The same "trick" can be used when you want to interrupt a dataline which has a certain forward "jump" (see https://stackoverflow.com/a/72535613/7295599).
Minimal solution:
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) w l lc rgb var
Script:
### plot "folded" data without connecting lines
reset session
# create some test data
set table $Data
plot [0:2*pi] for [i=1:4] '+' u 1:(sin(x)+rand(0)*0.5) w table
unset table
set xrange[0:2*pi]
set key noautotitle
set multiplot layout 1,2
plot $Data u 1:2 w l lc "red" ti "data as is"
plot x1=NaN $Data u 1:2:(x0=x1,x1=$1,x0>x1?0xff123456:0x0000ff) \
w l lc rgb var ti "\n\n\"Jumps\" removed\nwithout changing\ninput data"
unset multiplot
### end of script
Result:

gnuplot: connecting last to first point in polar plot

I have a data file like
0 8.4
60 7.5
120 8.9
180 9.2
240 8.3
300 6.9
My gnuplot script looks this way:
unset xtics
unset ytics
set polar
set angle degrees
set rrange [0:10]
set rtics 2
set grid polar
set size square
p 'data.txt' u 1:2 w lp
My problem is that I want the first and last data point to be connected by the line. I get the expected result if I repeat the first point in my data file again at the end of the file like:
0 8.4
60 7.5
120 8.9
180 9.2
240 8.3
300 6.9
0 8.4
Ist this the only way to get the expected result? I'm asking because my real file has a lot of data-sets which I reference by the gnuplot index command like p 'data.txt' index 1276 u 1:2 w lp and always duplicating the first data point again at the end at each block is quite annoying.
A solution is to connect the first and last point by doing a second plot with only those two points.
Using the syntax every (check help plot every), you can plot only the first point (number 0) and last point (number N)
with :
every N::0::N
In the example you gave, the line 9 should be modified as follow :
p 'data.txt' u 1:2 w lp ls 1, 'data.txt' u 1:2 ev 5::0::5 w lp ls 1 noti
A first flaw in this solution is you have to specify the style of the second line to ensure it looks like the first one, and does not appear in the keys (hence the ls 1 and noti).
The second flaw is you need to know the number of points in your block. It can be obtained in gnuplot using the stats syntax, as shown here. For your example, I would use it on the column 0 (for the points numbers) as follows :
stats 'data.txt' u 0
N = STATS_max

gnuplot - Increase size of point only in legend/key

I have a graph that looks like this:
I want to increase the size of the points in the legend (is it legend or key?) but without increasing the size of the points in the plot.
It's explained better in the picture. Can this be achieved?
First plot nothing with increased symbol size, then plot the data without the key.
gnuplot> plot 1/0 ls 7 lw 6 with points t "0.0", "yourdata" ls 7 notitle
Use the same point style for both of the plots, and rename the first plot key as you wish.
Unless you are using filled circles (pt 7) you may want to adopt this improvement of the Jari's answer which looks better as the points in the key are less fatty and more elegant:
plo 1/0 w p lc 1 pt 1 lw 3 ps 3 t "Data 1", "data1.dat" lc 1 pt 1 notitle,\
1/0 w p lc 3 pt 2 lw 3 ps 3 t "Data 2", "data2.dat" lc 3 pt 2 notitle

gnuplot conditional plotting: plot col A:col B if col C == x

How can I do this in gnuplot:
plot "test.csv" using 1:2 if value_in_column_3 == 80.0
It should only select those rows where column 3 == 80.0 and ignore all other rows (It should not plot a 0 for the other rows, simply ignore them)
Thanks in advance.
Consider the following dataset (1.dat),
1 0.8 0
2 0.6 0
3 0.9 1
4 1.1 0
5 0.7 0
6 0.6 1
where we want to plot the first two columns only when the third one equals zero. Then you can try this:
plot '1.dat' using 1:($3==0?$2:1/0)
(Credit to markjoe on Gnuplot mailing-list.)
Case where one wants to plot conditionally on another column containing text:
data
1 0.8 a
2 0.6 a
3 0.9 a
1 2.1 b
2 1.7 b
3 1.6 b
code
set terminal postscript color
set xrange [0:4]
set yrange [0:3]
plot "1.dat" using 1:(stringcolumn(3) eq "a"? $2:1/0) title "a" lc rgb "blue" ,\
"" using 1:(stringcolumn(3) eq "b"? $2:1/0) title "b" lc rgb "red"
command
gnuplot < 1.par > 1.ps
As chl says above, the only way to do this in gnuplot is rather hacky: you have to use gnuplot's terniary ?: operator to generate a numerical error on the points you want to filter out of your dataset.
I may be biased here as I'm an author on the project, but you may want to have a look at Pyxplot http://www.pyxplot.org.uk (also free and open source), written by a group of gnuplot users who were a bit fed up with hacky syntax like this.
Its syntax is very similar to gnuplot, but with extensions. For what you want, you can specify a "select criterion" in the plot command, and points are only included if it tests True. See http://pyxplot.org.uk/current/doc/html/sec-select_modifier.html for more information.
Another hack would be to use a shell command like awk:
plot "< awk '$3==80.0 { print $1, $2 }' test.csv" using 1:2
If you are calling a script, use column(2) instead of $2
plot "1.dat" using 1:(stringcolumn(3) eq "a"? column(2):1/0) title "a" lc rgb "blue" ,\
"" using 1:(stringcolumn(3) eq "b"? column(2):1/0) title "b" lc rgb "red"

Resources