gnuplot: variable values and definitions in plot command - gnuplot

I just stumbled across the following:
According to the gnuplot manual a plot element may contain a definition.
Syntax:
plot {<ranges>} <plot-element> {, <plot-element>, <plot-element>}
Each plot element consists of a definition, a function, or a data source
together with optional properties or modifiers:
plot-element:
{<iteration>}
<definition> | {sampling-range} <function> | <data source>
| keyentry
{axes <axes>} {<title-spec>}
{with <style>}
Check the following example:
For the first graph y=x+1 is plotted because a=1 was defined earlier. As expected.
For the second graph and the first plot command it should be the same but y=2*x+1 is plotted instead (twice).
In the third graph when a=1 is explicitely specified it is plotted as expected.
Why is gnuplot ignoring a=1 for the second graph?
Have I misunderstood something?
Code:
### definitions in plot command
reset session
a = 1
b = 1
f(x) = a*x + b
set yrange[-40:40]
set multiplot layout 1,3
plot f(x)
plot f(x), a=2 f(x), a=3 f(x)
plot a=1 f(x), a=2 f(x), a=3 f(x)
unset multiplot
### end of code
Result:

Your diagnosis is slightly off. In the second panel the first, purple plot is superimposed with the a=3 plot rather than the a=2 plot.
Why? Because gnuplot accumulates all elements of the full plot before actually drawing any of them. This involves making two passes over the command line. One pass to parse and load data from any data sources mentioned (needed for example for autoscaling), then a second pass to evaluate any functions over the range (which might have determined by autoscaling). During the first pass here, a gets set to 2 and then to 3. At the start of the second pass a is still 3 and in the absence of an initial definition to change it that is what is used when f(x) is evaluated.

Related

How to combine and scatter plot with a parametric plot in gnuplot

I am trying to plot some data with en ellipse on top in gnuplot. I want to plot the ellipse parametrically, and not using set object ellipse.
The following code will plot the data:
plot "my_file.dat" u 1:2
The following code will plot the ellipse:
x0 = 1
y0 = 2
a = 3
b = 2
f(t) = x0 + a*cos(t)
g(t) = y0 + b*sin(t)
set parametric
plot [0:2*pi] f(t),g(t)
How do I combine these plots in a single plot?
I am running gnuplot 5.2.
Any plot command in parametric mode can be reformulated to produce the same plot in non-parametric mode using the pseudofiles '+' for one parametric variable or '++' for two parametric variables.
So your
set parametric
plot [0:2*pi] f(t),g(t)
is exactly equivalent to
unset parametric
plot sample [t=0:2*pi] '+' using (f(t)) : (g(t))
In this form it is trivial to mix it with other data plots.
Well, check the gnuplot manual or on the gnuplot console help plot.
Syntax:
plot {<ranges>} <plot-element> {, <plot-element>, <plot-element>}
Simply add a plot element separated by comma. For better readability you may want to put it into a new line using \ as last character of the previous line.
plot [0:2*pi] f(t),g(t), \
"my_file.dat" u 1:2

Removing vertical lines due to sudden jumps in gnuplot

I am trying to plot a function that contains discontinuities in gnuplot. As a result, gnuplot automatically draws a vertical line connecting the jump discontinuities. I would like to remove this line. I have looked around and found two solutions, none of which worked: One solution was to use smooth unique when plotting, and the other one was to define the function in a conditional form and remove the discontinuity manually. The first solution simply did not make any changes to the plot (at least visually). The second solution seemed to move the location of the jump discontinuity to left or right, not get rid of the vertical line. Please note that I would like to plot with lines. I know with points works, but I do not wish to plot with points.
set sample 10000
N=50
l1(x)=2*cosh(1/x)
l2(x)=2*sinh(1/x)
Z(x)=l1(x)**N+l2(x)**N
e(x)=(-1/Z(x))*(l2(x)*l1(x)**(N-1)+l1(x)*l2(x)**(N-1))
plot e(x)
Produces:
If all you need to do is to remove the vertical line at the singularity you could use conditional plotting:
plot (x<0 ? 1/x : 1/0) w l ls 1, (x>0 ? 1/x : 1/0) w l ls 1
However, your function is more complicated: it cannot be numerically evaluated in a region around 0:
set grid
set xrange [-0.3:0.3]
plot e(x) with linespoints
If Mathematica is to be trusted, the function e(x) goes to 1 and -1 as x approaches 0 from the left and the right, respectively. However, you see in the picture above that gnuplot fails to properly evaluate the function already at x=0.1. print e(0.1) gives -0.0, and print e(0.05) already gives NaN. In this region the numerator and denominator of the function e(x) get too large to be handled with floating point numbers.
You can either exclude this region using conditional plotting,
plot (x<-0.15 ? e(x) : 1/0) w l ls 1, (x>0.15 ? e(x) : 1/0) w l ls 1
or you have to rewrite the function e(x) so you avoid extremely large values in its evaluation (if that is possible). Alternatively you can use a software package that can switch to higher precision, such as Mathematica.
You can redefine your function e(x) to avoid calculations of large exponentials like
e(x) = -(l2(x)/l1(x) + (l2(x)/l1(x))**(N-1))/(1 + (l2(x)/l1(x))**N)
Now you always calculate l2(x)/l1(x) before taking the power.
For your high sampling rate of 10000, this still gives some undefined points near the singularity, so that you have not connecting line. For lower sampling rates of e.g. 1000 you would also see a line crossing zero. To avoid that you can use an odd sampling rate:
set sample 1001
N=50
l1(x)=2*cosh(1/x)
l2(x)=2*sinh(1/x)
Z(x)=l1(x)**N+l2(x)**N
e(x) = -(l2(x)/l1(x) + (l2(x)/l1(x))**(N-1))/(1 + (l2(x)/l1(x))**N)
set autoscale yfix
set offsets 0,0,0.05,0.05
plot e(x) with lines
Late answer... but you can use the same principle as
here:
How to remove line between "jumping" values, in gnuplot?
or here:
Avoid connection of points when there is empty data
Just find the condition for where you want the line to be interrupted.
The condition in this case would be for example:
If two successive values y0 and y1 have different signs then make the line color fully transparent according to the color scheme 0xaarrggbb, e.g. 0xff123456, actually it doesn't matter what comes after 0xff, because 0xff means fully transparent.
Script:
### remove connected "jump" in curve
reset session
N=50
l1(x)=2*cosh(1/x)
l2(x)=2*sinh(1/x)
Z(x)=l1(x)**N+l2(x)**N
e(x)=(-1/Z(x))*(l2(x)*l1(x)**(N-1)+l1(x)*l2(x)**(N-1))
set key noautotitle
set grid x,y
plot y1=NaN '+' u 1:(y0=y1, y1=e(x)):(sgn(y0)!=sgn(y1)?0xff123456:0xff0000) w l lc rgb var
### end of code
Result: (identical independent of the number of samples)

How to plot lines parallel to the x-axis with a certain offset given by data in an input file with gnuplot

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.

GnuPlot not plotting over the whole range

Basicaly, I have the following code:
binom(n,k) = n!/(k!*(n-k)!)
hyperge(N,K,n,k) = binom(K,k)*binom(N-K,n-k)/binom(N,n)
hypergge(N,K,n,k) = sum [i=k:K] hyperge(N,K,n,i)
set term png
set output "onedrop.png"
set xlabel "Decksize"
set ylabel "Chance of having one of four one-drops on turn 1"
plot [x=59:209] (hypergge(floor(x)-9,4,6,1) + (1-hypergge(floor(x)-9,4,6,1))*(hypergge(floor(x)-9,4,6,1)))*100 with lines notitle lw 2
(The only thing that might be really important about hypergge is that it use factorials, i.e. needs integers as arguments).
which produces the following output
So for some reason, gnuplot just stops drawing the plot at ~180, and I see absolutely no reason why it behaves like that...
170! is the last factorial which gnuplot can evaluate:
gnuplot> print 170!
7.257415615308e+306
gnuplot> print 171!
inf.0

Vector field using gnuplot

How do I plot a vector field, where the direction at each point (x, y) is given by tangent(alpha) = f(x, y)?
As far as I can tell, gnuplot can only plot vector fields when reading data from a file. Your file will have to have 4 columns, x, y, deltax and delta y, and gnuplot will then plot a vector from (x,y) to (x+deltax, y+deltay) for each line in the file:
plot "file.dat" using 1:2:3:4 with vectors head filled lt 2
If you are not insisting on using gnuplot, there are other tools that can to this better or at least easier. I personally use asymptote. There is an example of a vectorfield plotted in asymptote here.
It seems this question/answer is a bit old, and since I believe that gnuplot is changed a bit in the latest versions, probably the answer should be updated.
I found a nice and compact solution here, by thse:
http://gnuplot.10905.n7.nabble.com/Vector-Fields-td3627.html
which I will report for convenience:
set xrange [-5:5]
set yrange [-5:5]
# only integer x-cordinates
set samples 11
# only integer y-cordinates
set isosamples 11
# we need data, so we use the special filename "++", which
# produces x,y-pairs
plot "++" using 1:2:1:(2.*$2) with vectors
Here, the original question was how to plot the vector field F(x,y) = <x, 2y>.
The trick is in the plot "++", which is a special file name which allows to use functions in the using specifier.
So, as #Jan said in his answer, gnuplot needs 4 fields in the data file to plot a vector field, but here the fields are synthetic and produced with two functions.
An equivalent formulation using defined functions could be:
set xrange [-5:5]
set yrange [-5:5]
dx(x) = x
dy(x) = 2*x
plot "++" using 1:2:(dx($1)):(dy($2)) w vec
See help special-filenames for further details.
HIH

Resources