Search code examples
plotgnuplot

Fitting and plotting a series in gnuplot


This is similar to this question and this but my problem is that I have several hundred files that need to be simultaneously fitted and plotted on one graph. Unlike the other questions posted I'm looking for the best fits for each file, not for the global data set so cat won't work.

I was hoping to use fit.. for like I do for plot but it's not working so well. Here's what I've got so far:

f(x) = 1+d*exp(-(x-f)**2/(2*(g**2)))+a*exp((-(x-b)**2)/(2*(c**2)))

filename(n) = sprintf("rheosaxs_saxs_%005d_0001_var_rebin_div.dat", n)
fit f(x) for [n=575:584] filename(n) u 1:2 via a,b,c,d,f,g
plot for [n=575:584] filename(n) using 1:2, f(x)

the error I get is: line 60: undefined variable: for which corresponds to the fit f(x) for [n=a:b]

I know that my starting parameters are reasonable because I can plot them without the fit command and they look sensible. Similarly my plot for works ok.

Any ideas? Thank you :)


Solution

  • In version 5.2 gnuplot introduces arrays, which allow you to save the results of each fit and plot those later.

    A simplified example script would be

    file(n) = sprintf('myfile_%d.dat', n)
    f(a, x) = a*x
    
    array A[10]
    do for [i=1:10] {
        tmpA = 1
        fit f(tmpA, x) file(i) via tmpA
        A[i] = tmpA
    }
    
    plot for [i=1:10] file(i),\
         for [i=1:10] f(A[i], x)
    

    Although gnuplots arrays are implemented as linked list of user variables, it is not possible to use A[i] directly for the fit, but I had to use a temporary variable to get it right.

    A full working example, including generation of random data, with python from gnuplot, uargh ;):

    # generate some random data
    system("python3 -c 'import random\nfor i in range(1, 11):\n\twith open(\"output_{0}.dat\".format(i), \"w\") as f:\n\t\tf.write(chr(10).join([str(i*100 + i* x * (1 + 0.1*(random.random()-0.5))) for x in range(0,100)]))'")
    
    
    file(n) = sprintf('output_%d.dat', n)
    
    f(a, b, x) = a*x + b
    array A[10]
    array B[10]
    do for [i=1:10] {
        tmpA = 1
        tmpB = 1
        fit f(tmpA, tmpB, x) file(i) u 0:1 via tmpA, tmpB
        A[i] = tmpA
        B[i] = tmpB
    }
    
    plot for [i = 1:10] file(i) u 0:1 with points lt i notitle, \
         for [i=1:10] f(A[i], B[i], x) with lines lt i notitle
    

    enter image description here

    BTW: There is no fit for, because that is equivalent to do for { fit }. But when plotting, plot for generates a single plot with multiple functions, whereas do for { plot } makes several plots and should be used with multiplot