The current behaviour may very well be by design however, the current behaviour seems counter-intuitive to me. From the IF command description in the manual:
This version of gnuplot supports block-structured if/else statements.
Now a multi-line clause may be enclosed in curly brackets.
The same behaviour is observed within a main script block and also within a function block so it appears to be a feature of any { .. } delimited, multiple line compound statement (a.k.a. multi-line clause) associated with an IF/ELSE statement.
It seems counter-intuitive that a string that is (apparently) defined on some "line" before it is used alongside the de-reference token, "@", should generate a warning: "<stringvar> is not a string variable" </stringvar>
To be fair, the man page regarding "Substitution of string variables as macros" does allude to this via two sentences:
Macro expansion is handled as the very first thing the interpreter does when looking at a new line of commands and is only done once.
Macro expansion inside a bracketed iteration occurs before the loop is executed;
Either of these might be interpreted as also applying to a multi-line clause (compound statement) associated with an IF/ELSE command. It seems to me that if a block-structured IF/ELSE statements are to be supported then commands on separate lines of a multi-line clause ought to be interpreted separately and therefore benefit from substitution of a previously defined string variable as a macro.
## IF/ELSE compound statement treated as one line - affects string expansion as macro using @ token
## (gnuplot v6 rc1 on Windows 11)
##
## To experience each bug uncomment that/those script line(s) that has/have just a single hash '#'.
##
##(5) a compound statement associated with IF/ELSE is treated as one line
##(5a) this causes a string defined apparently before a plot command to fail to dereference when using "@string" for macro expansion
##(5c) error messages also refere to the line number of the IF/ELSE statement rather than the line number within the compound {..} statement
##(5d) the behaviour is the same within the main script block or within a function block
function $yourPlot(strSource,sizeFont) << _EOFD
local ARG0 = "$yourPlot" # hack
set title strSource." - variable color and orientation in plotstyle 'with labels'" offset 0,-2
## a compound statement associated with IF/ELSE is treated as one line so string dereferencing
## (i.e. string expansion as a macro) fails unless string is defined before the IF/ELSE
str_earlyFont = sprintf("\", %d\"", sizeFont)
#str_lateFont = sprintf("\"Times,%d\"", sizeFont)
if (sizeFont) {
str_lateFont = sprintf("\"Times,%d\"", sizeFont)
plot @strSource using 1:1:2:3:0 with labels rotate variable tc variable font @str_lateFont
}
else {
plot @strSource using 1:1:2:3:0 with labels rotate variable tc variable font @str_earlyFont
}
return sprintf("function, %s, completed; with %d arguments", ARG0, ARGC)
_EOFD
##
## Additional data columns can be used to hold text rotation or color
## for plot style "with labels"
##
demo = 1
$DataEarly <<EOD
1 one -30
2 two -60
3 three -90
4 four -120
5 five -150
6 six -180
7 seven -210
8 eight -240
9 nine -270
10 ten -300
11 eleven -330
12 twelve -360
EOD
$DataLate <<EOD
1 one -30
2 two -60
3 three -90
4 four -120
5 five -150
6 six -180
7 seven -210
8 eight -240
9 nine -270
10 ten -300
11 eleven -330
12 twelve -360
EOD
set angle degrees
unset key
set title "variable color and orientation in plotstyle 'with labels'" offset 0,-2
set xrange [0:13]
set yrange [0:13]
set xtics 1,1,12 nomirror
set ytics 1,1,12 nomirror
set border 3
printerr $yourPlot("$DataEarly",0)
pause mouse close
## a compound statement associated with IF/ELSE is treated as one line so string dereferencing
## (i.e. string expansion as a macro) fails unless string is defined before the IF/ELSE
string_earlyFont = "\"Times,18\""
#string_lateFont = "\"Times,22\""
if (demo) {
set title "EARLY - variable color and orientation in plotstyle 'with labels'" offset 0,-2
plot $DataEarly using 1:1:2:3:0 with labels rotate variable tc variable font @string_earlyFont
pause mouse close
set title "LATE - variable color and orientation in plotstyle 'with labels'" offset 0,-2
## a string defined within an IF/ELSE compound statement cannot be dereferenced within the same compound statement
string_lateFont = "\"Times,10\""
plot $DataLate using 1:1:2:3:0 with labels rotate variable tc variable font @string_lateFont
pause mouse close
}
printerr $yourPlot("$DataLate",16)
pause mouse close
The implementation of string macros predates the introduction of bracketed clauses by at least a decade. It dates back to gnuplot version 4.2 (2007). In retrospect I don't think introduction of macros was a great idea, but that's water under the bridge. So much has been added to the program since then to support the use of string variables in expressions, function parameters, etc, that very few cases remain where the use of a string macro is necessary or preferred.
What exactly are you trying to do? I don't see anything in your script that explains why you are using the @ operator at all. For example where you have
the macro expansion is pointless. Is there a reason not to use the string directly?
That works in a bracketed clause with no problem.
I am new to gnuplot so I don't have the benefit of historical hindsight.
Yes, that script was necessarily dumbed down to only demonstrate a handful of error types that I wanted to report.
Where you read
if (demo) {I was originally testing an integer variable (not even a string!) for a non-zero value; and then, inside the if { }-clause, was using that non-zero value as a font-size to construct a"font, size"string to use after thefontkeyword.If the (integer) value was 0 then I would call a version of
plotthat does not have thewith labelsstyle.I don't explain my proclivity for the @ operator (string macro). My reply below explains how that preference came about.
In hindsight, the string macro example (using
font "<name>{,<size>}") that I ran with to illustrate the IF-related bug was not a good one because it turns out that string expansion into a command line macro can be easily avoided .. and replaced by a plain old string variable.The same cannot be said for the many "with <style>" color options that make reference to any one of "colorname" or <colorspec> or <n>.
Color confusion is all that I have come across so far.
In that confusion, I wrongly tarred
font "<name>{,<size>}"with the same brush. My bad!Prompted by this remark I endeavoured to eliminate from recent scripts as many instances of
@strVaras I could;replacing them by just a plain old
strVarreference. In most cases this was easy enough to do.So I really do take your point to heart.
The remaining problematic cases involved the interpreter throwing the error: "colorspec option not recognized"
This comes about when the string value is any of those described in numbered items 2 thru 6 below.
I think that the versatility of using a string variable as a command line macro (string macro) lies in this very powerful sentence, highlighted in bold below.
Take any of the bold cases alluded to earlier:
... {linecolor | lc} {"colorname" | <colorspec> | <n>}
... {textcolor | tc} {<colorspec> | {linetype | lt} <n>}
... {fillcolor | fc} {<colorspec> | linetype <n> | linestyle <n>}
within a plot-command that specifies a with-style that allows for one or more of these color options.
strVar = "7"(or the integerintVar = 7) is used in place of <n> the color corresponding to linetype 7 in thetest termoutput is applied to either line or text or fill. This is good.strVar = "blue"is used the expected color is not applied .. even when the strVar is expanded using a string macro (i.e.@strVar).strVar = "\"blue\""but once again this does not behave for a plain old string .. unless the strVar is expanded using a string macro.strVar = "palette"(orstrVar = "palette z") is used the variable color based on the last column of data is not applied .. unless the strVar is expanded using a string macro.strVar = "variable"is used the variable color based on the last column of data is not applied .. unless the strVar is expanded using a string macro.strVar = "rgbcolor variable"is used the variable color based on the last column of data is not applied .. unless the strVar is expanded using a string macro.I have several 2 or 3 line scripts to demonstrate each of the above anomalies but am inclined to hold off from sharing all of that here since it really has nothing to do with the IF statement issue being addressed.
Instead I propose to do so as a separate bug report that addresses just that topic of apparent inconsistency of handling colorspec strings.
In cases 2 thru 6 it is almost as though palette, variable, "rgbcolor variable" and color-name are handled as a lexical keyword.
The interpreter appears to prefer to see that particular string value expanded as a string macro,
i.e. expanded before before parsing for lexical elements.
... for a newcomer to the tool this all appears quite confusing.
Discovering the "method in the madness" comes with experience, I suppose.
In the interim human nature is to utilize the first working syntax that gets done whatever is the immediate task at hand.
With more experience using gnuplot I suspect I will learn of alternative ways (using string variables in expressions, function parameters, etc.) of achieving the equivalent capability of a string macro.
I suspect that
eval stringwill emerge as a useful tool in that endeavor.For now, I tend to utilize the string macro out of expedience ... or perhaps impatience!
The
@stringexpansion (string macro) method has high utility because it is a more elemental/atomic version of theeval longer_stringfeature -which I understand expects to be first evaluated and then parsed/handled as one complete command rather than as just one small portion of a command.
That is exactly correct. These are lexical elements rather than string variables. And that was indeed the original reason for the introduction of macro expansion, because back in the day there were many fewer places where a string variable was accepted by the parser. There may well be exceptions (corrections welcome!) but in theory any place in the documentation that defines the syntax of a command will show lexical elements as regular text and command tokens that may be provided as variables or expressions in angle brackets or quotes. For example, from "help colorspec"
[continued]
Specifically with regard to the use of macros to expand color names. Yes - this was a point that has caused confusion before. The color names were implemented as lexical elements rather strings. To be fair, they were introduced in version 4.0 before string variables even existed as an alternative.
To mitigate this limitation, gnuplot version 6 introduces a function rgbcolor() that accepts the color name as a string and returns the hexadecimal representation of that color as an integer. So the following is now possible:
We'll see whether this reduces confusion or increases it :-).