Is there a way to have procedures (or C-like functions) in Gnuplot? I need something really simple, just something like:
function func1()
{
var1 = "string1";
var2 = var1."string2";
return var2;
}
to make my gnuplot scripts a little bit more compact.
Gnuplot supports (simple) functions with arguments:
func1(x)=x."string2"
More complicated "inline" functions can be created if you're using gnuplot 4.4:
func1(x)=(var1=x, var2=var1."string2", var1.var2) #returns x.x."string2"
In this form, the last portion of the function is what is returned (var1.var2) and the statements are evaluated left to right.
If you want to have functions which accept no parameters, you can (often) use macros:
set macro
funcmacro='"string1"."string2"'
print #funcmacro
Yes. You can concatenate strings in gnuplot with something like
strcat(str1,str2) = sprintf("%s%s",str1,str2)
str3 = strcat("string1","string2"); print str3
The first line is the function definition, the second line is just an example of usage. You can read more in the "User-defined variables and functions" section of the gnuplot documentation (it is under the "Expressions" section; you may have trouble searching for the string 'user-defined' in the pdf because of the 'fi' character generated by LaTeX).
You might want to consider looking at the Pyxplot plotting package http://pyxplot.org.uk, which has very similar syntax to gnuplot (albeit cleaned up), but which also has a lot of the features of a scripting language. It has subroutines, which should do exactly what you're asking for.
Related
You can define a function to pass its keyword arguments to inner functions like this:
function example(data;xcol,ycol,kwargs...)
DoSomething(; spec=:EX, x=xcol, y=ycol, kwargs...)
end
Now, the function DoSomething accepts many arguments, such as color. This works for functions, but I'd like to do this with a macro from VegaLite.jl:
function example(data;xcol,ycol,kwargs...)
#vlplot(data=data,mark=:point, x=xcol, y=ycol,kwargs...)
end
example(df,xcol=:Miles_per_Gallon, ycol=:Horsepower, color=:Origin)
Note that the code above does not work.
So the answer here is... it's tricky. And in fact, in general, this isn't possible unless the macro itself supports it.
See, macros do their transformations at parse time — and often will exploit what you've actually written to mean something different and special. For example, #vlplot will specially handle and support JSON-like {} syntaxes. These aren't valid Julia code and can't be passed to a function you define (like example)!
Now, it's tempting to see this and think, ok, let's make that outer example thing into a macro, too! But it's not that easy. I'm not sure it's possible to have a general answer that will always pass the arguments appropriately and get the hygiene correct. I'm pretty sure you need to know something about how the macro you're calling handles its arguments.
you need to add ; before kwargs to signal they are kwargs not positional arguments e.g.:
DoSomething(;spec=:EX, x=xcol, y=ycol, kwargs...)
(this is the answer for DoSomething being a function as this was the original formulation of the question)
I have a function where I want to solve for many variables separately, do I have to write down the function every time in terms of the other variable?
x,xG,xR
y = e.^tan(x.^2)+cos.^2(x);
yG = e.^tan(xG.^2)+cos.^2(xG);
First you cannot write an expression like cos.^2(x). If x is a single variable (ie x=pi) you could write either cos(x)^2 or cos(x^2). If x is a vector (a column vector might be x=[3;4;pi] and a row vector might be x=[3,4,pi], then you might write cos(x).^2 or cos(x.^2). The role of the period (.) in octave is explained here: https://octave.org/doc/v4.0.3/Arithmetic-Ops.html
Another issue has to do with understanding the difference between an expression: x=e^tanh(y); and a function. The later is a separate chunk of code that can be invoked from anywhere in your program.
Consider this simple example
1;
function y=myfunc(x)
y=exp(tanh(x));
endfunction
## main program
xxx=pi/3;
yyy=myfunc(xxx);
printf('%7.3f %7.3f\n',xxx,yyy)
y=exp(tanh(pi/3))
comments: The '1' in the first line tells Octave that there is more to the script than just the following function: the main program has to be interpreted as well. The function line specifies that inside the function, the input will be called x and the output y, so when my function is called from main, the input is xxx(=pi/2) and the output is yyy. The last line in this tiny script is an expression that does the same thing as the function. Note that since I didn't include a semi-colon at the end of that line the result is printed out
I suggest you play with this for a while, then if you have more questions, ask them in a new question.
I wonder if it is right semantics to have a variable as an argument, something like this:
proc p1 {$aa} {}
I tried it on tclsh, there is no complaint, but the following experiment fails:
% set aa bb
bb
% set bb 200
200
% proc p1 {$aa} {puts $bb}
% p1 bb
can't read "bb": no such variable
Do you see what is wrong?
[UPDATE - after seeing Peter's answer]
I know the upvar semantic, thanks.
My main curiosity is still around using variable as proc argument. I know it is not common, but just cannot help musing what it really can do if the language syntax allows it.
Yes, your upvar example is exactly what I want to explore using a variable as proc argument, but my exploration so far tells me, really, there is no way we can do this because "$" is interpreted as a plain char.
Do debunk me please if I am wrong.
Tcl does not support reference arguments as such: the usual pass-by-reference semantics is too static for Tcl. Instead, the logic of the command can, by use of upvar, dynamically create reference parameters including indirect reference parameters and calculated reference parameters, and also retarget the local name to another external variable. The upvar mechanism may look ungainly, but is very powerful indeed.
(The (edited) remains of my original answer follows:)
The usual idiom for doing this is
proc p varName {
upvar 1 $varName var
puts $var
}
The upvar command looks into another stack frame (in this case 1, which is the caller's stack frame) and makes a variable named $varName (i.e. the variable's name is the value of varName) in that stack frame and a variable named "var" in the command's stack frame refer to the same data object.
I won't explain this further since this is not useful to the asker.
Documentation: proc, puts, upvar
There are cases where it makes sense for the arguments in a procedure creation call to be supplied from a variable. The main example is where you are creating procedures dynamically, calculating the arguments you want to use as you go along.
That's actually a use-case that isn't done very frequently! It's not particularly easy to use well. But I have done it. (OK, that's a method call, but the syntax of formal arguments is shared.)
The main reason that the capability is there is that it's part of Tcl's general syntax. Tcl tries very hard to not have special cases in how it parses things (other than in how a command parses the strings passed into it) and this includes in things that would be very special cases in the enormous majority of other programming languages, such as formal parameter lists to procedures. In Tcl, these are just ordinary values and can be produced using any technique that gives ordinary values.
The usual thing with putting them in braces is just how you do it reliably and is easy to teach. It's also overwhelmingly what people want to do.
All this is independent of the facts that Tcl's commands (including its procedures) can handle variable numbers of arguments (check out the special args parameter and how to specify default values) and that $aa is a legal (but strange) name for a local variable.
If I want to introduce some new expression operator, e.g. "%%" to deal with some custom data structure, I will need to re-define "expr" command to recognize it. Is this right?
Basically TCL extension is at the command level, there is no interface to directly add new operator.
Could you confirm my understanding?
The operators in Tcl are implemented directly in Tcl's bytecode engine; you can't extend them or modify their semantics. Not without editing the expression parser (written in C) or the bytecode engine itself (a compiler and an execution engine, both written in C). Extending this part of Tcl directly is rather difficult. (You're looking at tclParseExpr.c, tclCompExpr.c and tclExecute.c at least to make things work, and quite possibly the other tclParse* and tclComp* files too, as well as the assembler and maybe the disassembler. Not to be taken on lightly!)
However…
You can write your own command that interprets a string as anything you want, including an expression involving whatever new operators you desire. This is what VecTcl does. Under the covers, it converts its expression language into calls to Tcl commands that implement the various operators (some of which are implemented in C, but as a normal extension package, so that's nothing unusual).
Effectively, it converts an invoke of one of its expressions:
vexpr {3*x}
into something a bit like this:
numarray::* 3 [set x]
which it then can execute using Tcl's bytecode engine (frankly, a trivial execution, but it makes more sense in more complex examples; see the VecTcl tutorial, which is a bit too long to reproduce here).
The mathop manual page calls out explicitly that while you can access the expr operators using the ::tcl::mathop namespace you cannot add new ones nor redefine the existing ones there. You can add you expr functions using the tcl::mathfunc namespace as documented in the expr man page so if a function will do that is the simplest method to do what you want.
Otherwise you could intercept the expr command itself. If you rename the expr command and define your own replacement you can do some expression parsing and replace your custom operator with a function call or pass the expression on to the real implementation. Below is a trivial example.
rename expr _expr
proc expr {args} {puts "called expr $args"; _expr {*}$args}
In short, your understanding is correct. You cannot inject new operators into the expr expression parser.
how can i add some kind of help to the user defined functions in TCL
Supposing if i have a function called runtest {ip_address test_time},
How to describe what the test or procedure is about in the TCL_shell?
How can i specify the information to the user, if he types in function_name --help in the TCL shell the user should be able to know what the function does and what exactly are the parameters.
how can i do this?
While it is true that it is not part of the language, it is fairly easy to implement something that adds this functionality to pre-existing functions. The only caveat being that the function then cannot take the string --help as a valid argument since that argument will trigger the feature.
Here's one simple implementation:
# Lets call the feature "document". As in, add documentation:
proc document {procname text} {
rename $procname __$procname
proc $procname args [string map [list %TEXT% $text %PROC% $procname] {
if {$args == "--help"} {
puts {%TEXT%}
} else {
set script [linsert $args 0 __%PROC%]
return [uplevel 1 $script]
}
}]
}
What this does is to override the function (by renaming and then declaring another function of the same name) and see if the function is called with the argument --help. If it is it prints the documentation otherwise it executes the original function. Just be careful not to call this twice on the same function (it can be modified for it to work though).
So you can do things like:
proc foo {} {puts 2}
document foo {Prints the number 2.}
Now if you call:
foo --help
and it would output:
Prints the number 2.
You don't have to touch the existing procedures:
proc help {procname} {
puts $::helptext($procname)
}
proc addhelp {procname text} {
set ::helptext($procname) $text
}
addhelp foo "this is the help text for procedure foo"
help foo
Without redefining the proc command, you cannot. Ie, that functionality is not built into the language, but would be possible to add if you so wished.
I will note that adding the capability yourself, while possible, is probably beyond the difficulty where it's worth doing, especially for someone that isn't intimately familiar with the language. That being said, you can check the tclers wiki for a preexisting implementation.
I tend to prefer to put help in a separate file (e.g., as HTML) which lets me browse it in another window. There are so many ways you can do that while still keeping the docs with the code, such as through doxygen.
There are also a number of ways of doing interactive documentation, several of which are described in the Tcler's Wiki; it would seem to me that some of the techniques mentioned on that page (together with #slebetman's answer) would give you what you wanted. (I think it would be easier to have a separate help command as that would avoid having the help syntax interfere with the command, but that's your call.)