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

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)

Related

Define pointtype using `word` command in gnuplot

I am plotting several datafiles using the same linestyle (ls 1). However, I would like to differentiate the data using different pointtypes contained in wrd_pt on the code below.
The result is shown in the figure, where GNUPLOT plots as pointtype the values contained into the variable wrd_pt instead of the symbols (square, triangle, ...) associated with each numbers. I am using GNUPLOT 5.0 and there is no way I can update it (I am not the sudoer of the computer I am using) to use arrays for e.g. of the version 5.2.
Does anyone knows how I can fix that?
[... initializing ...]
wrd_pt ="5 7 9 11 13 15"
[... some other piece of code ...]
set output "plot_1a.eps"
plot for [i=1:words(fspo_one)] work_dir.word(fspo_one, i) u 1:5 w lp ls 1 pt word(wrd_pt, i) ps 1 notitle
unset output
Why not using plotting style with labels? Works also with gnuplot 5.0.
Something like this:
Code:
### point types as string from a string
reset session
wrd_pt = "5 7 9 11 13 15"
set xrange[0:10]
set style textbox opaque
set samples 10
plot for [i=1:words(wrd_pt)] '+' u 1:(i*$1**2) w l lw 2 notitle, \
for [i=1:words(wrd_pt)] '+' u 1:(i*$1**2):(word(wrd_pt,i)) w labels boxed notitle
### end of code
Result:

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:

nested do and if statements miss plots

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

Is there a way to put a label for the last entry in gnuplot?

I want to use gnuplot for real time plotting (Data gets appended to file which I use for plotting and I use replot for real time plotting). I also want to put a label for the latest entry which is plotted. So as to get a idea what is the latest value. Is there a way to do this?
If you are on a unixoid system, you can use tail to extract the last line from the file and plot it separately in whatever way you desire. To give a simple example:
plot\
"data.dat" w l,\
"< tail -n 1 data.dat" u 1:2:2 w labels notitle
This will plot the whole of data.dat with lines and the last point with labels, with the label depicting the value.
There is no need to use the Linux command tail, you can simply do it with gnuplot-only, hence platform-independently.
The principle: while plotting the data, you assign the values of column 1 and 2 to variables x0 and y0, respectively.
After the first plot command, x0 and y0 will contain the last values.
With this, you don't have to load the file a second time for extracting the last values.
For the label plotting, use these values and print the label with a sprintf() expression (check help sprintf).
The construct '+' u ... every ::0::0 is just one way of many ways to plot a single data point.
Data: SO28152083.dat
1 5.1
2 2.2
3 3.3
4 1.4
5 4.5
Script: (works with gnuplot 4.4.0, March 2010 or even with earlier versions)
### plot last value as label
reset
FILE = "SO28152083.dat"
set key noautotitle
set offsets 0.5,0.5,1,1
plot FILE u (x0=$1):(y0=$2) w lp pt 7 lc rgb "red" ti "data", \
'+' u (x0):(y0):(sprintf("%g",y0)) every ::0::0 w labels offset 0,1
### end of script
Result:

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