How to restrict yrange for fit in gnuplot - 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.

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%)

Show a label of x and y values, and possibly other values when hovering over a function with the mouse in GNUPLOT

Is there a way that when i hover over a function, say f(x) = x**2, that it pops up a label when i move my mouse onto the function at, say, x=2, it shows a label of "x = 2 \n (new line) y = 4" or something like that? Also if that is possible can I make it so that it includes external values? What i mean by this is if i have a gradient formula, for x**2, 2*x, I can tell GNUPLOT to say below the x and y label values, "Gradient: 4". It doesn't have to be the derivative but that is just an example of what i mean.
I guess you are looking for hypertext. In the gnuplot console check help hypertext.
If you move the mouse pointer close to a datapoint, some text will pop-up. It will be easier to "catch" the point and get the hypertext shown if you plot the labels with a pointsize a bit larger, e.g. ps 3 and "invisible", i.e. lt -2 which is the background color.
This works with an interactive wxt terminal. You need to check other terminals. Tested with gnuplot 5.2.6.
Code:
### add hypertext (wxt terminal)
reset session
# create some test data
set print $Data
do for [x=-5:5] {
print sprintf("%g %g", x, x**2)
}
set print
plot $Data u 1:2:(sprintf("x=%g\ny=%g",$1,$2)) w labels hypertext point pt 7 ps 3 lt -2 notitle, \
'' u 1:2 w lp pt 7 title "f(x)"
### end of code
Result: (screenshot)
Addition:
Example with more points and plotted with lines. There is no snapping to the curve, you have to move along the curve.
Code:
### add hypertext (wxt terminal)
reset session
# create some test data
set samples 201
set xrange[-5:5]
set table $Data
plot '+' u 1:($1**2):(2*$1) w table
unset table
set xlabel 'x'
set ylabel 'y'
plot $Data u 1:2:(sprintf("x=%.2f\ny=%.2f\ndy/dx=%.2f",$1,$2,$3)) w labels hypertext point pt 7 ps 1 lt -2 notitle, \
'' u 1:2 w l lw 2 title "f(x)"
### end of code
Result: (screen capture)
Addition2: (using functions for interactive zoom-in)
Code:
### add hypertext (wxt terminal) with functions for interactive zoom-in
reset session
set xlabel 'x'
set xrange[-5:5]
set ylabel 'y'
set samples 201
f(x) = x**2
g(x) = 2*x
plot '+' u (x):(f(x)):(sprintf("x=%.2g\ny=%.2g\ndy/dx=%.2g",x,f(x),g(x))) w labels hypertext point pt 7 ps 1 lt -2 notitle, \
f(x) w l lw 2 title "f(x)"
### end of code

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

Gnuplot with Errorbars and line of regression

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:

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:

Resources