I have data (data can be downloaded here: gauss_data) and need to find the area of a particular peak. From my data set, the peak seems to have some contribution from another peak. I made the fit on my data with 3 Gaussians using this code:
# Gaussian fit
reset
set terminal wxt enhanced
# Set fitting function
f(x) = g1(x)+g2(x)+g3(x)
g1(x) = p1*exp(-(x-m1)**2/(2*s**2))
g2(x) = p2*exp(-(x-m2)**2/(2*s2**2))
g3(x) = p3*exp(-(x-m3)**2/(2*s3**2))
# Estimation of each parameter
p1 = 100000
p2 = 2840
p3 = 28000
m1 = 70
m2 = 150
m3 = 350
s = 25
s2 = 100
s3 = 90
# Fitting & Plotting data
fit [0:480] f(x) 'spectrum_spl9.txt' via p1, m1, s, p2, m2, s2, p3, m3, s3
plot [0:550] 'spectrum_spl9.txt' lc rgb 'blue', f(x) ls 1, g1(x) lc rgb 'black', g2(x) lc rgb 'green' , g3(x) lc rgb 'orange'
and the result is shown in fig below
I need to calculate the area under the peak i.e. area f(x) - area g3(x). Is there any way to find/calculate the area of each function in Gnuplot?
Your data is equidistant in x-units with a step width of 1. So, you can simply sum up the intensity values multiplied by the width (which is 1). If you have irregular data then this would be a bit more complicated.
Code:
### determination of area below curve
reset session
FILE = "SO/spectrum_spl9.txt"
# fitting function
f(x) = g1(x)+g2(x)+g3(x)
g1(x) = p1*exp(-(x-m1)**2/(2*s1**2))
g2(x) = p2*exp(-(x-m2)**2/(2*s2**2))
g3(x) = p3*exp(-(x-m3)**2/(2*s3**2))
# Estimation of each parameter
p1 = 100000
p2 = 2840
p3 = 28000
m1 = 70
m2 = 150
m3 = 350
s1 = 25
s2 = 100
s3 = 90
set fit quiet nolog
fit [0:480] f(x) FILE via p1, m1, s1, p2, m2, s2, p3, m3, s3
set table $Difference
plot myIntegral=0 FILE u 1:(myIntegral=myIntegral+f($1)-g3($1),f($1)-g3($1)) w table
unset table
set samples 500 # set samples to plot the functions
plot [0:550] FILE u 1:2 w p lc 'blue' ti FILE noenhanced, \
f(x) ls 1, \
g1(x) lc rgb 'black', \
g2(x) lc rgb 'green', \
g3(x) lc rgb 'orange', \
$Difference u 1:2 w filledcurves lc rgb 0xddff0000 ti sprintf("Area: %.3g",myIntegral)
### end of code
Result:
Can you use the analytic integral under a Gaussian function?
y(x) = 1/(s*sqrt(2*pi)) * exp(-(x-m1)**2/(2*s**2))
integral(y) [-inf:inf] = 1
This would mean that:
I1 = integral(g1) = p1 * s1 * sqrt(2.0*pi)
I2 = integral(g2) = p2 * s2 * sqrt(2.0*pi)
area f(x) - area g3(x) = I1 + I2
Please double check the math :)
Related
So here is what I'm trying to do.
The values on x axis are from 10000, 20000, 30000, ... 100000. I'm trying to write it like this: 10, 20, 30, 40, ... 100 (only x axis)
Is there some way to do this in Gnuplot?
I have this so far:
(data.dat - example of data)
# x y
10000 +1.24241522E-04
11000 +1.28623514E-04
12000 +1.35229020E-04
13000 +1.43767741E-04
14000 +1.53409148E-04
15000 +1.63788695E-04
16000 +1.75429485E-04
17000 +1.88827813E-04
18000 +2.02984785E-04
19000 +2.20830420E-04
...
(my gnuplot script)
set term png
set out 'example.png'
U0 = 0.00732 #parameters for this particular problem
v1 = 68000
b1 = 6550
v2 = 59600
b2 = 6050
I = sqrt(-1)
A(w, w0, b) = ((w0)**2)/(((w0)**2) - ((w)**2) + 2*I*w*b)
f(x) = U0*abs(A(2*pi*x, 2*pi*v1, b1) - A(2*pi*x, 2*pi*v2, b2))
set xlabel "x"
set ylabel "y"
fit f(x) 'data.dat' u 1:2 via U0, v1, b1, v2, b2
plot 'data.dat' u 1:2 t "Title1" w p, U(x) t "Title2"
set out
But how do I do this?
I've tried this example
How to scale the axes in Gnuplot
but it doesn't work.
See below.
# I modified the things a little bit
f(x) = (.... ... ....)/1000
fit f(x) 'data.dat' u ($1/1000.):2 via U0, v1, b1, v2, b2
plot 'data.dat' u ($1/1000.):2 t "Title1" w p, f(x) t "Title2"
But now the fitted function disappears!
How can I modify x-axis without other function disappearing?
Does there exist a line command in gnuplot for this? I'm sure there has to be a more elegant way of writing this insted of dividing each function by a desired factor.
Two possible ways come to my mind:
if you want to avoid too many zeros in the xtic labels, simply set the xtic label format to engineering
set format x "%.0s%c"
This will show, e.g. 10000 and 100000 as 10k and 100k, respectively.
if you scale (in your case: divide) the x values of the data by factor of 1000, gnuplot will take this x range for plotting the function f(x). Since this is will give x values which are a factor of 1000 too small you have to scale your x values by a factor of 1000 accordingly (in your case: multiply).
Code:
### avoid too many zeros in xtic labels
reset session
# create some random test data
set print $Data
A = rand(0)*10+5
B = rand(0)*50000+25000
C = rand(0)*5000+5000
do for [i=10000:100000:500] {
print sprintf("%g %g",i,A*exp(-((real(i)-B)/C)**2))
}
set print
a=1; b=50000; c=5000 # give some reasonable starting values
f(x) = a*exp(-((x-b)/c)**2)
set fit quiet nolog
fit f(x) $Data u 1:2 via a,b,c
set multiplot layout 1,2
set format x "%.0s%c" # set xtics to engineering
plot $Data u 1:2 w p, \
f(x) w l lc "red"
set format x "%g" # set xtics to default
plot $Data u ($1/1000):2 w p, \
f(x*1000) w l lc "red"
unset multiplot
### end of code
Result:
I try to draw some vector fields in a circular region. Consider the following MWE
unset grid
unset tics
unset colorbox
unset border
set size square
besselj(n, x) = n > 1 ? 2*(n-1)/x*besselj(n-1,x) - besselj(n-2,x) : (n == 1 ? besj1(x) : besj0(x))
dbesselj(n, x) = n/x*besselj(n,x) - besselj(n+1,x)
rho(x,y) = sqrt(x**2+y**2)
phi(x,y) = atan2(y,x)
d = 1.0
l = 1.0
z = l/2
q = 1
set xrange [-d/2*1.1:d/2*1.1]
set yrange [-d/2*1.1:d/2*1.1]
Erho(x,y,n,ynp) = (-1/rho(x,y)) * besselj(n, (ynp*2/d)*rho(x,y)) * (-n*sin(n*phi(x,y))) * sin(q*pi*z/l)
Ephi(x,y,n,ynp) = (ynp*2/d) * dbesselj(n, (ynp*2/d)*rho(x,y)) * (cos(n*phi(x,y))) * sin(q*pi*z/l)
Ex(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : cos(phi(x,y))*Erho(x,y,n,ynp) - sin(phi(x,y))*Ephi(x,y,n,ynp)
Ey(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : sin(phi(x,y))*Erho(x,y,n,ynp) + cos(phi(x,y))*Ephi(x,y,n,ynp)
mag(x,y,n,ynp) = sqrt(Ex(x,y,n,ynp)**2 + Ey(x,y,n,ynp)**2)
set object circle at 0,0 size 0.5 fc black lw 3 front
set multiplot layout 1,2
set title 'TE_{01}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,0,3.832)/50):(Ey($1,$2,0,3.832)/50) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,0,3.832)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
set title 'TE_{11}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,1,1.841)/20):(Ey($1,$2,1,1.841)/20) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,1,1.841)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
unset multiplot
which plots the vector field as well as its magnitude inside the circle with diameter d. The result from this is
which is totally okay for the left image (TE01), but the right image (TE11) looks ugly because there are some vectors which are drawn outside the circle. My actually desired result is this
where I have no vectors outside of the black circle. How can I achieve that?
I know there is the clip function in gnuplot, but this does not allow to specify the shape to be used for clipping.
Here is what you can try. Define your own clip function, e.g. a circle.
First you need to check whether a data point is outside of your circle or not.
Clip(x,y) returns NaN if it is outside and 0 if it is inside.
Now, when you plot simply add the value of the clip function to your value. Your data will be clipped within a circle because something +0 remains unchanged and something +NaN will be NaN and will not be plotted. It is sufficient if you do this just for x (vector start) and x + delta x (vector end).
Code:
### clip function in circle form
reset session
set size square
# create some test data
set samples 25
Scaling = 0.5
set table $Data
plot [-5:5] '++' u 1:2:(Scaling*$1/sqrt($1**2+$2**2)): \
(Scaling*$2/sqrt($1**2+$2**2)) : (sqrt($1**2+$2**2)) with table
unset table
set palette rgb 33,13,10
CenterX = 0
CenterY = 0
Radius = 3.5
Clip(x,y) = sqrt((x-CenterX)**2 + (y-CenterY)**2) > Radius ? NaN : 0
set xrange[-6:6]
set yrange[-6:6]
set multiplot layout 1,3
plot $Data u 1:2:3:4:5 w vec lc pal not
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
CenterX = 1
CenterY = 1
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
unset multiplot
### end of code
Result:
I want to fit the following data:
70 0.0429065
100 0.041212
150 0.040117
200 0.035018
250 0.024366
300 0.02017
350 0.018255
400 0.015368
to the following function which is combination of an exponantial and a gaussian functions:
$ f(x)= a1*(a2* exp(-x/T2e)+ exp(-(x/T2g)**2))
$ fit f(x) 'data' via a1,a2,T2e,T2g
But it keeps giving me the following results:
a1 = 0.0720021 +/- 0.04453 (61.84%)
a2 = 0.310022 +/- 0.9041 (291.6%)
T2e = 63291.7 +/- 2.029e+07 (3.206e+04%)
T2g = 252.79 +/- 32.36 (12.8%)
While when I try to fit it separetly to
$ g(x)=b* exp(-(x/T2g)**2)
$ fit g(x) 'data' via b,T2g
I get
b = 0.0451053 +/- 0.001598 (3.542%)
T2g = 359.359 +/- 16.89 (4.701%)
and
$ S(x)=S0* exp(-x/T2e)
$ fit S(x) 'data' via S0,T2e
gives:
S0 = 0.057199 +/- 0.003954 (6.913%)
T2e = 319.257 +/- 38.17 (11.96%)
I already tried to set the initial values but it didn't change the results.
Does anybody know what is wrong?
Thank you,
Ok, you can see an exponential decay with a hump which could be a Gaussian.
The approach, how I got to a fit: first, exclude the datapoints 100 and 150 and fit the exponental and then set a Gaussian approximately at 170.
You probably don't get a good fit, because at least the Gaussian peak is shifted by some value x1.
With the code:
### fitting
reset session
$Data <<EOD
70 0.0429065
100 0.041212
150 0.040117
200 0.035018
250 0.024366
300 0.02017
350 0.018255
400 0.015368
EOD
a = 0.055
T2e = 310
b = 0.008
x1 = 170
T2g = 54
Exponential(x) = a*exp(-x/T2e)
Gaussian(x) = b*exp(-((x-x1)/T2g)**2)
f(x) = Exponential(x) + Gaussian(x)
fit f(x) $Data u 1:2 via a,b,x1,T2e,T2g
plot $Data u 1:2 w lp pt 7, f(x) lc rgb "red"
### end of code
You'll get:
a = 0.0535048 +/- 0.00183 (3.42%)
b = 0.00833589 +/- 0.001006 (12.06%)
x1 = 170.356 +/- 5.664 (3.325%)
T2e = 315.114 +/- 12.94 (4.106%)
T2g = 54.823 +/- 12.13 (22.12%)
I have a problem when plotting a piecewise linear function h(x) = max(0, 1-|x|) (hat function) with gnuplot. My goal is to showcase the interpolation of a polynomial employing these hat functions as basis functions. Thus I need to shift and scale them to different grid points.
My code looks like this:
set key inside bottom right
set xrange [0:1]
set yrange [0:6]
set grid xtics
set style line 1 linecolor rgb '#0060ad' linetype 1 linewidth 2
set ytics 1
set xtics 2**(-3)
set key right top
s(x) = (3.0 * x - 1)
a0 = 2
a1 = -6
a2 = 5
a3 = 5
a4 = -5
a5 = 1
f(x) = a0 + a1*s(x) + a2*(s(x)**2) + a3*(s(x)**3) + a4*(s(x)**4) + a5*(s(x)**5)
max(x, y) = (x > y) ? x:y
h(x) = max(0, 1 - abs(x))
nodal(x, i)=h(2**(3)*x - i) * f(i * 2**(-3))
plot f(x) title "f(x)", nodal(x, 1)
The output however looks like this:
Obviously towards the point where the nodal basis function is not differentiable it fails to nicely plot the function, which looks bad. As I want to include this a thesis I have to submit, it is not something that I could include. Is there any solution for this problem?
I want to reproduce this effect in gnuplot:
How can I achive it? If it can't be done, what software can I use to reproduce it?
Using a 2d kernel for every pixel can be done inside gnuplot. That way, more dense accumulations get brighter than single pixels. Check show palette rgbformulae and the respective chapter in the help to change the colours.
set term wxt size 300,300 background rgb 0
set view map
set samp 140
set dgrid3d 180,180, gauss kdensity2d 0.2,0.2
set palette rgbform 4,4,3
splot "+" us 1:(sin($1/3)**2*20):(1) with pm3d notitle
Disclaimer: It can be done with gnuplot as instructed in this answer but you should probably consider a different tool to draw this particular type of plot.
There is at least one way to do it, with preprocessing of the data. The idea is to mimic the glow effect by using a Gaussian kernel to smear the data points. Consider the following data, contained in a file called data:
1 2
1 2.1
1.1 2.2
2 3
3 4
I have purposely placed the first 3 points close to each other to be able to observe the intensified glow of neighboring points. These data look like this:
Now we smear the data points using a 2D Gaussian kernel. I have written the following python code to help with this. The code has a cutoff of 4 standard deviations (sx and sy) around each point. If you want the glow to be a circle, you should choose the standard deviations so that the sx / sy ratio is the same as the ratio of the x/y axes lengths in gnuplot. Otherwise the points will look like ellipses. This is the code:
import numpy as np
import sys
filename = str(sys.argv[1])
sx = float(sys.argv[2])
sy = float(sys.argv[3])
def f(x,y,x0,y0,sx,sy):
return np.exp(-(x-x0)**2/2./sx**2 -(y-y0)**2/2./sy**2)
datafile = open(filename, 'r')
data = []
for datapoint in datafile:
a, b = datapoint.split()
data.append([float(a),float(b)])
xmin = data[0][0]
xmax = data[0][0]
ymin = data[0][1]
ymax = data[0][1]
for i in range(1, len(data)):
if(data[i][0] < xmin):
xmin = data[i][0]
if(data[i][0] > xmax):
xmax = data[i][0]
if(data[i][1] < ymin):
ymin = data[i][1]
if(data[i][1] > ymax):
ymax = data[i][1]
xmin -= 4.*sx
xmax += 4.*sx
ymin -= 4.*sy
ymax += 4.*sy
dx = (xmax - xmin) / 250.
dy = (ymax - ymin) / 250.
for i in np.arange(xmin,xmax+dx, dx):
for j in np.arange(ymin,ymax+dy, dy):
s = 0.
for k in range(0, len(data)):
d2 = (i - data[k][0])**2 + (j - data[k][1])**2
if( d2 < (4.*sx)**2 + (4.*sy)**2):
s += f(i,j,data[k][0],data[k][1],sx,sy)
print i, j, s
It is used as follows:
python script.py data sx sy
where script.py is the name of the file where the code is located, data is the name of the data file, and sx and sy are the standard deviations.
Now, back to gnuplot, we define a palette that mimics a glowing pattern. For isolated points, the summed Gaussians yield 1 at the position of the point; for overlapping points it yields values higher than 1. You must consider that when defining the palette. The following is just an example:
set cbrange [0:3]
unset colorbox
set palette defined (0 "black", 0.5 "blue", 0.75 "cyan", 1 "white", 3 "white")
plot "< python script.py data 0.05 0.05" w image
You can see that the points are actually ellipses, because the ratio of the axes lengths is not the same as that of the standard deviations along the different directions. This can be easily fixed:
plot "< python script.py data 0.05 0.06" w image
Set a black background, and then plot your dataset several time in different colours with decreasing pointsize.
set term wxt backgr rgb "black"
plot sin(x) w p pt 7 ps 2 lc rgb 0x00003f not, \
sin(x) w p pt 7 ps 1.5 lc rgb 0x00007f not, \
sin(x) w p pt 7 ps 1 lc rgb 0x0000af not, \
sin(x) w p pt 7 ps .5 lc rgb 0x0000ff
Alternatively, some combination of splot with pm3d,set dgrid3d gauss kdensity2d, and set view map, combined with a suitable palette, can be used, see my other answer.