I am using gnuplot v6 rc1 as I am relying on a function block to implement a non-trivial algorithm.
I have a function block definition function $f << _EOFD that returns a 7 element array based on each data point in a dataset. The function call, $f($1), consumes each data point in the dataset parsed by a plot command and returns a 7-element array value. So I wish to achieve something equivalent to:
local array x[7] = $f($1)
where the scope of that local array variable, x, extends over the entire plot command that makes the $f($1) function call (just the once!) for each line of the dataset.
- The datasets are never complex and are "well behaved" - being just one positive integer value per line in an ASCII file and always monotonic increasing in magnitude. The length of a dataset can be very large. Currently ~20,000,000 data points is the longest dataset but I run short tests using datasets of fewer than 600 data points.
Ideally, within the current plot command I'd assign the return value of the function to an array variable and then use references to that array variable within the "using : : : : " section of the plot command however, I cannot see how to achieve such a variable assignment in a way that will trigger for each reading of a data point by the plot command. I cannot find an example of plot command syntax that accommodates this. The closest I have read is the notion of using one <plot element>, to define a function which can then be used across the remainder of the plot command. I'd like to do something similar but with an array variable rather than a function.
As you will see from the script snippet below, I use 5 elements of the returned array in a plot command and since I currently do so by calling $f($1) a total of (5+6)=11 times I suspect it is terribly wasteful of CPU cycles and time.
I'd appreciate learning how to achieve the same result more efficiently/elegantly.
script snippet to illustrate:-
array lastFNvalue[7] = [0,0,0,0,0,0,0]
function $f << _EOFD
if ( (lastFNvalue[2] == ARGC) && (lastFNvalue[1] == ARGV[1]) ) { return lastFNvalue }
:
: # algorithm yielding 5 values from one input value
:
local array s[7] = [ ARGV[1], ARGC, azimuth, r, delTheta, delR, density ]
lastFNvalue = s
return s
_EOFD
:
: # intervening code of no direct relevance
:
plot @inFile \
using ($f($1)[3]) : ($f($1)[4]) : ($f($1)[5]) : ($f($1)[6]) : ($f($1)[7]) \
with sectors linecolor palette \
, @inFile \
using ($f($1)[3]+$f($1)[5]/2) : ($f($1)[4]-0.4) : 1 : (-fixT*( ($f($1)[3]+$f($1)[5]/3) + pi/2 ) ) : ($f($1)[7]) \
with labels nopoint center rotate variable textcolor palette font "Times,8" \
, '-' using 1:2:3:4:5 with sectors linecolor variable
0 0 2 @N 0
EOD
So you can see that elements 3,4,5,6 of the array are used to plot (annular) sectors and element 7 (the density) indexes a color palette to yield a meaningful color for each radius of this plot .. which clearly uses polar coordinates.
I'd imagined I could use one comma-delimited:
<plot-element>,
to assign the returned value of $f($1) to an array variable and thereby avoid calling $f() multiple times within the one plot command. When I could not discover a suitable syntax for doing so I capitulated and settled for calling $f($1) multiple times and added a conditional test (as shown above) to bypass the time-consuming algorithm whenever the $1 data value being passed to $f() has not changed since the last time $f() was called. This was done out of expedience but now I'd like to understand the gnuplot interpreter better and see if a more elegant solution can be found.
- Do you know of a legitimate syntax that enables (what hopefully the reader will agree is) intuitive/expected behavior from the pseudo-code I describe below?
specifically that plot-element:
local array x[7] = $f($1) ,
plot @inFile \
local array x[7] = $f($1) \
, using (x[3]) : (x[4]) : (x[5]) : (x[6]) : (x[7]) \
with sectors linecolor palette \
, using (x[3]+x[5]/2) : (x[4]-0.4) : 1 : (-fixT*( (x[3]+x[5]/3) + pi/2 ) ) : (x[7]) \
with labels nopoint center rotate variable textcolor palette font "Times,8" \
, '-' using 1:2:3:4:5 with sectors linecolor variable
0 0 2 @N 0
EOD
The intent being that array x[7] has scope local to just that one plot command and therefore $f($1) need be called only the once per data point in any data set.
Thank you for considering this gnuplot conundrum!
- NOTE: I currently use 2 elements of the returned array to skip over time-consuming parts of the function block code whenever
ARGV[1]andARGChave not changed since the last time the$f()was called. This is a hack I am prepared to live with if my other goal is not (yet!) possible. - FWIW: I did toy with having
$f()return a string resembling the "using" syntax: "using (azimuth) : (r) : (delTheta) : (delR) : (density)" with a view to substitution of that string variable as a macro via:@$f($1)style of de-referencing but that was frustratingly unsuccessful. That type of approach is alluded to in this Q&A. - For similar reasons expressed by the O.P. at this Q&A, I'd imagined I could use one comma-delimited:
<plot-element>,to assign the returned value of$f($1)to an array variable and thereby avoid calling$f($1)multiple times within the oneplotcommand. This is the solution path I wish to exhaust until I'm told it is not (yet!) possible.
using (x = $f($1), x[3]) : (x[4]) : (x[5]) : (x[6]) : (x[7])evaluates $f($1) and assigns the array result tox; butx[3]is returned tousingas the value to use first and subsequent references tox[n]draw upon the value of$f($1)evaluated once and assigned tox[].