Gnuplot with Errorbars and line of regression - gnuplot

I want to graph some values with errorbars but it somehow doesnt work. Can you help me please?
431.00E12 0.69 47.00E5
567.00E12 1.10 58.00E5
662.00E12 1.75 67.00E5
watched a lot of videos and tutorials and did exactly what they did but it doesnt work.. The part with Regression and so on worked fine but now I want those error bars horizontally. My textfile is in this order:
x-Value y-Value DeltaX
The DeltaX should be the Errorbar so the errorbar schould look like this: at point x, the errorbar has length from x+-DeltaX.
Could you please tell me the code that combines the regression line and the Errorbars?
plot "/Users/amar/Desktop/dgd.txt" using 1:2:3 with errorbars, f(x)

Check help xerrorbars.
A delta x which is 8 orders of magnitude smaller than the x-value will be difficult to see as errorbar. Just to demonstrate xerrorbars, I changed it to a similar order of magnitude.
With the following code:
### xerrorbars
reset session
$Data <<EOD
431.00E12 0.69 47.00E12
567.00E12 1.10 58.00E12
662.00E12 1.75 67.00E12
EOD
set key left
f(x) = a*x + b
a = 1e-15 # some initial guesses
b = -1
set fit nolog brief
fit f(x) $Data u 1:2 via a,b
plot $Data u 1:2:3 with xerrorbars pt 7 lc rgb "red", \
f(x) title sprintf("f(x) = %g * x + %g",a,b)
### end of code
You'll get:

Related

How to fit a logarithmic function with gnuplot?

I have the following data and want to fit a function with gnuplot. It seems that the function is:
f(x) = 0.000855*(1 + b*log(x/a)) with b=0.45 and a=32.23
fits with the data. I used the following command in gnuplot but I couldn't fit this function with the data.
6.77 0.000165774
8.13 0.00034866
9.48 0.000440373
10.83 0.000473223
16.25 0.000589812
18.28 0.000629904
20.31 0.000661883
I used the following command:
p "./data.txt" u 1:2
f(x) = 0.000855*( 1 + b*log(x/a))
fix f(x) "data.txt" using 1:2 via b,a
p "./data.txt", f(x)
could you please suggest any more functions?
Thanks in advance,
How do you know that your function should fit the data and from where do you get the values a,b?
In general, you can shift and scale basic functions, e.g. like log().
So, if you think log(x) is a suitable function to describe your data then try to shift and scale it.
Shift x by x0, shift y by y0 and scale with some factor a.
Altogether:
f(x) = a*log(x-x0) + y0
In the script example below it seems that you don't even need approximate starting values to let the fit converge.
However, the mathematical description of your system should give you the function. Without knowing your system, nobody can tell whether f(x) is an appropriate function to fit your data.
Script:
### fitting a log function
reset session
$Data <<EOD
6.77 0.000165774
8.13 0.00034866
9.48 0.000440373
10.83 0.000473223
16.25 0.000589812
18.28 0.000629904
20.31 0.000661883
EOD
f(x) = a*log(x-x0) + y0
set fit nolog
fit f(x) $Data u 1:2 via a,x0,y0
set key top left
plot $Data u 1:2 w lp pt 7, \
f(x) w l lc "red", \
0.000855*(1 + 0.45*log(x/32.23)) w l dt 3 lc "blue" ti "your guess"
### end of script
Result:
Final set of parameters Asymptotic Standard Error
======================= ==========================
a = 0.000153601 +/- 8.592e-06 (5.594%)
x0 = 6.17491 +/- 0.1102 (1.785%)
y0 = 0.000245976 +/- 1.982e-05 (8.057%)

How to merge all plots in one window in gnuplot

I know similar question are asked and answered multiple times in SO.
Here I have something unique that includes the fitting for each plot.
I am using
f(x) = (a0 + a1/x)
fit f(x) 'test.data' using 1:2 via a0,a1
plot 'test.data' using 1:2 w points pt 1 t , f(x) t sprintf("K_{fit} = a_0 + a_1/T", a0)
f(x) = (a0 + a1/x)
fit f(x) 'test.data' using 1:3 via a0,a1
plot 'test.data' using 1:3 w points pt 1 t , f(x) t sprintf("K_{fit} = a_0 + a_1/T", a0)
here I am skipping other plot commands to keep the query short.
f(x) = (a0 + a1/x)
fit f(x) 'test.data' using 1:8 via a0,a1
plot 'test.data' using 1:8 w points pt 1 , f(x) t sprintf("K_{fit} = a_0 + a_1/T", a0)
f(x) = (a0 + a1/x)
fit f(x) 'test.data' using 1:9 via a0,a1
plot 'test.data' using 1:9 w points pt 1 t , f(x) t sprintf("K_{fit} = a_0 + a_1/T", a0)
Using the above plots, I am getting one box for each plot.
How I can merge all plots in a single window?
The data files is having 9 columns (1st colum will be x-axis while others are y-axos) and inserting plot commands for each plot makes the gnuplot script too long. Is there any workaround so that I do not need to type p"plot each time and the job can be done by some loop?
I tried to manage all plots in a single box using
plot for [i=1:9] 'test.data' using (i):i notitle with boxplot lt -1, \
f(x) = (a0 + a1/x)
fit f(x) 'test.data'for [i=1:9] using (i):i via a0,a1
plot 'test.data' for [i=1:9] using (i):i w points pt 1 t , f(x) t sprintf("K_{fit} = a_0 + a_1/T", a0)
but I am getting below error
fit f(x) 'test.data'for [i=1:9] using (i):i via a0,a1
^
"test.gnu", line 23: Need via and either parameter list or file
Below is my test.data file
100.0 0.45564E+02 0.20558E+02 0.53903E+02 0.24899E+02 0.56334E+02 0.26169E+02 0.58482E+02 0.27273E+02
200.0 0.17118E+02 0.81681E+01 0.18147E+02 0.86680E+01 0.18397E+02 0.87831E+01 0.18598E+02 0.88736E+01
300.0 0.10908E+02 0.53456E+01 0.11307E+02 0.55301E+01 0.11398E+02 0.55703E+01 0.11470E+02 0.56013E+01
400.0 0.81160E+01 0.40313E+01 0.83328E+01 0.41288E+01 0.83808E+01 0.41496E+01 0.84181E+01 0.41655E+01
500.0 0.64937E+01 0.32506E+01 0.66311E+01 0.33115E+01 0.66611E+01 0.33243E+01 0.66841E+01 0.33340E+01
600.0 0.54231E+01 0.27282E+01 0.55185E+01 0.27700E+01 0.55390E+01 0.27787E+01 0.55547E+01 0.27853E+01
700.0 0.46602E+01 0.23525E+01 0.47305E+01 0.23830E+01 0.47455E+01 0.23894E+01 0.47569E+01 0.23942E+01
800.0 0.40878E+01 0.20687E+01 0.41419E+01 0.20920E+01 0.41533E+01 0.20968E+01 0.41620E+01 0.21005E+01
900.0 0.36419E+01 0.18465E+01 0.36847E+01 0.18649E+01 0.36937E+01 0.18687E+01 0.37006E+01 0.18716E+01
1000.0 0.32843E+01 0.16677E+01 0.33192E+01 0.16826E+01 0.33264E+01 0.16857E+01 0.33320E+01 0.16880E+01
If you check help fit you won't find that gnuplot can fit in a loop as in a plot loop.
But you can fit several data columns in a do for loop, check help do.
And you can store the fit parameters in arrays for plotting them later in a plot for loop. I hope you can figure out how the example code below works.
Code:
### fit multiple columns in a loop
reset session
f(x) = a0 + a1/x
# arrays for fit parameters
array arr0[8]
array arr1[8]
# create some random test data
do for [i=1:8] {
arr0[i] = int(rand(0)*50)+5
arr1[i] = int(rand(0)*10)+5
}
set print $Data
do for [x=10:50] {
line = sprintf("%g",x/100.)
do for [i=1:8] {
a0 = arr0[i]
a1 = arr1[i]
line = line.sprintf(" %.3f",f(x/100.)+10*i)
}
print line
}
set print
# fit columns in a loop and put fit values into array
do for [i=1:8] {
fit f(x) $Data u 1:i+1 via a0,a1
arr0[i] = a0
arr1[i] = a1
}
set key Left
plot for [i=1:8] $Data u 1:i+1 ti sprintf("%d: a0=%.1f, a1=%.1f",i,arr0[i],arr1[i]), \
for [i=1:8] tmp=(a0=arr0[i],a1=arr1[i]) f(x) w l lc rgb "red" not
### end of code
Result:
Addition (with OP's data)
Code:
### fit multiple columns in a loop
reset session
f(x) = a0 + a1/x
# arrays for fit parameters
array arr0[8]
array arr1[8]
$Data <<EOD
100.0 0.45564E+02 0.20558E+02 0.53903E+02 0.24899E+02 0.56334E+02 0.26169E+02 0.58482E+02 0.27273E+02
200.0 0.17118E+02 0.81681E+01 0.18147E+02 0.86680E+01 0.18397E+02 0.87831E+01 0.18598E+02 0.88736E+01
300.0 0.10908E+02 0.53456E+01 0.11307E+02 0.55301E+01 0.11398E+02 0.55703E+01 0.11470E+02 0.56013E+01
400.0 0.81160E+01 0.40313E+01 0.83328E+01 0.41288E+01 0.83808E+01 0.41496E+01 0.84181E+01 0.41655E+01
500.0 0.64937E+01 0.32506E+01 0.66311E+01 0.33115E+01 0.66611E+01 0.33243E+01 0.66841E+01 0.33340E+01
600.0 0.54231E+01 0.27282E+01 0.55185E+01 0.27700E+01 0.55390E+01 0.27787E+01 0.55547E+01 0.27853E+01
700.0 0.46602E+01 0.23525E+01 0.47305E+01 0.23830E+01 0.47455E+01 0.23894E+01 0.47569E+01 0.23942E+01
800.0 0.40878E+01 0.20687E+01 0.41419E+01 0.20920E+01 0.41533E+01 0.20968E+01 0.41620E+01 0.21005E+01
900.0 0.36419E+01 0.18465E+01 0.36847E+01 0.18649E+01 0.36937E+01 0.18687E+01 0.37006E+01 0.18716E+01
1000.0 0.32843E+01 0.16677E+01 0.33192E+01 0.16826E+01 0.33264E+01 0.16857E+01 0.33320E+01 0.16880E+01
EOD
# fit columns in a loop and put fit values into array
set fit nolog
do for [i=1:8] {
fit f(x) $Data u 1:i+1 via a0,a1
arr0[i] = a0
arr1[i] = a1
}
set key Left
plot for [i=1:8] $Data u 1:i+1 ti sprintf("%d: a0=%.1f, a1=%.1f",i,arr0[i],arr1[i]), \
for [i=1:8] tmp=(a0=arr0[i],a1=arr1[i]) f(x) w l lc rgb "red" not
### end of code
Result:
Addition: (after your comments)
You can also plot the data in a loop.
You can simply define functions for the linetype and the dashtype. Dashtype dt 1 is a solid line and dt 2 is a dashed line basically identical to dt "-". Type test in the gnuplot console and you will see the different linestyles.
Maybe also an explanation for the term tmp=(a0=arr0[i],a1=arr1[i]). You can add a definition in the plot command (see help plot), but since we need two definitions a0=arr0[i] and a1=arr1[i] we use serial evaluation (see help operators binary) and assign it to a dummy variable tmp.
Your functions and the plot command would then be:
myLineType(i) = (i-1)/2+1 # Attention: /2 in gnuplot is integer division if `i` is integer!
myDashType(i) = (i-1)%2+1 # % is modulo
plot for [i=1:8] $Data u 1:i+1 w l lw 2 lt myLineType(i) dt myDashType(i) not, \
for [i=1:8] tmp=(a0=arr0[i],a1=arr1[i]) f(x) w p lt myLineType(i) not

Problems to fit with gnuplot and non-linear function

I have this set of data that want to fit with gnuplot using the function f(x) = exp(A+ B/(x-x0)) where A,B and x0 are my set of parameters to fit
# x f(x)
0.382 8.29023731095968
0.509 6.36124122026352
0.637 4.66938977764103
0.764 3.3194714217965
0.891 2.15140777817893
1.019 1.15428884806615
1.146 0.262232461832655
I have try it with
fit log(f(x)) 'data.dat' using 1:(log($2)) via A, B, x0
also have defined the function as f(x) = A+ B/(x-x0) and tried with
fit f(x) 'data.dat' using 1:(log($2)) via A, B, x0
and then plot exp(f(x))
The code works but the fitted parameters are not fine, because when I plot the curve and the points together not make sense. Is this fit too complicate for gnuplot?
Fitting can fail if you have an inappropriate function or if you have starting values which might make it difficult for the fitting procedure to converge.
In your case, I guess x0 is an important parameter. You should help the gnuplot fitting algorithm a little to have a chance to find reasonable values. Here, I guess x0=1.5 is a reasonable starting value. If this is not sufficient and if your model permits you might want to add additional variables or terms to get a better fit.
Code:
### fitting with appropriate starting values
reset session
$Data <<EOD
0.382 8.29023731095968
0.509 6.36124122026352
0.637 4.66938977764103
0.764 3.3194714217965
0.891 2.15140777817893
1.019 1.15428884806615
1.146 0.262232461832655
EOD
A = 1
B = 1
x0 = 1.5
f(x) = exp(A + B/(x-x0))
set fit nolog
fit f(x) $Data u 1:2 via A,B,x0
plot $Data u 1:2 w lp pt 7 ti "Data",\
f(x) w l lc rgb "red" ti "Fit"
### end of code
Result:
Final set of parameters Asymptotic Standard Error
======================= ==========================
A = 4.61445 +/- 0.3907 (8.466%)
B = 3.57094 +/- 0.8876 (24.86%)
x0 = 1.80616 +/- 0.1371 (7.593%)

fitting sub-range on time data in gnuplot

Let me start by saying that I am working on:
$ gnuplot --version
gnuplot 5.2 patchlevel 2
I would like to plot and fit date/time data in gnuplot and have the fit only performed and subsequently displayed on a sub-range of the plot.
Example data that I played with can e.g. be found here.
EDIT: I realized that the data in the file don't match the timefmt signature, I added a /06 to each line so that the point would be drawn in the middle of the year which allowed to nicely plot it together with also monthly data from the same source.
I can get the desired result with the code below where I plot three functions, one over the full range of the plot and two others both of which only cover part of the date range.
set key left
set yrange[-0.75:1.0]
set xdata time
set timefmt '%Y/%m'
r=10e-10
e(x) = r*x+s
fit e(x) 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 via r,s
a=10e-10
f(x) = a * x + b
set xrange ["1970/06":"2018/06"]
fit f(x) 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 via a,b
g(x) = ( x > "1970/06" ) ? f(x) : 1/0
set xrange ["1850/06":"1970/06"]
c=9.24859e-11
h(x) = c * x + d
fit h(x) 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 via c,d
i(x) = ( x < "1970/06" ) ? h(x) : 1/0
set xrange ["1849/06":"2018/06"]
set term png size 1500,1000
set output 'annual_average_with_fit.png'
plot 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 with lp lw 2 t'annual avg (decadally smoothed)', e(x) t'full range fit' lw 2, i(x) t'1850-1970 fit' lw 2, g(x) t'1970-2018 fit' lw 2
which yields this plot
This is all good and well, but (and this is where the question comes in) in principle I should be able to achieve the same result also by other means.
First: I restrict the range of the file data to a certain range to fit it only on that range. In principle I should be able to do the same using this (type of) syntax:
fit ["1970/06":"2018/06"] f(x) 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 via a,b
which however gives
Read 168 points
Skipped 168 points outside range [x=1970:2018]
[...] No data to fit
which seems weird given that the set xrange clearly has the desired effect.
Secondly trying to restrict the plotting of the curve to the fit range with
plot 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt' using 1:2 with lp lw 2 t'annual avg (decadally smoothed)', ["1970/06":"2018/06"] f(x) t''
does not plot the function at all.
I might be overlooking something very basic, but having tried various things I don't see what it is
The following (a bit cleaned up) code should do what you want (tested with gnuplot 5.2.5).
I guess the problem is that you tried to fit a range ["1970/06":"2018/06"], but your data is only until 2017. So better leave it open, e.g. ["1970/06":] or ["1970/06":*].
edit: added a limited range fit i(x)
reset session
set term png size 1500,1000
set output 'annual_average_with_fit.png'
set key left
set yrange[-0.75:1.0]
set xdata time
set timefmt '%Y/%m'
set format x '%Y'
FILE = 'HadCRUT.4.6.0.0.annual_ns_avg_smooth.txt'
r=10e-10
f(x) = r*x+s
fit [*:*] f(x) FILE using 1:2 via r,s
c=9.24859e-11
g(x) = c * x + d
fit [*:"1970/06"] g(x) FILE using 1:2 via c,d
a=10e-10
h(x) = a * x + b
fit ["1970/06":*] h(x) FILE using 1:2 via a,b
p=1e-9
i(x) = p * x + q
fit [strptime("%Y/%m", "1910/06"):strptime("%Y/%m", "1945/06")] i(x) FILE using 1:2 via p,q
set xrange [*:*]
plot FILE using 1:2 with lp lw 2 t'annual avg (decadally smoothed)', \
f(x) t 'full range fit' lw 2, \
[:"1970/06"] g(x) t '1850-1970 fit' lw 2, \
["1970/06":] h(x) t '1970-2018 fit' lw 2,\
[strptime("%Y/%m", "1910/06"):strptime("%Y/%m", "1945/06")] i(x) t '1910-1945 fit' lw 2
set output
Output:

How to restrict yrange for fit in gnuplot

I used the following scripts for plotting and fitting.
Data set:
2.474 2.659
0.701 2.637
0.582 2.643
0.513 2.666
0.403 2.639
0.308 2.615
0.218 2.561
0.137 2.537
Script:
reset
set key bottom right
f(x) = a*atan(x/b); a = 2.65; b = 2.5
fit f(x) 'test.txt' u 1:2 via a,b
plot 'test.txt' u 1:2 w p not, f(x) t 'f(x)'
The plot looks like this:
I am trying to restrict it between min_y and max_y. The following intuitive code failed horribly,
fit [y=2.537:2.659] f(x) 'test.txt' u 1:2 via a,b
Any suggestion on restriction would be highly appreciated! Thanks!
The range option only specifies which input points should be used, not restricting the output. So far as I can see from the manual, restrictions on the output value of f(x) aren't really possible (and so far as I can see from the problem, not really desirable).
You should be able also to do it simply by defining a fit range [][].
The following code works also with gnuplot4.6 which was the version in 2014.
"Data.dat":
1 2
2 3
3 4
1 9
2 8
3 7
Code:
### fit with limited y-range
reset
set xrange[0:10]
set yrange[0:10]
f(x) = a*x + b
set multiplot layout 3,1
fit [*:*][0:5] f(x) "Data.dat" u 1:2 via a,b
plot "Data.dat" u 1:2 w p pt 7 lc rgb "red" not,\
f(x) t sprintf("Fitrange: [*:*][0:5]\nf(x) = %g*x + %g",a,b)
fit [*:*][5:10] f(x) "Data.dat" u 1:2 via a,b
plot "Data.dat" u 1:2 w p pt 7 lc rgb "red" not,\
f(x) t sprintf("Fitrange: [*:*][5:10]\nf(x) = %g*x + %g",a,b)
fit [*:*][0:10] f(x) "Data.dat" u 1:2 via a,b
plot "Data.dat" u 1:2 w p pt 7 lc rgb "red" not,\
f(x) t sprintf("Fitrange: [*:*][0:10]\nf(x) = %g*x + %g",a,b)
unset multiplot
### end of code
Result:
This is an old question, but I arrived here looking for a solution to a similar problem. The answer is to use the stats command:
stats 'test.txt'
This will analyze, by default, the y data and set a bunch of STATS_* variables, which you can use in your fit statement along with the ternary operator:
fit f(x) 'test.txt' u 1:($2 >= STATS_min && $2 <= STATS_max ? $2 : NaN) via a,b
You can also add a using clause to the stats statement to further filter the data to match your fit statement, if needed.

Resources