Agung
Agung

Reputation: 55

how to use 3rd variable as fitting range in linear fit in gnuplot

I have some questions regarding data fitting in gnuplot. Suppose I have data formatted as follows example of data: test.txt

#   x       y       y_unc
1   0.20124531  2415.58 8.25706
2   0.20516169  2416.44 8.20651
3   0.21008456  2418.48 8.12084
4   0.21531272  2420.98 8.14102
5   0.22070909  2423.81 8.08436
6   0.2259568   2426.22 8.11353
7   0.23033106  2426.90 8.10172
8   0.23536205  2428.67 8.12772
9   0.24108887  2431.43 8.0769
10  0.24623346  2433.40 8.10201
11  0.252087    2436.33 8.19167
12  0.25853813  2439.53 8.14111
13  0.2634114   2441.27 8.14649
14  0.26842701  2442.58 8.19902
15  0.27422249  2444.09 8.25536
16  0.2799958   2447.22 8.32832
17  0.28573883  2449.42 8.37259
18  0.29226887  2452.35 8.34731
19  0.29696763  2453.71 8.32749
20  0.3020314   2454.80 8.40804
21  0.30853319  2457.60 8.3655
22  0.31335223  2459.26 8.41802
23  0.31937134  2461.96 8.4152
24  0.32383776  2461.80 8.45517
25  0.32963562  2464.02 8.49144
26  0.33469725  2465.15 8.37373
27  0.34041607  2467.62 8.30546
28  0.34591591  2469.44 8.30957
29  0.35146141  2471.29 8.37891
30  0.35608864  2471.50 8.30454
31  0.36138475  2472.98 8.31596
32  0.36773384  2476.24 8.43088
33  0.37238193  2476.59 8.34855
34  0.37814891  2478.86 8.26447
35  0.38311863  2479.65 8.28821
36  0.38847184  2481.35 8.25968
37  0.39456666  2484.14 8.21979
38  0.40007389  2486.06 8.16865
39  0.40610838  2488.30 8.25412
40  0.41157734  2490.10 8.29775
41  0.41630316  2491.59 8.31229
42  0.42112446  2492.40 8.26294
43  0.42697787  2494.75 8.32757
44  0.43137014  2495.07 8.36824
45  0.43700123  2496.25 8.46014
46  0.4422034   2497.68 8.45171
47  0.44765294  2500.41 8.42395
48  0.45317519  2502.29 8.48215
49  0.45835781  2503.81 8.50099
50  0.46392608  2505.78 8.61147
51  0.46943402  2508.04 8.60481
52  0.47533679  2510.15 8.58076
53  0.47967601  2510.77 8.6058
54  0.48523116  2513.11 8.63744
55  0.49090195  2515.74 8.8106
56  0.49617493  2517.32 8.8445
57  0.50119078  2518.77 8.87158
58  0.5066849   2520.57 8.93972
59  0.51132584  2522.25 8.91477
60  0.51644492  2524.03 8.89287
61  0.52197838  2526.33 9.00516
62  0.52705693  2528.27 8.92575
63  0.53193879  2529.73 8.95115
64  0.53704453  2531.44 8.99157
65  0.54210413  2532.46 9.03761
66  0.54626262  2533.34 9.00458
67  0.55056 2534.07 8.99342
68  0.55507934  2535.02 9.04953
69  0.55982471  2536.35 8.97597
70  0.56411815  2536.96 9.01189
71  0.56895626  2537.75 9.01932
72  0.57330275  2539.28 8.99917
73  0.57795715  2540.63 8.98475
74  0.58263767  2541.96 9.01778
75  0.58747137  2543.59 9.08297
76  0.59117234  2543.47 9.07999
77  0.59538865  2543.54 9.11839
78  0.59938073  2544.33 9.1549
79  0.60377049  2545.28 9.18278
80  0.60801435  2545.99 9.17474
81  0.61249495  2547.23 9.21996
82  0.61721373  2548.98 9.13147
83  0.62135947  2549.96 9.15198
84  0.6255244   2550.66 9.09919
85  0.629843    2551.9      9.15456
86  0.63427138  2553.34 9.21929
87  0.6376698   2552.96 9.19235
88  0.6422739   2554.31 9.24774
89  0.6468153   2555.74 9.1766
90  0.65102458  2556.53 9.22202
91  0.65579379  2558.13 9.16892
92  0.66031909  2559.52 9.20696
93  0.66545904  2561.28 9.29657
94  0.66935432  2561.9      9.23281
95  0.67299354  2562.15 9.28052
96  0.67770863  2564.20 9.37245
97  0.68189645  2565.98 9.48318
98  0.68605471  2566.81 9.56233
99  0.69018805  2567.83 9.59128
100 0.69424725  2568.67 9.63816

I try to fit the data in column 2 agains column 3. Up to now I can do the fit by using the following code

 # Fitting data from file 

reset session 
set terminal qt size 800,480
set key left

FILE = 'test.txt'

# fit function

f(x) = a*x+b

fit [0.25:0.58] f(x) FILE u 2:3  via a,b

chi2=(FIT_STDFIT*FIT_STDFIT)

# setting label 
set label 1 'Fit Parameters' left at graph 0.7, graph 0.95 font "arial,15"
set label 2 sprintf("y= %.2fx + %.2f", a,b)left at graph 0.7, graph 0.90 font "arial,10"
set label 3 sprintf("a = %.2f %.2s %.2f",a,'±',a_err) left at graph 0.7, graph 0.86 font "arial,10"
set label 4 sprintf("b = %.2f %.2s %.2f",b,'±',b_err) left at graph 0.7, graph 0.82 font "arial,10"
set label 5 sprintf("ndf = %.2f ",  FIT_NDF) left at graph 0.7, graph 0.78 font "arial,10"
set label 6 sprintf("{/Symbol c}^2/ndf = %.2f ", chi2) left at graph 0.7, graph 0.74 font "arial,10"

# setting label box
set arrow 1 nohead at 0.51, 2755 to 0.75, 2755
set obj 10 rect at 0.63, 2710 size 0.25, 160
set obj 10 fillstyle empty border -1 front

# setting range
set xrange [0:0.8]
set yrange [2200:2800]
set ytics nomirror
set y2range [-50:300]
set y2tics 
set x2zeroaxis lt -1
set xlabel 'x-axis'
set ylabel 'y-axis'
set y2label 'residual'

# plotting 

plot FILE u 2:3:4 w yerr pt 7  lc rgb 'black' ti 'data',\
[0:0.58] f(x) w l lw 2 lc rgb 'red' ti 'fit',\
[0.25:0.58] FILE u 2:(f($2)-$3) pt 1 axes x1y2  ti 'residual'

# end code

and using the test data I can obtain this result:

fitting data

My main question is: is it possible to use 3rd variable, e.g. the line number in column 1, as the fitting range, instead of using the x value? For example, using [1:5] to fit the first 5 data instead of using [0.20:0.22].

Additional question regarding my code above, I plot the residual in together with the fit, but I want to limit the residual plot only within the fitted data. Using the above code, the residual is plotted for the whole data and I got warning: "Ignoring sample range in non-sampled data" when running this code. Is there any way to fix this one?

And last one, is there a simpler way to print the fit parameters in the plot instead of using label?

Upvotes: 2

Views: 179

Answers (1)

theozh
theozh

Reputation: 25714

As I understand, you have several questions:

  1. fit a column versus another column while limiting the range by a third column
  2. simplify the label with the fitting results
  3. avoid warning: "Ignoring sample range in non-samples data"

ad 1: write a filter function, e.g. myRange(colD,colR,min,max) which returns NaN outside the desired range. colD is the data column, colR is the column for the range, min,max are the limits of the range.

ad 2: you can use newline \n in a label and use enhanced text. Check help enhanced. You can make a box around using set style textbox, might not work for all terminals, check help textbox. Still a bit confusing but certainly simpler than drawing many manually placed labels and arrows and boxes.

ad 3: again limit your plot via your filter function (see ad 1)

So, the following code:

  1. plots the data in the full range
  2. fits the data in a limited range, limited by a 3rd column
  3. plots the fit in a given range, here: [0:0.58]
  4. plots the residual in a limited range, limited by a 3rd column
  5. places a label with the results

Maybe there are simpler solutions which I am currently not aware of.

Code:

### limit fit and plotting range via 3rd column
reset session

$Data <<EOD
#   x       y           y_unc
1   0.20124531  2415.58 8.25706
2   0.20516169  2416.44 8.20651
3   0.21008456  2418.48 8.12084
4   0.21531272  2420.98 8.14102
5   0.22070909  2423.81 8.08436
6   0.2259568   2426.22 8.11353
7   0.23033106  2426.90 8.10172
8   0.23536205  2428.67 8.12772
9   0.24108887  2431.43 8.0769
10  0.24623346  2433.40 8.10201
20  0.4         2500    8.0         # just added to show the larger range
30  0.5         2560    8.0
EOD

# filter function
myRange(colD,colR,min,max) = column(colR)>=min && column(colR)<=max ? column(colD) : NaN

# fit function
f(x) = a*x+b
fit f(x) $Data u (myRange(2,1,1,5)):3  via a,b
chi2=(FIT_STDFIT*FIT_STDFIT)

# setting label 
set label 1 at graph 0.7, graph 0.95 boxed \
        sprintf("%s\n%s\n%s\n%s\n%s\n%s", \
        "{/'Arial':Bold=14 Fit Parameters}", \
        sprintf("y= %.2fx + %.2f", a,b), \
        sprintf("a = %.2f %.2s %.2f",a,'±',a_err), \
        sprintf("b = %.2f %.2s %.2f",b,'±',b_err), \
        sprintf("ndf = %.2f ",  FIT_NDF), \
        sprintf("{/Symbol c}^2/ndf = %.2f ", chi2))
        
set style textbox border
set key left

# setting range
set xlabel 'x-axis'
set xrange [0:0.8]

set ylabel 'y-axis'
set yrange [2200:2800]
set ytics nomirror

set y2label 'residual'
set y2range [-50:300]
set y2tics 
set x2zeroaxis lt -1

plot $Data u 2:3:4 w yerr pt 7  lc rgb 'black' ti 'data',\
    [0:0.58] f(x) w l lw 2 lc rgb 'red' ti 'fit',\
    $Data u (myRange(2,1,1,5)):(f($2)-$3) pt 1 axes x1y2  ti 'residual'
### end of code

Result:

enter image description here

Upvotes: 1

Related Questions