Making eye-diagram with gnuplot - gnuplot

I would like to plot 1000+ curves and display their eye diagram with gnuplot.
Example of eye-diagram example with matlab: http://www.mathworks.fr/fr/help/comm/ref/commscope.eyediagram.html
I can already plot the curves using the script bellow:
gnuplot> plot for [col=1:1000] 'input_dataset1.txt' using 0:col with lines linecolor rgb("#0000ff")
Result: output_image.png
My problem is that when two lines intersects, the intersection has the same color as the line. The eye-diagram should display area with lots of intersections in a different color.
I haven't fould any example of such diagrams made with gnuplot.
Playing with line transparency didn't work: the intersction of two semi-transparent lines is the same color as the line.
Any ideas ?
Thanks,

I worked out a gnuplot-only way to do this, it involves a bit of work and you'll probably have to fine tune the details for your particular problem.
As an example I generated a data file containing values for the function exp(x) and its Taylor expansions from order zero (T^(0)[exp(x)] = 1) to order 3 (T^(3)[exp(x)] = 1 + x + x**2/2. + x**3/6.). This kind of data is suited to this problem because you will have a high data density around the origin, where all the approximations converge to the exact value, and lower data density away from it. It can be generated like this with gnuplot:
set xrange [0:1]
set table
set output "| grep -v '^$' > data"
plot exp(x), 1, 1+x, 1+x+x**2/2., 1+x+x**2/2.+x**3/6.
unset table ; unset output
Note I'm formatting the output so my data file has no blank lines, otherwise gnuplot treats fields separated by blank lines as different data blocks and this eventually messes up the histograms below. This data looks like this (plot "data"):
Now, I create a 2D histogram with this data. It would be extremely helpful if gnuplot offered this feature, but it doesn't, so the task gets a bit tricky. What I will do is create several 1D histograms. For more info on how to generate the latter, check this.
The first thing is to figure out the width along x and y for your bins, xwidth and ywidth, where the number of data points are counted, that is, we divide the data space into a grid where each element measures xwidth by ywidth and is assigned a number equal to the number of data points contained within. The smaller these elements the better resolution your graph will have, but also the more data points you'll need for it to look good. For my data above, this could be something like
xwidth = 0.02
ywidth = 0.05
Now we declare a function to define our 1D bins (details):
bin(x,width)=width*floor(x/width)+width/2.0
and define the number of bins along each direction. Because the xrange for my data is [0:1] and my yrange is [1:2.8], the number of bins would be 50 and 36, respectively. I could use Nx = xrange / xwidth but that would lead to a float Nx and I want an integer. To be safe I do:
Nx = 50
Ny = 36
It might make more sense to define these values the other way around: calculate xwidth as xrange / Nx, in which case you should not have problems with integer/float.
Now I generate the 1D histograms along y, looping over x values:
set output "| grep -v 'u\\|^$' | sed 's/#/\\n#/g' > data2"
set table
plot for [i=0:(Nx-1)] "./data" using \
(bin($2,ywidth)):( i*xwidth <= $1 && (i+1.)*xwidth > $1 ? 1.0 : 0.0) \
smooth freq
unset table ; unset output
Now data2 contains Nx blocks of data, each of them being a scan along y with Ny data points. The value of these data points is the number of data entries in the original data file. As it is, data2 contains 2D data (y, color), which I need to remap to 3D. The x value is given by the data block position, accessible with the every option in gnuplot. To plot this 3-dimensionally I do:
set output "| grep -v 'u\\|^$' | sed 's/#/\\n#/g' > data3"
set table
splot for [i=0:(Nx-1)] "./data2" every :::i::i using \
((i+0.5)*xwidth):1:2
unset table ; unset output
This data3 can now be plotted as a color map:
plot "./data3" with image
which looks like this:
Had I used higher quality data (i.e. with higher resolution) the graph would look nicer. With 2x resolution along each direction, the same looks like below:

Related

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)

Plot filledcurve with variable transparency

I want to plot a function in gnuplot with filledcurve, but having a variable transparency.
To be clear, consider the following example:
http://www.gnuplot.info/demo_canvas_4.7/rgba_lines.html
In this case, the arrow angle (an integer variable) is used as parameter to define the alpha channel. Is it possible to do the same using a function instead?
PS: I am aware that I'll probably will need to convert to an integer, as the alpha channel are bits...
One simple approach to achieve your goal is plotting several highly transparent (e.g. alpha 0xef) scaled areas on top of each other. For this, the areas need to be easily scalable from a center point, e.g. like circles, ellipses, squares, triangles, etc.
In order to tune the results, you need to play with:
N: number of areas you are stacking. If N is small you will see steps, if N is large plotting will be slow (and resulting graph maybe large in case of vector format)
Alpha: transparency of objects. In order to fade it out the value should be high, e.g. >0xee.
R(): function of scaling radius of areas, e.g. (real(i)/N) would be linear
This question could also be of interest: Gnuplot: transparency of data points when using palette
Script: (works with gnuplot>=5.0.0)
### cirles with variable radial transparency
reset session
# create some random test data
set table $Data
set samples 60
# x,y,r,color
plot '+' u (rand(0)*100):(rand(0)*100):(rand(0)*10+1):(int(rand(0)*0xffffff)) w table
unset table
set style fill solid 1.0 noborder
set samples 100
set key noautotitle
set angle degrees
N = 50
Alpha = 0xef
R(col,n) = column(col)*(real(n)/N)**2
myColor(col) = (Alpha<<24) + int(column(col))
plot for [n=1:N] $Data u 1:2:(R(3,n)):(myColor(4)) w circle lc rgb var
### end of script
Result:

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.

reduce datapoints when using logscale in gnuplot

I have a large set of data points from x = 1 to x = 10e13 (step size is fixed to about 3e8).
When I try to plot them using a logscale I certainly get an incredible huge point-density towards the end. Of course this affects my output plots since postscript and svg files (holding each and every data point) are getting really big.
Is there a way to tell gnuplot to decrease the data density dynamically?
Sample data here. Shows a straight line using logarithmic x-axis.
Usually, for this kind of plots, one can use a filter function which selects the desired points and discards all others (sets their value to 1/0:
Something like:
plot 'sample.dat' using (filter($1) ? $1 : 1/0):2
Now you must define an appropriate filter function to change the data density. Here is a proposal, with pseudo-data, although you might for sure find a better one, which doesn't show this typical logarithmic pattern:
set logscale x
reduce(x) = x/(10**(floor(log10(x))))
filterfunc(x) = abs(log10(sc)+(log10(x) - floor(log10(x))) - log10(floor(sc*reduce(x))))
filter(x) = filterfunc(x) < 1e-5 ? x : 1/0
set multiplot layout 1,2
sc = 1
plot 'sample.data' using (filter($1)):2 notitle
sc = 10
replot
The variable sc allows to change the density. The result is (with 4.6.5) is:
I did some work inspired by Christoph's answer and able to get equal spacing in log scale. I made a filtering, if you have numbers in the sequence you can simply use Greatest integer function and then find the nearest to it in log scale by comparing the fraction part. Precision is tuned by precision_parameter here.
precision_parameter=100
function(x)=(-floor(precision_parameter*log10(x))+(precision_parameter*log10(x)))
Now filter by using the filter function defined below
density_parameter = 3.5
filter(x)=(function(x) < 1/(log10(x))**density_parameter & function(x-1) > 1/(log10(x))**density_parameter ) ? x : 1/0
set datafile missing "NaN"
Last line helps in plotting with line point. I used x and x-1 assuming the xdata is in arithmetic progression with 1 as common difference, change it accordingly with your data. Just replace x by filter(x) in the plot command.
plot 'sample_data.dat' u (filter($1)):2 w lp

How do I create a 3d phase-space plot in gnuplot?

See this article Enclosed, but not Encrypted.
I have some binary data. I want to perform the gnuplots shown in that article, but using my data.
For a three-dimensional phase-space plot, the sequence a, b, c, d, e,
f, etc. can be used as space coordinates (a-b, b-c, c-d), (b-c, c-d,
d-e), (c-d, d-e, e-f), etc. Patterns in the plot created reveal
recurring relations between subsequent sequences. In this phase plot,
50,000 16-bit random numbers would produce an unstructured cloud of
dots.
I want to do exactly the same kind of thing. I have a binary file (about 10 MB) and I'd like to run it through gnuplot to create the nice gnuplot graphs.
What do I type into gnuplot to make that happen?
Doing a Google search for "phase space plot" and gnuplot doesn't return much. I don't know if that's because the article is a translation from German. I don't think I've found relevant answers in stack exchange sites.
To plot the 3d phase space use the following script, which works like the running average example from the gnuplot page:
reset
back4 = back3 = back2 = back1 = 0
shift(x) = (back4 = back3, back3 = back2, back2 = back1, back1 = x)
samples(x) = $0 < 3 ? NaN : x
set ticslevel 0
# the labels are only for orientation when checking the test data
set xlabel 'xlabel'
set ylabel 'ylabel'
splot 'randomdata.dat' using (shift($1), samples(back4-back3)):(samples(back3-back2)):(samples(back2-back1))
Gnuplot must hold four data values, which are stored in back1 to back4. For every new value, the stored values are shifted with shift. samples takes care that the first three values are not used, but only stored (NaN creates an invalid data point).
To test it, use this file randomdata.dat:
21
15
10
6
3
1
0
This plots four data points at (6,5,4), (5,4,3), (4,3,2), and (3,2,1).
If you have a binary data file with e.g. 16bit numbers, use
splot 'binaryfile' binary format="%ushort" using (shift($1), samples(back4-back3)):(samples(back3-back2)):(samples(back2-back1))
If you need to change the datasize, invoke gnuplot and type show datafile binary datasizes to see which formats are supported.

Resources