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.
Related
I calculated the eigenvalues of the Hamiltonian for the 1D-hydrogen atom in atomic units with the Fourier-Grid-Hamiltonian method in a nice little Fortran program.
All the eigenvalues found between -1 and 0 (the bound states) are saved into a file line by line like this:
-0.50016671392950229
-0.18026105614262633
-0.11485673263086937
-4.7309305955423042E-002
-4.7077108902158216E-002
As the number of found eigenvalues differs depends on the stepsize my program uses, the number of entries in the file can vary (in theory, there are infinite ones).
I now want to plot the values from the file as a line parallel to the x-axis with the offset given by the values read from file.
I also want to be able to plot the data only up to a certain line number, as the values get really close to each other the further you come to zero and they cannot be distinguished by eye anymore.
(Here e.g. it would make sence to plot the first four entries, the fifth is already too close to the previous one)
I know that one can plot lines parallel to the x axis with the command plot *offset* but I don't know how to tell gnuplot to use the data from the file. So far I had to manually plot the values.
As a second step I would like to plot the data only in a certain x range, more concrete between the points of intersection with the harmonic potential used for the numeric solution V(x) = -1/(1+abs(x))
The result should look like this:
scheme of the desired plot (lookalike)
The closest I got to, was with
plot -1/(1+abs(x)),-0.5 title 'E0',-0.18 title 'E1', -0.11 title 'E2'
which got me the following result:
my plot
Hope you guys can help me, and I'm really curios whether gnuplot actually can do the second step I described!
As for the first part of your question, you can for example use the xerrorbars plotting style as:
set terminal pngcairo
set output 'fig.png'
unset key
set xr [-1:1]
set yr [-1:0]
unset bars
plot '-' u (0):($1<-0.1?$1:1/0):(1) w xerrorbars pt 0 lc rgb 'red'
-0.50016671392950229
-0.18026105614262633
-0.11485673263086937
-4.7309305955423042E-002
-4.7077108902158216E-002
e
The idea here is to:
interpret the energies E as points with coordinates (0,E) and assign to each of them an x-errorbar of width 1 (via the third part of the specification (0):($1<-0.1?$1:1/0):(1))
"simulate" the horizontal lines with x-errorbars. To this end, unset bars and pt 0 ensure that Gnuplot displays just plain lines.
consider only energies E<-0.1, the expressions $1<-0.1?$1:1/0 evaluates otherwise to an undefined value 1/0 which has the consequence that nothing is plotted for such E.
plot '-' with explicit values can be of course replaced with, e.g., plot 'your_file.dat'
This produces:
For the second part, it mostly depends how complicated is your function V(x). In the particular case of V(x)=-1/(1+|x|), one could infer directly that it's symmetric around x=0 and calculate the turning points explicitly, e.g.,
set terminal pngcairo
set output 'fig.png'
fName = 'test.dat'
unset key
set xr [-10:10]
set yr [-1:0]
unset bars
f(x) = -1 / (1+abs(x))
g(y) = (-1/y - 1)
plot \
f(x) w l lc rgb 'black', \
fName u (0):($1<-0.1?$1:1/0):(g($1)) w xerrorbars pt 0 lc rgb 'red', \
fName u (0):($1<-0.1?$1:1/0):(sprintf("E%d", $0)) w labels offset 0, char 0.75
which yields
The idea is basically the same as before, just the width of the errorbar now depends on the y-coordinate (the energy). Also, the labels style is used in order to produce explicit labels.
Another approach may be to get data from "energy.dat" (as given in the question) with system and cat commands (so assuming a Un*x-like system...) and select V(x) and E at each x via max:
set key bottom right
set yr [-1:0.2]
set samples 1000
Edat = system( "cat energy.dat" )
max(a,b) = ( a > b ) ? a : b
V(x) = -1/(1+abs(x))
plot for [ E in Edat ] \
max(V(x),real(E)) title sprintf("E = %8.6f", real(E)) lw 2, \
V(x) title "V(x) = -1/(1+|x|)" lc rgb "red" lw 2
If we change the potential to V(x) = -abs(cos(x)), the plot looks pretty funny (and the energy levels are of course not correct!)
More details about the script:
max is not a built-in function in Gnuplot, but a user-defined function having two formal arguments. So for example, we may define it as
mymax( p, q ) = ( p > q ) ? p : q
with any other names (and use mymax in the plot command). Next, the ? symbol is a ternary operator that gives a short-hand notation for an if...else construct. In a pseudo-code, it works as
function max( a, b ) {
if ( a > b ) then
return a
else
return b
end
}
This way, max(V(x),real(E)) selects the greater value between V(x) and real(E) for any given x and E.
Next, Edat = system( "cat energy.dat" ) tells Gnuplot to run the shell command "cat energy.dat" and assign the output to a new variable Edat. In the above case, Edat becomes a string that contains a sequence of energy values read in from "energy.dat". You can check the contents of Edat by print( Edat ). For example, it may be something like
Edat = "-0.11 -0.22 ... -0.5002"
plot for [ E in Edat ] ... loops over words contained in a string Edat. In the above case, E takes a string "-0.11", "-0.22", ..., "-0.5002" one-by-one. real(E) converts this string to a floating-point value. It is used to pass E (a character string) to any mathematical function.
The basic idea is to draw a truncated potential above E, max(V(x),E), for each value of E. (You can check the shape of such potential by plot max(V(x),-0.5), for example). After plotting such curves, we redraw the potential V(x) to make it appear as a single potential curve with a different color.
set samples 1000 increases the resolution of the plot with 1000 points per curve. 1000 is arbitrary, but this seems to be sufficient to make the figure pretty smooth.
[Current]
I am importing a text file in which the first column has simulation time (0~150) the second column has the delay (0.01~0.02).
1.000000 0.010007
1.000000 0.010010
2.000000 0.010013
2.000000 0.010016
.
.
.
149.000000 0.010045
149.000000 0.010048
150.000000 0.010052
150.000000 0.010055
which gives me the plot:
[Desired]
I need to plot an average line on it like shown in the following image with red line:
Here is a gnuplot only solution with sample data:
set table "test.data"
set samples 1000
plot rand(0)+sin(x)
unset table
You should check the gnuplot demo page for a running average. I'm going to generalize this demo in terms of dynamically building the functions. This makes it much easier to change the number of points include in the average.
This is the script:
# number of points in moving average
n = 50
# initialize the variables
do for [i=1:n] {
eval(sprintf("back%d=0", i))
}
# build shift function (back_n = back_n-1, ..., back1=x)
shift = "("
do for [i=n:2:-1] {
shift = sprintf("%sback%d = back%d, ", shift, i, i-1)
}
shift = shift."back1 = x)"
# uncomment the next line for a check
# print shift
# build sum function (back1 + ... + backn)
sum = "(back1"
do for [i=2:n] {
sum = sprintf("%s+back%d", sum, i)
}
sum = sum.")"
# uncomment the next line for a check
# print sum
# define the functions like in the gnuplot demo
# use macro expansion for turning the strings into real functions
samples(x) = $0 > (n-1) ? n : ($0+1)
avg_n(x) = (shift_n(x), #sum/samples($0))
shift_n(x) = #shift
# the final plot command looks quite simple
set terminal pngcairo
set output "moving_average.png"
plot "test.data" using 1:2 w l notitle, \
"test.data" using 1:(avg_n($2)) w l lc rgb "red" lw 3 title "avg\\_".n
This is the result:
The average lags quite a bit behind the datapoints as expected from the algorithm. Maybe 50 points are too many. Alternatively, one could think about implementing a centered moving average, but this is beyond the scope of this question.
And, I also think that you are more flexible with an external program :)
Here's some replacement code for the top answer, which makes this also work for 1000+ points and much much faster. Only works in gnuplot 5.2 and later I guess
# number of points in moving average
n = 5000
array A[n]
samples(x) = $0 > (n-1) ? n : int($0+1)
mod(x) = int(x) % n
avg_n(x) = (A[mod($0)+1]=x, (sum [i=1:samples($0)] A[i]) / samples($0))
Edit
The updated question is about a moving average.
You can do this in a limited way with gnuplot alone, according to this demo.
But in my opinion, it would be more flexible to pre-process your data using a programming language like python or ruby and add an extra column for whatever kind of moving average you require.
The original answer is preserved below:
You can use fit. It seems you want to fit to a constant function. Like this:
f(x) = c
fit f(x) 'S1_delay_120_LT100_LU15_MU5.txt' using 1:2 every 5 via c
Then you can plot them both.
plot 'S1_delay_120_LT100_LU15_MU5.txt' using 1:2 every 5, \
f(x) with lines
Note that this is technique can be used with arbitrary functions, not just constant or lineair functions.
I wanted to comment on Franky_GT, but somehow stackoverflow didn't let me.
However, Franky_GT, your answer works great!
A note for people plotting .xvg files (e.g. after doing analysis of MD simulations), if you don't add the following line:
set datafile commentschars "##&"
Franky_GT's moving average code will result in this error:
unknown type in imag()
I hope this is of use to anyone.
For gnuplot >=5.2, probably the most efficient solution is using an array like #Franky_GT's solution.
However, it uses the pseudocolumn 0 (see help pseudocolumns). In case you have some empty lines in your data $0 will be reset to 0 which eventually might mess up your average.
This solution uses an index t to count up the datalines and a second array X[] in case a centered moving average is desired. Datapoints don't have to be equidistant in x.
At the beginning there will not be enough datapoints for a centered average of N points so for the x-value it will use every second point and the other will be NaN, that's why set datafile missing NaN is necessary to plot a connected line at the beginning.
Code:
### moving average over N points
reset session
# create some test data
set print $Data
y = 0
do for [i=1:5000] {
print sprintf("%g %g", i, y=y+rand(0)*2-1)
}
set print
# average over N values
N = 250
array Avg[N]
array X[N]
MovAvg(col) = (Avg[(t-1)%N+1]=column(col), n = t<N ? t : N, t=t+1, (sum [i=1:n] Avg[i])/n)
MovAvgCenterX(col) = (X[(t-1)%N+1]=column(col), n = t<N ? t%2 ? NaN : (t+1)/2 : ((t+1)-N/2)%N+1, n==n ? X[n] : NaN) # be aware: gnuplot does integer division here
set datafile missing NaN
plot $Data u 1:2 w l ti "Data", \
t=1 '' u 1:(MovAvg(2)) w l lc rgb "red" ti sprintf("Moving average over %d",N), \
t=1 '' u (MovAvgCenterX(1)):(MovAvg(2)) w l lw 2 lc rgb "green" ti sprintf("Moving average centered over %d",N)
### end of code
Result:
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
i'm having some problems with gnuplot
I have to draw a cdf function and i'm interested in the values of variable x when F(x) is equal to 0.1 and 0.9
How can I tell Gnuplot to show me on the x axis the value corresponding to a given value on the y value (in my example those values are 0.1 and 0.9)
thanks
You're basically asking gnuplot to solve an equation. In your particular case, actually two equations: F(x)=0.1 and F(x)=0.9. As far as I know this cannot be done, but I might be wrong. What you can do if you simply want a graphical solution, is make a conditional plot, and ask that when F(x) is very close to 0.1 0.9, gnuplot plots something other than the function.
For example, assume f(x)=x^2 and you want to know "graphically" for which x f(x)=0.1. Then you can request the value abs(f(x) - 0.1) be small, for example < 0.01. Then tell gnuplot to go to zero (just an example!) if this is the case, otherwise plot f(x)=x^2:
f(x)=x**2
set xrange [-2:2]
set samples 1000
plot abs(f(x)-1) < 0.01 ? 0 : f(x)
Which yields:
The two peaks that go to zero mark graphically on the x axis the solution to the equation f(x)=0.1. Of course, you need gnuplot to sample this point in order to see a peak. Thus you need to play with set samples and set xrange.
From your question it is not clear whether you have a function F(x) as expression or just a x,y-data file. I assume that your function is monotonic increasing in x and y.
Two solutions come to my mind:
via simple linear interpolation
via curve fitting
Let's create some test data. For this, let's assume your function is known (as expression) and something like this (check help norm): F(x) = a*norm(b*x + c)
Let's take a = 1; b = 0.8; c = -4. In the example below, sampling will be only 8, just for illustration purpose.
You can easily set samples 200 and you will get the same results as for the curve fitting method below. From gnuplot 5.0 on, you could write the data into a datablock instead of a file on disk.
Data: SO22276755.dat
0 3.16712e-05
1.42857 0.002137
2.85714 0.043238
4.28571 0.283855
5.71429 0.716145
7.14286 0.956762
8.57143 0.997863
10 0.999968
Script 1: (basically works for gnuplot 4.6.0, March 2012)
### interpolate x-values
reset
FILE = "SO22276755.dat"
yis = '0.10 0.90'
yi(n) = real(word(yis,n))
xis = ''
xi(n) = real(word(xis,n))
Interpolate(yi) = (x1-x0)/(y1-y0)*(yi-y0) + x0
getXis(xis) = xis.(n=words(xis), n<words(yis) ? yi=real(word(yis,n+1)) : 0, \
y0<=yi && y1>=yi ? sprintf(" %g",Interpolate(yi)) : '')
set key left top noautotitle
set grid x,y
plot x1=y1=NaN FILE u (x0=x1,x1=$1):(y0=y1,y1=$2,xis=getXis(xis),y1) \
w l lc rgb "blue" ti "data", \
'+' u (xi=xi(int($0+1))):(yi=yi(int($0+1))):\
(sprintf("(%.4g|%.4g)",xi,yi)) every ::0::1 \
w labels point pt 7 lc rgb "red" right offset -1,0 ti "interpolated"
### end of script
Result:
Script 2: (basically works for gnuplot>=4.6.0, March 2012)
With this approach you are fitting your known function F(x) to constant lines, i.e. your desired values 0.1 and 0.9. For this, a file will be created (could be a datablock for gnuplot>=5.0) and it will basically look like this SO22276755.fit:
0 0.1
1 0.1
0 0.9
1 0.9
### interpolate x-values
reset
F(x) = a*norm(b*x+c) # function
a = 1
b = 0.8
c = -4
yis = '0.10 0.90'
yi(n) = real(word(yis,n))
xis = ''
xi(n) = real(word(xis,n))
set key left top noautotitle
set grid x,y
# create fit levels file
LEVELS = "SO22276755.fit"
set table LEVELS
set samples 2
plot for [i=1:words(yis)] '+' u (yi(i))
unset table
xmin = 0
xmax = 10
set xrange[xmin:xmax]
set samples 100
xis = ''
do for [i=1:words(yis)] {
xi = (xmin+xmax)*0.5 # set start value
fit F(xi) LEVELS u 1:2 index i-1 via xi
xis = xis.sprintf(" %g",xi)
}
plot F(x) w l lc rgb "web-green" ti "F(x)", \
'+' u (xi=xi(int($0+1))):(yi=yi(int($0+1))):(sprintf("(%.4g|%.4g)",xi,yi)) \
every ::0::1 w labels point pt 7 lc rgb "red" righ offset -1,0 ti "fitted"
### end of script
Result:
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: