Search code examples
arraysplotgnuplotbest-fit-curve

Gnuplot: Using arrays as parameters in fit curve doesn't work


It seems individual array values do not work the same way in gnuplot as normal variables.

I have tried the following code given below.

# Following code doesn't work.
reset

# Parameters and fitting curve
n = 3
array p[n]
p[1] = 1.3 ; p[2] = 0.2 ; p[3] = 0.7
f(x) = p[1] * sin( p[2] + p[3] * x )

set fit
fit f(x) 'datafile.txt' using 1:2 via p[1], p[2], p[3]
unset fit

I get the following error: line 11: unknown type in real()

Note that if I change the arrays p[1], p[2], p[3], to a, b, c the code works.

# Following works.
reset

a = 1.3 ; b = 0.2 ; c = 0.7
f(x) = a * sin( b + c * x )

set fit
fit f(x) 'datafile.txt' using 1:2 via a, b, c
unset fit

Partial data is given below (should be saved as 'datafile.txt') for completeness:

# x y
0  0.0222457
0.1  0.113168 
0.2  0.252268  
0.3  0.378091  
0.4  0.397219  
0.5  0.577536  
0.6  0.621418  
0.7  0.695817  
0.8  0.741057  
0.9  0.849566  
1  0.864276  

So my question is:

  1. Is my assumption correct that gnuplot arrays do not work the same way as normal variables?
  2. Is there a way to make the arrays behave in the same manner as normal variables?

Solution

  • As @Karl mentioned in the comments, you would have to assign your variables and arrays back and forth. The following solution seems to work in an automated way, but I'm not sure whether this is really a simplification. Maybe it makes life a bit easier if you want to change from p to q, or from 3 variables to 7 variables. It uses a few not so obvious "tricks", check help arrays, help macros, help evaluate, help keyentry, help sum, help sprintf, ...

    Code:

    ### workaround for fitting using array values
    reset session
    
    $Data <<EOD
    # x y
    0  0.0222457
    0.1  0.113168 
    0.2  0.252268  
    0.3  0.378091  
    0.4  0.397219  
    0.5  0.577536  
    0.6  0.621418  
    0.7  0.695817  
    0.8  0.741057  
    0.9  0.849566  
    1  0.864276  
    EOD
    
    # parameters and fitting curve
    N = 3
    array p[N]
    p[1] = 1.3 ; p[2] = 0.2 ; p[3] = 0.7
    myVar = 'p'   # define your variable
    myColX = 1
    myColY = 2
    
    f(x) = p1 * sin( p2 + p3 * x )    # fitting function, defined with p1, p2, p3, ..., pN
    
    #=======
    # from here on "everything" goes automatic with variables and arrays
    print "Initial array values: ", @myVar
    
    # defining procedures for assigning variables and/arrays back and forth
    myArrToVar(var) = sprintf("do for [i=1:|%s|] { eval(sprintf('%s%s = %s[%s]',i,i)) }",var,var,'%d',var,'%d')
    myVarToArr(var) = sprintf("do for [i=1:|%s|] { eval(sprintf('%s[%s] = %s%s',i,i)) }",var,var,'%d',var,'%d')
    
    # values from array --> variables
    ArrToVar = myArrToVar(myVar)
    @ArrToVar
    
    # create the via, e.g p1,p2,p3,...
    myViaStr(var) = (_tmp = '', (sum[_i=1:N] (_tmp = _tmp.sprintf('%s%d%s',var,_i,_i==N?'':', '),1)), _tmp)
    viaStr = myViaStr(myVar)
    
    # actual fitting
    set fit quiet nolog
    fit f(x) $Data using myColX:myColY via @viaStr
    
    # values from variables --> array
    VarToArr = myVarToArr(myVar)
    @VarToArr
    
    print "Final array values:  ", @myVar
    set key top left
    
    plot $Data u myColX:myColY w p pt 7 ti "Data", \
         f(x) w l lc "red", \
         for [i=1:N] keyentry ti sprintf('%s[%d]=%.4f',myVar,i,@myVar[i])
    ### end of code
    

    Result:

    Initial array values: [1.3,0.2,0.7]
    
    Final array values:  [0.9215500294371,0.0231339564404058,1.20450770853891]
    

    enter image description here