2

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?
ASarkar
  • 469
  • 5
  • 16
  • As far as I understand it, unfortunately: 1.) Basically, yes. 2.) Not really. Define your function a second time, with normal variable names (a,b,c, or p1,p2,p3), and transfer the values inbetween as necessary. – Karl Jan 24 '19 at 22:03
  • from your minimal example, I do not see any necessity or advantage using an array `p[n]` instead of `p1,p2,p3`. Maybe for your actual task there is some more code around where you need arrays? – theozh Jan 31 '19 at 11:43
  • @theozh: I am in the process of writing a code via which one could call gnuplot directly from fortran. It would have been helpful if arrays worked as regular variables, specifically for fitting a curve. – ASarkar Feb 01 '19 at 13:39

1 Answers1

0

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

theozh
  • 22,244
  • 5
  • 28
  • 72
  • actually, you could also initialize your array like this: `array p[3] = [1.3, 0.2, 0.7]`. – theozh Jan 08 '21 at 11:47
  • Thanks, @theozh for working on this example. But like you said this is a bit complicated for my taste :). But since this achieves what I wanted I will accept the answer, unless I can come across a better answer. – ASarkar Jan 08 '21 at 15:25