GNUPLOT: stats gives wrong results on loop - gnuplot

I have a data file with matrices split into different gnuplot indices. I wanna do an animation of a density plot evolving with time (=index).
The problem is that I want to keep the maximum and minimum of the cbrange symmetric while allowing it to change with time.
In the code below, the first "stats" command simply gives me the number of blocks for the loop. The second "stats" command with prefix "B" should give me the max and min values for the matrix at each index, so I can set cbrange properly.
The first time the code enters the loop it works (for i=1) and stats gives me the proper numbers. Starting on the second loop (i=2) stats gives me wrong numbers...
I've tried to set cbrange and zrange to [*:*] before the stats command, but it doesn't help.
Here's the code:
set terminal gif animate delay 0.5
set output 'foobar.gif'
stats 'dat-rw2d.dat' nooutput
set pm3d map
set palette defined (-1 "blue", 0 "white", 1 "red")
print STATS_blocks
do for [i=1:int(STATS_blocks)] {
print i
stats "dat-rw2d.dat" index (i-1) matrix nooutput prefix "B"
max = (B_max > -B_min)?(B_max):(-B_min)
set cbrange [-max:max]
print B_max, B_min
splot 'dat-rw2d.dat' matrix index (i-1)
}
If I don't plot anything (code below), the stats give me the correct numbers. So it is actually the "splot" that is causing the problem. It's fixing some scale and getting in the way of stats? I've tried to set cbrange [*:*] before the stats, but it doesn't solve the problem.
do for [i=1:int(STATS_blocks)] {
print i
stats "dat-rw2d.dat" index (i-1) matrix nooutput prefix "B"
max = (B_max > -B_min)?(B_max):(-B_min)
set cbrange [-max:max]
print B_max, B_min
}

If you don't specify any column to use for stats, gnuplot tries to guess a suitable default one. With the matrix option this seems to be a wrong one (probably x-value or y-value, or matrix size), which doesn't change from block to block.
You must tell gnuplot to explicitely use the third column for the stats:
stats 'dat-rw2d.dat' nooutput
set pm3d map
set palette defined (-1 "blue", 0 "white", 1 "red")
print STATS_blocks
do for [i=1:int(STATS_blocks)] {
print i
stats "dat-rw2d.dat" using 3 index (i-1) matrix nooutput prefix "B"
max = (B_max > -B_min)?(B_max):(-B_min)
set cbrange [-max:max]
print B_max, B_min
splot 'dat-rw2d.dat' matrix index (i-1)
}

Since it looks like a bug, I can just propose a workaround (awful IMHO) but that's what comes to my mind:
Call gnuplot within a system command, save variables in a file dummy.txt and load that file from your script.
stats 'test.txt' nooutput
do for [cntr=1:int(STATS_blocks)] {
# next line doesn't work
# stats 'test.txt' index (cntr-1) matrix prefix "B"
# next 3 lines do the hack
cmd=sprintf('gnuplot -e "stats \"test.txt\" index %d matrix nooutput prefix \"B\"; save var \"dummy.txt\""',cntr-1)
system(cmd)
load("dummy.txt")
print cntr, B_max, B_min
max = (B_max > -B_min)?(B_max):(-B_min)
set cbrange [-max:max]
splot 'test.txt' matrix index (cntr-1) w l
}
If someone is willing to reproduce the problem , here is my test.txt file:
0 0
0 1
1 1
1 2
2 2
3 3

Related

Gnuplot ellipsoids with Text file center

I have a text file with 3 columns defining 3D points.
I want to paint every point in 3D and an ellipsoid centered in every point. I discard using the
set parametric
way because I need to iterate my text file.
So i think in doing something like this:
gnuplot
reset
set xrange [-5:5]
set yrange [-5:5]
set zrange [-5:5]
Rx = 1
Ry = 1
Rz = 1
fx(u,v) = column(2) + Rx*cos(u)*cos(v)
fy(u,v) = column(1) + Ry*sin(u)*cos(v)
fz(u,v) = column(3) + Rz*sin(v)
iMax = 200
splot "file.txt" using ($2):($1):($3) title "Input " with points ps 2 pt 7,\
for [i=0:iMax] "file.txt" u (fx(2*pi*i/iMax, pi*i/iMax)):(fy(2*pi*i/iMax, pi*i/iMax)):(fz(2*pi*i/iMax, pi*i/iMax)) notitle with points ps 2 pt 7
But the only think I can get is this strange and heavy (I know that they are a lot of iterations per row, but maybe there is another approach) pattern
Any help? Thank you.
There is something wrong for the mathematic point of view? Using something like this Im perfectly able to plot spheres, but without parsing data:
set parametric
R = 1
set urange [-pi/2:pi/2]
set vrange [0:2*pi]
splot R*cos(u)*cos(v),R*cos(u)*sin(v),R*sin(u) w l lc rgb "yellow"
I assume you want to plot the 2D surfaces of 3D ellipsoids. But the plot command has only a loop over i which is only 1D. This can not give a 2D surface. It might be possible to nest another 1D loop to get this approach to work.
I would suggest something else. Before plotting, you can store the center coordinates into a gnuplot array. Then you loop over this array and plot a sphere/ellipsoid using parametric mode.
This might be a starting point:
# This is the file with the center coordinates.
datafile = "ellipses.dat"
# The "stats" command stores the number of rows in the STATS_records variable.
stats datafile nooutput
num_rows = STATS_records
# Generate arrays which will contain the center coordinates of the ellipsoids.
array centers_x[num_rows]
array centers_y[num_rows]
array centers_z[num_rows]
# Read the center coordinates into the prepared arrays.
# I "misuse" the stats command. The "using" expression in parenthesis executes
# the respective commands and returns the value after the last comma: row + 1.
# This return value is not needed anywhere.
row = 1
stats datafile using (centers_x[row]=$1, \
centers_y[row]=$2, \
centers_z[row]=$3, \
row = row + 1) nooutput
# Output into an image file.
set terminal pngcairo
set output "ellipsoids.png"
# Set parameters for ellipsoids.
Rx = 0.1
Ry = 0.1
Rz = 0.7
# Use parametric mode for plotting.
set parametric
set urange [-pi/2:pi/2]
set vrange [0:2*pi]
# Finally plot:
splot datafile using 1:2:3 title "Input " with points ps 2 pt 7, \
for [i=1:num_rows] centers_x[i] + Rx*cos(u)*cos(v), \
centers_y[i] + Ry*cos(u)*sin(v), \
centers_z[i] + Rz*sin(u) notitle
Please doublecheck x, y, and z: I was not that careful. This is the result:
I have used this example data:
1 2 3
2 2 4
2 3 4
3 3 3
3 4 5
Arrays are available starting with gnuplot 5.2. For older versions, please search the internet for workarounds.

Gnuplot: power notation axis

I set the y-axis in power notation (1.0e+5 or 1.0 * 1.0^5) but I would like to report the power just on top of the axis to save space. In particular I would like to report at the end of the axis as reported in the link
Try use this commented code:
# Creating some 'x y' data to plot and
# save output using 'table' and
# datablock named 'data'
set table $data
plot (1E-5 + sin(x)*1E-5)
unset table
# Performs statistics using 'y' column
# to find max value, turn off output, and
# set prefix name 'data' to stats results
stats $data u 2 nooutput name 'data'
set tmargin at screen 0.94 # Change the top margin
# Define a label containing the power to base 10
# of max value from data and put on top-left
# using the same value of top margin
# but using offset on y axis
set label gprintf('×10^{%T}',data_max) at graph 0.0, screen 0.94 offset 0,0.75
set format y '%.2t' # Format for 'y' values using mantissa
# to base 10 and 2 decimal places
set xlabel 't' # label to 'x' axis
set ylabel 'Ω' # label to 'y' axis
unset key # Turn off key (legend)
set tics nomirror # Turn off upper and right tic marks
# The plot itself
plot $data using 1:2 w l
Produces
I guess is very common to put the prefactor in the label (instead of top of the axis). If you absolutely need it on top, let me know. One way would be the following. There would also be ways to determine the prefactor automatically.
Code:
### prefactor for axis
reset session
Power = 5
set format y "%.2f"
set ylabel sprintf("Ω [10^%d rpm]", Power) enhanced
f(x) = 3e4*sin(x)+1.2e5
plot f(x)/10**Power w l notitle
### end of code
Result:

Gnuplot : Using a stats output as a data point

I have three data files each with a matrix; I use stats to find the maximum value in the matrix for each file and it is displayed correctly. I need to use those three maximum values as data points and plot them so as to have points on my plot as (1.0, A_max), (2.0, B_max) and (3.0, C_max) where A_max is the maximum value calculated using stats from first data file, B_max from second and C_max from third. Here is how my gp file looks like :
set terminal epslatex size 3.5,2.62 color colortext
set output 'data.tex'
set xlabel '$x$'
set ylabel '$y$'
stats 'dataA.txt' matrix name "A"
show variables A_
stats 'dataB.txt' matrix name "B"
show variables B_
stats 'dataC.txt' matrix name "C"
show variables C_
plot '-' w p, '-' w p, '-' w p
1.0 A_max
e
2.0 B_max
e
3.0 C_max
e
The plot I get, looks like below.
Clearly, it is taking x-axis as 0 and the points I intend for my x-axis corresponding to y. Not sure what I am missing, probably how to read the stats variable. Any help will be appreciated.
Inline data, like you are using, is used as-is without any variable replacement.
Use set print $data to print data to the named data block $data:
set print $data
stats 'dataA.txt' matrix name "A"
print sprintf("%e A", A_max)
stats 'dataB.txt' matrix name "B"
print sprintf("%e B", B_max)
stats 'dataC.txt' matrix name "C"
print sprintf("%e C", C_max)
plot $data using 0:1:xticlabel(2) w p notitle
or, with more automation:
set print $data
do for [f in "A B C"]{
stats 'data'.f.'.txt' matrix name f
print sprintf("%e %s", value(f.'_max), f)
}
plot $data using 0:1:xticlabel(2) w p notitle

Gnuplot, how I get the length of an value?

I want to know the number of characters of a value.
but strlen ( ) is only for strings , not for values.
( strlen(value("zon")) does not work)
Example: zon = 12000, len value is 5.
Is this possible with gnuplot?
In some situations you may prefer to see how long a number is when it is printed:
zon = 12000
print strlen(sprintf("%d", zon))
This also prints 5.
To get the number of digits of a numerical value, use log10 and round the value up:
zon = 12000
digits = int(ceil(log10(zon)))
print digits
prints 5, as requested.
Here is the result of the two questions I have placed;
Is it possible to get the values for de y-axis in gnuplot?
how I get the length of an value?
The reason was, I wanted a value in the columns where possible.
Here are the results and then the pieces of scripts that were needed.
Here the graphic;
And here the pieces of script;
set terminal unknown
plot "<tail -24 uur.txt" using 1:(-$7) w p, '' u 1:4 w p
ymax= GPVAL_Y_MAX
ymin= GPVAL_Y_MIN
ptmax=ymax*dy/(ymax-ymin)
ptmin=ymin*dy/(ymax-ymin)
replot
And;
"<tail -24 uur.txt" u ($1-600):4:( $4>0 && ($4/ymax*ptmax)> (10 * strlen(sprintf("%d", $4))) ? $4 : sprintf("")) w labels right rotate font ",8" tc rgb "white" offset 0,-0.1 notitle,\
"<tail -24 uur.txt" u ($1-600):4:( $4>0 && ($4/ymax*ptmax)<=(10 * strlen(sprintf("%d", $4))) ? $4 : sprintf("")) w labels left rotate font ",8" tc rgb "black" offset 0,0.1 notitle,\
Thanx all for the solutions, its now perfect, it works by every scale.

Gnuplot last point in line

I have some values of an experiment I want to plot in the xyz coordinate system. the values are somewhat limited to a certain amount and have thus a beginning and an end. Furthermore I want to plot them and the last point of them should be visible in a special way. Like a unique point with a special color or a special dot. How can I create such a line where the end is visible as a dot or something similar?
In case that it is the last point, you can use every to select it. Unfortunately, there is no 'magic' value to get the last point. You must count the number of entries and use that value:
stats 'file.dat' nooutput
last_index = int(STATS_records - 1)
splot 'file.dat' with lines, '' every ::last_index with points
Alternatively, you could use the using statement, to add some filtering which is true only for this single point which you want to select.
In the most general case, you would have
f(i, x, y, z) = ...
splot 'file.dat' with lines, '' using (f($0, $1, $2, $3) ? $1 : 1/0):2:3 with points
This skips all points, for which f returns 0. $0 is the shorthand for column(0), which gives the row index, $1 gives the numerical value of the first column and so on.
Now it is up to you to define an appropriate filtering function f.
If the end point is given e.g. by the point with the maximum x-value, you could use:
stats 'file.dat' using 1 nooutput
f(x) = (x == STATS_max ? 1 : 0)
splot 'file.dat' with lines, '' using (f($1) ? $1 : 1/0):2:3 with points
If you have an other criterium, you must define your function f accordingly.
To add a label to this point, you can use the label plotting style:
splot 'file.dat' with lines, \
'' using (f($1) ? $1 : 1/0):2:3:(sprintf('(%.1f,%.1f,%.1f)', $1, $2, $3)) \
offset char 1,1 point notitle
Here is a solution without stats which works even with gnuplot 4.4.0 (I guess stats was only available in gnuplot 4.6.0).
use the pseudocolumn 0 (check help pseudocolumns), if $0==0 (i.e. first row) you assign the values to x0,y0,z0.
assign x1=$1, y1=$2, and z1=$3. So after the first plot command the variables x1,y1,z1 hold the last point's coordinates.
use the special filename '+' (check special filenames) for plotting a single datapoint.
Script: (works with gnuplot>=4.4.0, March 2010)
### mark startpoint and endpoint of a path
reset
FILE = "SO19426060.dat"
# create some random test data
a = rand(0)
b = rand(0)
c = rand(0)
set table FILE
splot '+' u (a=a+rand(0)-0.5):(b=b+rand(0)-0.5):(c=c+rand(0)-0.5)
unset table
set grid x
set grid y
set xyplane relative 0
splot FILE u ($0==0?x0=$1:0,x1=$1):($0==0?y0=$2:0,y1=$2):($0==0?z0=$3:0,z1=$3) \
w l lc rgb "black" notitle, \
'+' u (x0):(y0):(z0) every ::0::0 w p pt 7 lc rgb "blue" ti "start", \
'+' u (x1):(y1):(z1) every ::0::0 w p pt 7 lc rgb "red" ti "end"
### end of script
Result:

Resources