Plot filledcurve with variable transparency - gnuplot

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:

Related

How to make dashed grid lines intersect making crosshairs in gnuplot?

I'm plotting some data and I want to use dashed grid lines.
Any dashed grid line would suffice, but I prefer a "long dash, short dash, long dash" format.
For example, given the following code
set grid lc rgb "#000000" lt 1 dt (50, 25, 20, 25)
plot x**2
I get this result
But I would rather the grid lines intersection to happen always at the middle of two dashes, like this
If I could make horizontal grid lines different to vertical grid lines and I could add some offset to each one, then I'd imagine there's a way to accomplish this. But I can't seem to do that either.
It looks like gnuplot cannot have two different dashstyles for x-grid and y-grid.
One workaround I see currently is to plot two identical plot on top of each other. One with appropriate x-grid lines and the other with appropriate y-grid lines.
If you want a dash pattern with proportions of (50-25-20-25), this correspond to (25-25-20-25-25-0) or (5-5-4-5-5-0) between two tics.
Furthermore, the dash and gap length numbers, e.g. in dt (50,25,20,25), seem to be in a fixed relation to the graph size. The "empirical" factor is 11 with good approximation (at least for the wxt terminal which I tested under gnuplot 5.2.6).
Edit: actually, the code below gives different results with a qt terminal. And it's not just a different factor. It's more complicated and probably difficult to solve without insight into the source code. So, the fact that the following seems to work with wxt terminal (maybe even just under Windows?) was probably a lucky strike.
With this you can create your dash lines automatically resulting in crosshairs at the intersections of the major grid lines.
Assumptions are:
your first and last tics are on the borders
you know the number of x- and y-intervals
You also need to know the graph size. These values are stored in the variables GPVAL_TERM..., but only after plotting. That's why you have to replot to get the correct values.
This workaround at least should give always crosshairs at the intersection of the major grid lines.
Edit 2: just for "completeness". The factors to get the same (or similar) looking custom dashed pattern on different terminals varies considerably. wxt approx. 11, qt approx. 5.6, pngcairoapprox. 0.25. This is not what I would expect. Furthermore, it looks like the factors slightly depend on x and y as well as graph size. In order to get "exact" crosshairs you might have to tweak these numbers a little further.
Code:
### dashed grid lines with crosshairs at intersections
reset session
TERM = "wxt" # choose terminal
if (TERM eq "wxt") {
set term wxt size 800,600
FactorX = 11. # wxt
FactorY = 11. # wxt
}
if (TERM eq "qt") {
set term qt size 800,600
FactorX = 5.58 # qt
FactorY = 5.575 # qt
}
if (TERM eq "pngcairo") {
set term pngcairo size 800,600
set output "tbDashTest.png"
FactorX = 0.249 # pngcairo
FactorY = 0.251 # pngcairo
}
set multiplot
set ticscale 0,0
Units = 24 # pattern (5,5,4,5,5,0) are 24 units
# set interval and repetition parameters
IntervalsY = 10
RepetitionsY = 1
IntervalsX = 4
RepetitionsX = 3
# initial plot to get graph size
plot x**2
gX = real(GPVAL_TERM_YMAX-GPVAL_TERM_YMIN)/IntervalsY/Units/FactorY/RepetitionsY
gY = real(GPVAL_TERM_XMAX-GPVAL_TERM_XMIN)/IntervalsX/Units/FactorX/RepetitionsX
# first plot with x-grid lines
set grid xtics lt 1 lc rgb "black" dt (gX*5,gX*5,gX*4,gX*5,gX*5,0)
replot
unset grid
# second plot with y-grid lines
set grid ytics lt 1 lc rgb "black" dt (gY*5,gY*5,gY*4,gY*5,gY*5,0)
replot
unset multiplot
set output
### end of code
Result:
Not really. The closest I can think of is
set grid x y mx my
set grid lt -1 lc "black" lw 1 , lt -1 lc bgnd lw 16
set ticscale 1.0, 0.01
set mxtics 4
plot x**2 lw 2
But that leaves the vertical grid lines solid.

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)

Gradient colored polar curve

I'm trying to do the following in gnuplot: color with gradient an ellipse. Each point of the
ellipse has its z-value given by the function
charge_density(t,beta) = -sin(t)*beta*(sqrt(1-(beta**2)))/(1-((sin(t)*beta)**2))
The radius function of the ellipse is given by a similar function:
radius(t,beta) = sqrt(1-(beta**2))/sqrt(1-((sin(t)*beta)**2))
Where beta is just a parameter satisfying 0<beta<1, and t is the angle.
Well, I tried to use the "+" special file with the lc rgb variable option, but it doesn't work with polar coordinates.
I also tried the set mapping cylindrical, but nothing happened.
Is this possible only with cartesian coordinates? In this case, I'll have to do 2 graphics and modify the above functions...
Or will I have to create a data file with angle, radius, z data?
I'd like to do this with pm3d and the following palette:
set palette model RGB defined (-1 "blue", 0 "black", 1 "red")
here is the code:
beta =0.5
charge_density(t,beta) = -sin(t)*beta*(sqrt(1-(sin(t)*beta)**2))/(1-((sin(t)*beta)**2))
radius(t,beta) = sin(t*beta) # your function equals 1!
# convert polar to carthesian
r_x(t)=radius(t,beta)*cos(t)
r_y(t)=radius(t,beta)*sin(t)
set palette model RGB defined (-1 "blue", 0 "black", 1 "red")
set size ratio -1 # same unit length in x and y
# number of sample points.
# increase if curve has edges
set samples 100
#decouple range of "+" and xrange
set parametric
plot [0:3*pi] "+" u (r_x($1)):(r_y($1)):(charge_density($1,beta))\
with lines linewidth 3 linecolor palette
and there the result:
NOTE: Your radius equals to 1, so I took another function. Also, your charge_density has one extra closing parenthesis.
Some comments:
if you plot with lc rgb variable, a 24bit RGB color value is expected:
(red*256^2 + green*256 + blue) with red, green, blue = 0...255
If you want gnuplot to use the color according to the palette, write lc palette
gnuplot 4.6 does not support "+" for polar. Also, the mapping sets the behavior for 3D plots. However, as your formula calculates a radius for an angle, you can easily transform this to carthesian coordinates and plot these. There is still one drawback: The range given in the plot sets the xrange, too. This also means that the "length" of your curve changes when you change the xrange. You can solve this by set parametric which causes gnuplot to use a dedicated variable u instead of x when plotting functions. It is nice (and helps you) that this affects the special file "+", too. I do not know if this is a (positive) bug or a feature.

Making eye-diagram with 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:

Histogram using gnuplot?

I know how to create a histogram (just use "with boxes") in gnuplot if my .dat file already has properly binned data. Is there a way to take a list of numbers and have gnuplot provide a histogram based on ranges and bin sizes the user provides?
yes, and its quick and simple though very hidden:
binwidth=5
bin(x,width)=width*floor(x/width)
plot 'datafile' using (bin($1,binwidth)):(1.0) smooth freq with boxes
check out help smooth freq to see why the above makes a histogram
to deal with ranges just set the xrange variable.
I have a couple corrections/additions to Born2Smile's very useful answer:
Empty bins caused the box for the adjacent bin to incorrectly extend into its space; avoid this using set boxwidth binwidth
In Born2Smile's version, bins are rendered as centered on their lower bound. Strictly they ought to extend from the lower bound to the upper bound. This can be corrected by modifying the bin function: bin(x,width)=width*floor(x/width) + width/2.0
Be very careful: all of the answers on this page are implicitly taking the decision of where the binning starts - the left-hand edge of the left-most bin, if you like - out of the user's hands. If the user is combining any of these functions for binning data with his/her own decision about where binning starts (as is done on the blog which is linked to above) the functions above are all incorrect. With an arbitrary starting point for binning 'Min', the correct function is:
bin(x) = width*(floor((x-Min)/width)+0.5) + Min
You can see why this is correct sequentially (it helps to draw a few bins and a point somewhere in one of them). Subtract Min from your data point to see how far into the binning range it is. Then divide by binwidth so that you're effectively working in units of 'bins'. Then 'floor' the result to go to the left-hand edge of that bin, add 0.5 to go to the middle of the bin, multiply by the width so that you're no longer working in units of bins but in an absolute scale again, then finally add back on the Min offset you subtracted at the start.
Consider this function in action:
Min = 0.25 # where binning starts
Max = 2.25 # where binning ends
n = 2 # the number of bins
width = (Max-Min)/n # binwidth; evaluates to 1.0
bin(x) = width*(floor((x-Min)/width)+0.5) + Min
e.g. the value 1.1 truly falls in the left bin:
this function correctly maps it to the centre of the left bin (0.75);
Born2Smile's answer, bin(x)=width*floor(x/width), incorrectly maps it to 1;
mas90's answer, bin(x)=width*floor(x/width) + binwidth/2.0, incorrectly maps it to 1.5.
Born2Smile's answer is only correct if the bin boundaries occur at (n+0.5)*binwidth (where n runs over integers). mas90's answer is only correct if the bin boundaries occur at n*binwidth.
Do you want to plot a graph like this one?
yes? Then you can have a look at my blog article: http://gnuplot-surprising.blogspot.com/2011/09/statistic-analysis-and-histogram.html
Key lines from the code:
n=100 #number of intervals
max=3. #max value
min=-3. #min value
width=(max-min)/n #interval width
#function used to map a value to the intervals
hist(x,width)=width*floor(x/width)+width/2.0
set boxwidth width*0.9
set style fill solid 0.5 # fill style
#count and plot
plot "data.dat" u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle
As usual, Gnuplot is a fantastic tool for plotting sweet looking graphs and it can be made to perform all sorts of calculations. However, it is intended to plot data rather than to serve as a calculator and it is often easier to use an external programme (e.g. Octave) to do the more "complicated" calculations, save this data in a file, then use Gnuplot to produce the graph. For the above problem, check out the "hist" function is Octave using [freq,bins]=hist(data), then plot this in Gnuplot using
set style histogram rowstacked gap 0
set style fill solid 0.5 border lt -1
plot "./data.dat" smooth freq with boxes
I have found this discussion extremely useful, but I have experienced some "rounding off" problems.
More precisely, using a binwidth of 0.05, I have noticed that, with the techniques presented here above, data points which read 0.1 and 0.15 fall in the same bin. This (obviously unwanted behaviour) is most likely due to the "floor" function.
Hereafter is my small contribution to try to circumvent this.
bin(x,width,n)=x<=n*width? width*(n-1) + 0.5*binwidth:bin(x,width,n+1)
binwidth = 0.05
set boxwidth binwidth
plot "data.dat" u (bin($1,binwidth,1)):(1.0) smooth freq with boxes
This recursive method is for x >=0; one could generalise this with more conditional statements to obtain something even more general.
We do not need to use recursive method, it may be slow. My solution is using a user-defined function rint instesd of instrinsic function int or floor.
rint(x)=(x-int(x)>0.9999)?int(x)+1:int(x)
This function will give rint(0.0003/0.0001)=3, while int(0.0003/0.0001)=floor(0.0003/0.0001)=2.
Why? Please look at Perl int function and padding zeros
I have a little modification to Born2Smile's solution.
I know that doesn't make much sense, but you may want it just in case. If your data is integer and you need a float bin size (maybe for comparison with another set of data, or plot density in finer grid), you will need to add a random number between 0 and 1 inside floor. Otherwise, there will be spikes due to round up error. floor(x/width+0.5) will not do because it will create pattern that's not true to original data.
binwidth=0.3
bin(x,width)=width*floor(x/width+rand(0))
With respect to binning functions, I didn't expect the result of the functions offered so far. Namely, if my binwidth is 0.001, these functions were centering the bins on 0.0005 points, whereas I feel it's more intuitive to have the bins centered on 0.001 boundaries.
In other words, I'd like to have
Bin 0.001 contain data from 0.0005 to 0.0014
Bin 0.002 contain data from 0.0015 to 0.0024
...
The binning function I came up with is
my_bin(x,width) = width*(floor(x/width+0.5))
Here's a script to compare some of the offered bin functions to this one:
rint(x) = (x-int(x)>0.9999)?int(x)+1:int(x)
bin(x,width) = width*rint(x/width) + width/2.0
binc(x,width) = width*(int(x/width)+0.5)
mitar_bin(x,width) = width*floor(x/width) + width/2.0
my_bin(x,width) = width*(floor(x/width+0.5))
binwidth = 0.001
data_list = "-0.1386 -0.1383 -0.1375 -0.0015 -0.0005 0.0005 0.0015 0.1375 0.1383 0.1386"
my_line = sprintf("%7s %7s %7s %7s %7s","data","bin()","binc()","mitar()","my_bin()")
print my_line
do for [i in data_list] {
iN = i + 0
my_line = sprintf("%+.4f %+.4f %+.4f %+.4f %+.4f",iN,bin(iN,binwidth),binc(iN,binwidth),mitar_bin(iN,binwidth),my_bin(iN,binwidth))
print my_line
}
and here's the output
data bin() binc() mitar() my_bin()
-0.1386 -0.1375 -0.1375 -0.1385 -0.1390
-0.1383 -0.1375 -0.1375 -0.1385 -0.1380
-0.1375 -0.1365 -0.1365 -0.1375 -0.1380
-0.0015 -0.0005 -0.0005 -0.0015 -0.0010
-0.0005 +0.0005 +0.0005 -0.0005 +0.0000
+0.0005 +0.0005 +0.0005 +0.0005 +0.0010
+0.0015 +0.0015 +0.0015 +0.0015 +0.0020
+0.1375 +0.1375 +0.1375 +0.1375 +0.1380
+0.1383 +0.1385 +0.1385 +0.1385 +0.1380
+0.1386 +0.1385 +0.1385 +0.1385 +0.1390
Different number of bins on the same dataset can reveal different features of the data.
Unfortunately, there is no universal best method that can determine the number of bins.
One of the powerful methods is the Freedman–Diaconis rule, which automatically determines the number of bins based on statistics of a given dataset, among many other alternatives.
Accordingly, the following can be used to utilise the Freedman–Diaconis rule in a gnuplot script:
Say you have a file containing a single column of samples, samplesFile:
# samples
0.12345
1.23232
...
The following (which is based on ChrisW's answer) may be embed into an existing gnuplot script:
...
## preceeding gnuplot commands
...
#
samples="$samplesFile"
stats samples nooutput
N = floor(STATS_records)
samplesMin = STATS_min
samplesMax = STATS_max
# Freedman–Diaconis formula for bin-width size estimation
lowQuartile = STATS_lo_quartile
upQuartile = STATS_up_quartile
IQR = upQuartile - lowQuartile
width = 2*IQR/(N**(1.0/3.0))
bin(x) = width*(floor((x-samplesMin)/width)+0.5) + samplesMin
plot \
samples u (bin(\$1)):(1.0/(N*width)) t "Output" w l lw 1 smooth freq

Resources