
°

Yanaconda is Yet ANother Abridged
COding 'N' Development Approach

Why yet another macro language? Why not
use Python directly, as it is possible in YASARA plugins?
There are two simple reasons:
 Many users prefer not to use the graphical
interface, but type the commands
directly in the console to save time. In this case, every keystroke is
a precious
resource, and Yanaconda has been designed to minimize the number of
keystrokes
while maximizing the readability of the code.
So if you quickly want to color all CA
and CB atoms blue, you type:
Because the command above is not a valid
Python syntax, you would have to type:
ColorAtom("ca cb","blue")
In the first case, it takes 20
keystrokes, in the second case
33 (counting SHIFTs), that's 65% more. The quick way is possible
because Yanaconda is not case sensitive and the command
'ColorAtom' knows its argument types and does not expect quotes around
strings.
When writing a macro that will be used
again, you would invest more time and choose a more readable form of
the command, with the same result:
 Not everyone knows how to (or likes to) program in
Python, and Yanaconda
can be seen as a minimal common set of instructions that everyone
knowing at least
one other programming language can memorize in ten minutes. (If
Yanaconda is
your first 'programming language' it may take 30 minutes).
°

Yanaconda is a reinterpreted language

The only language the processor can
understand is machine code. The
lowlevel Assembly language is just a way to make machine code readable
for humans. Highlevel languages like C/C++ must be translated to
machine code by a compiler, or to an intermediate 'bytecode' that can
be executed by an interpreter (Python,Perl).
Yanaconda is one additional level
'higher'
(and slower, which is not an issue because virtually all of the time is
spent in YASARA commands anyway). The source code is reinterpreted
continuously and can modify itself using
'explicit evaluators' described below. This revival of 'selfmodifying
code' allows for surprising shortcuts that can increase readability and
efficiency at the same time.
°

Explicit evaluators modify the
source
code at run time

When reading Yanaconda source code,
there is one single golden rule:
EVERYTHING ENCLOSED IN PARENTHESES ( ) IS
EVALUATED AND REPLACED BY THE RESULT
Example:
Name = 'Yami' Print 'Hi I am (Name)!' Hi I am Yami!
And a more extreme example:
Name = 'Yami' Function = 'Print' Argument = 'Hi I am (Name)!' (Function) (Argument) Hi I am Yami!
In short, the pair of opening and
closing parentheses is called an
'explicit evaluator', because it explicitly forces the evaluation of an
expression at any location in the source code. The entire expression
including the parentheses is replaced by the value of the expression.
°

When writing Yanaconda macros, use
Python syntax highlighting

Much of
Yanaconda's syntax has been kept compatible with Python, so that you
can immediately use syntax highlighting in your favorite editor. It
helps to add the file extension for Yanaconda macros
'.mcr' to the editor settings. You can also use Python style comments
with a double cross
'#' for one line comments and triple quotes """ for multiline
comments.
°

The four datatypes are integer,
float,
weak string and strong string

Yanaconda knows four different
datatypes, which are described below.

°

Integers remember the number
of leading
zeroes

Integers are numbers without a
decimal point. Contrary to other programming languages, they can be
defined with leading zeroes and remember them.
Examples:
a = 5 b = 4003 c = 000 d = 000005
To wheat your appetite, here is an
example which takes away some things explained later, but illustrates
the point. Imagine you want to load 10 PDB files, named Model001 to
Model010.
As a C programmer, you would type:
char filename[9]; int i; for (i=1;i<=10;i++) { sprintf(filename,"Model%03d",i); LoadPDB(filename); }
As a Python programmer, you save a
lot and earn percents and a mysterious
'11':
for i in range(1,11): LoadPDB("Model%03d"%i)
As a Yanaconda programmer, your
life is easy:
for i=001 to 010 LoadPDB Model(i)
°

Floats remember their precision

Floats are numbers with a decimal
point and an optional exponent. If
you specify an exponent or just a dot without decimal digits,
calculations will be done at maximum precision. Otherwise the result
will be rounded to the number of digits after the comma.
Examples:

a = 5.000

A float with a precision of
three decimal digits 
b = 4e0

A float with maximum precision
(4*10^0 = 4) 
c = 3.

Just a dot without decimal
digits also gives maximum precision 
d = 2.5e3

A float with maximum precision
(2.5*10^3 = 2500) 
e = 7.345e4

Another float with maximum
precision (7.345*10^4 = 0.0007345) 
f = 0.0034

A float with a precision of
four decimal digits 

°

Weak strings are enclosed by
single
quotes

You already met some weak strings
in the section about explicit
evaluators. They are called weak because of two reasons:
 Explicit evaluators inside the string are
indeed evaluated.
 When a weak string is explicitly evaluated, it
loses the single quotes.
Example:
a = 2 b = 3 # Assign '5' to MyWeakString MyWeakString = '(a+b)' Print 'Result is (MyWeakString)' Result is 5
Note that the result is 5, not '5',
not (a+b) and not
'(a+b)'.
°

Strong strings are enclosed by
double
quotes

Strong strings are somehow
complementary to weak strings:
 Explicit evaluators inside the string are
ignored.
 When a strong string is explicitly evaluated,
it keeps the double quotes.
Example:
a = 2 b = 3 MyStrongString = "(a+b)" Print 'Result is (MyStrongString)' Result is "(a+b)"

°

The left operand defines the
datatype
of the result

It is easily possible to perform an
operation with two operands of different datatypes. In this case, the
result gets the datatype of the left operand.
Example:
a = 2 b = 1.7 # Result is a float Print (b+a) 3.7 # Result is an integer, 3.7 rounded to 4 Print (a+b) 4
This simple rule permits a large number
of useful applications:
pi = 3.14159265359 Print (0.00+pi) 3.14
 Convert from floats
to integers
pi = 3.14159265359 a = 0+pi Print (a) 3
 Convert to and from string
a = "2" b = 5+a Print (b) 7 a = 2 b = "5"+a Print (b) "52" a = 5 b = "2"*a Print (b) "22222"
Remember to be careful when writing more
complicated mathematical expressions:
 DEFINE FLOATS WITH AN EXPONENT TO GAIN MAXIMUM
PRECISION
 PUT THE INTEGERS ON THE RIGHT SIDE TO PREVENT THEM
FROM CONVERTING FLOATS
°

Yanaconda supports the usual
operators

Most programming languages share a common
set of operators. Some
differences become apparent if you use multiple operators in one
expression without explicitly ordering them using parentheses. Then
evaluation order depends on the predefined operator priority. The
operators you can use in Yanaconda are listed in the following
sections. Operators of the same priority are evaluated from left to
right.

°

The negation operator has the
maximum
priority
6: !, not

This operator switches true
(anything except 0) to false (0) and vice versa. You can use '!' or
'not', whichever you prefer.
a = 3 b = 0 Print (!a) 0 Print (not b) 1
°

Operators with priority 5: *,
/, //, %,
<<, >>

Here are some examples for the six
operators with the second highest priority. Note that the modulo
operator
'%' requires an integer on the left side. The '//' operator is mainly
known to Python programmers, it is a division with truncation of the
result's fractional part. The normal division operator
'/' rounds the result to the closest integer if the requested result
data type is an integer.
a = 2 b = 3. Print (a*b) 6 Print (b*a) 6.0000000000e0 Print (a/b) 1 Print (a//b) 0 Print (b/a) 1.5000000000e0 Print (a%b) 2 Print (b%a) Error  unsupported operator
The shift operators '<<' and
'>>' do bitwise binary shifts to the left or right, they require
an integer on the left side. A left shift corresponds to a
multiplication with
2, a right shift to a division by 2. That's why they have the same
priority as '*' and
'/'.
a = 2 b = 3.000 Print (a<<1) 4 Print (a<<b) 16 Print (a>>1) 1 Print (b>>a) Error  unsupported operator
°

Operators with priority 4: +, 

a = 2 b = 3.000 Print (a+b) 5 Print (b+a) 5.000
°

Operators with priority 3:
>, >=,
<=, <, ==, !=

All comparison operators have the
third lowest priority. They return
1 if the comparison is true, 0 otherwise. Note that '!=' stands for 'is
not equal to'.
a = 2 b = 3.000 Print (a>b) 0 Print (a<b) 1 Print (a==b) 0 Print (a!=b) 1
°

Operators with priority 2:
&, , ^

These operators do a bitwise 'and',
'or' and 'xor', there must be an
integer on the left side. They are rarely if ever needed in Yanaconda.
°

Operators with minimum
priority 1: and,
or

Logical operators are used most of
the time in if/else statements to combine the results of comparisons.
a = 2 b = 3 if a==1 or b==3 Print "Hello World!" Hello World!

°

Indentation defines the program flow
and must be a multiple of two spaces

Python
introduced a very smart concept which is taken over by Yanaconda:
instead of using explicit code block markers like braces
'{' and '}' in C/C++ or 'begin' and 'end' in Pascal, blocks of code
that belong together are identified by their indentation level. Taking
away the section about conditional execution below, here is an example:
a = 2 b = 3 if a==3 Print "A equals 3!" if b==3 Print "and B too!" else Print "but B does not" else Print "sorry, A does not equal 3" if b==3 Print "but therefore B does!" else Print "and neither does B" sorry, A does not equal 3 but therefore B does!
When compared to the language C, the
benefits are enormous: you have to type less, do not waste space with
braces, and do not spend your time searching where you forgot a brace.
However, as soon as you want to use code
written by someone else, it is payback time. Python programmers know
the nightmare: You receive a codesnippet by email, paste it into your
editor, save, run and crash. Then you spend your time hunting down
little indentation problems, because the original code was written with
a mixture of tabs and spaces, got additionally modified on its way
through the various email clients and is dead on arrival.
To keep these troubles away from
Yanaconda
users and promote the quick and easy exchange of macros, Yanaconda
insists that indentation is done with multiples of two spaces and no
tabs are used
(which is the standard Python convention anyway). If you like to use
the 'Tab' key, just configure your editor to replace each tab with two
spaces while typing. (Virtually any source code editor with syntax
highlighting can do that.) If you are very unhappy about that and would
prefer a different indentation style, be assured that most of the time,
you will not need any indentation at all, due to the simple nature of
Yanaconda macros.
°

Control the program flow with if,
elif
and else

An example
for conditional execution has been given above, the syntax is the
same as in Python, 'elif' is used instead of
'else if'. Note that you cannot continue on the same line after 'if',
'elif' or
'else', you always have to start a new (indented) line.
a = 2 if a==1 Print 'A equals 1!' elif a==2 Print 'A equals 2!' else Print 'A equals neither 1 nor 2!' A equals 2!
°

There are four types of loops

Equally important as conditional
execution is the ability to repeat a
set of instructions for a given number of cycles or while a condition
is true.

°

Loops can run over a range of
numbers:
for i
= X to Y step Z

Use a for loop to cycle
over a fixed range of numbers.
for i = 1 to 3 Print (i) 1 2 3 for i = 5 to 12 step 2 Print (i) 5 7 9 11 for i = 20.0 to 15.0 step 1.5 Print (i) 20.0 18.5 17.0 15.5
For testing purposes, you can of
course also type a loop directly into the console. Just make sure to
keep the indentation
(the first loop iteration will execute while you type) and close the
loop by typing a command without indentation:
>for i=1 to 3 > Print (i) 1 > Print (i*4) 4 >Print 'Done' 2 8 3 12 Done
°

Loops can run over a list: for
i in
X,Y,Z,..

If you have a fixed number of
elements that are either strings or nonsequential numbers, use this
form of the for loop. This syntax matches Python.
for i in 5,10,3,8 Print (i) 5 10 3 8 for text in 'Hi!','I am','Yami..' Print (text) Hi! I am Yami..
And you can also loop over the
content of a file:
for id in file /home/yasara/pdb_id.txt Clear LoadPDB (id) CountRes all
In the example above, the file
pdb_id.txt contains a list of PDB IDs to loop over. In this simple text
file, you can use either commas or linefeeds to separate the elements:
# Example for valid loopfile: # Line starting with '#' are ignored. # Using linefeeds to separate 1CRN 5TIM # Using commas to separate 1SOL, 1STY,1THV # By default, strings are weak strings, single quotes are not essential: '1RIS', '1RWT' # Double quotes are needed to specify strong strings: "1VII","1YAS" # Integers and floats are also allowed: 1,2,3 5.7, 1e60
°

Loops can run while an
expression is
true: while X and do .. while X

In addition to the Python syntax,
Yanaconda supports the Clike do
.. while X style. In the latter case, the loop is run at least once,
even if the expression at the end is false.
i = 3 while i<50 Print (i) i = i*2 3 6 12 24 48 i = 60 do Print (i) i = i*2 while i<50 60
°

Stop a loop with 'break'

Like C and Python, Yanaconda
supports the 'break' statement to stop a loop. In addition, it is
possible to specify the number of nested loops to stop right after the
'break'.
i = 0 while 1 Print (i) if i==5 break i = i+1 0 1 2 3 4 5
for i=1 to 3 for j=10 to 15 Print (i)(j) if j==12 break 2 110 111 112
°

Loop ahead with 'continue'

The 'continue' statement has also
been borrowed from C and Python. Again, you can specify the number of
the loop to continue with.
for i=1 to 3 for j=10 to 15 if j==12 continue 2 Print (i)(j) 110 111 210 211 310 311

°

Lists are emulated with explicit
evaluators

Having a list of something (strings,
numbers) can be very handy.
for i = 1 to 5 MyList(i) = i*10 for i = 5 to 1 Print (MyList(i)) 50 40 30 20 10
Note that lists are not a special
datatype but 'faked' using explicit
evaluators. The first for loop creates five variables named
'MyList1' to 'MyList5', and the second for loop simply prints
them out in reversed order.
If
you assign more than one value to a variable, it is assumed to be a
list, and the 'fake' variables Name1,Name2…NameN are created
automatically. You can document the fact that MyList is a list by
appending two parentheses.
MyList() = 4,7,8,9,5 for i in MyList Print (i) for i = 1 to 5 Print 'Element (i): (MyList(i))' Print 'Accessing list elements:' MyList(3) = MyList(3)+1 Print (MyList(3)) MyList3 = MyList3+1 Print (MyList3) 4 7 8 9 5 Element 1: 4 Element 2: 7 Element 3: 8 Element 4: 9 Element 5: 5 Accessing list elements: 9 10
To delete a list, use:
MyList()=0
This expression will set MyList1 to 0 and delete all other variables
with the same root name
'MyList'.
The same concept holds for
multidimensional lists, but care must be taken that the list indices do
not interfere, best by separating them with an underscore
'_':
for i=1 to 12 for j=1 to 12 wrongmatrix(i)(j)=i*j rightmatrix(i)_(j)=i*j
Why is the first matrix wrong? Simply
because the matrix elements
1,12 and 11,2 (like several others) map to the same variable name:
wrongmatrix112. The underscore makes sure that the indices stay
separated: rightmatrix1_12 and rightmatrix11_2 are indeed different
names.
If you know the number of columns and
rows in advance, you can use leading zeroes to avoid the underscore:
for i=01 to 12 for j=01 to 12 rightmatrix(i)(j)=i*j
In the above case, rightmatrix0112 and
rightmatrix1102 correctly map to different variable names.

°

The
'count' function determines the length of lists

As lists are just variables with
the same root name and a sequential number at the end, the length of a
list can be determined by counting the number of names that match a
certain pattern. This is done by the
'count' function:
MyList() = 4,8,5,2 for i = 1 to count MyList Print 'Element (i): (MyList(i))' Element 1: 4 Element 2: 8 Element 3: 5 Element 4: 2
If no variable name matches,
'count' returns 0 to indicate that the list is empty
/ does not exist.
°

The 'min', 'max', 'sum',
'mean',
'stddev' functions return the smallest, largest, sum, mean and standard
deviation of all list elements

These five functions scan all
variable names that match the given root
name and return the smallest, largest, summed up and average value,
respectively. The datatype of the result is either an integer or float,
depending on the list elements. The standard deviation is calculated
using the formula:
StdDev^2 = Sum((ElementXMean)^2) / Elements
Example for a simple list:
MyList() = 1,4,5,10,8,2 Print (count MyList) Print (min MyList) Print (max MyList) Print (sum MyList) Print (mean MyList) Print (stddev MyList) 6 5 10 20 3.33333333333333e+00

°

Yanaconda macros can access
predefined
variables

Some variables are predefined to make
life easier, they are just normal variables and can be overwritten.

View 
1 if the stage of your YASARA is at
least View, always true 
Model 
1 if the stage of your YASARA is at
least Model (true for Model, Dynamics, Structure), 0 otherwise 
Dynamics 
1 if the stage of your YASARA is at
least Dynamics (true for Dynamics, Structure), 0 otherwise 
Structure 
1 if the stage of your YASARA is at
least Structure (true for Structure only), 0 otherwise 
Twinset 
1 if you have the Twinset installed 
Movie 
1 if you are running YASARA Movie 
Windows 
1 if the operating system is Windows 
Linux 
1 if the operating system is Linux 
MacroDir 
Directory where the current macro
resides 
MacroTarget 
Target set for this macro with the
MacroTarget command 
Atoms 
Number of atoms in the soup, see
also Count 
Objects 
Number of objects in the soup , see
also Count 
FirstObj 
Number of first defined object, 0 if
no object defined 
LastObj 
Number of last defined object, 0 if
no object defined 
EnergyUnit 
Current EnergyUnit,
either 'kcal/mol' or 'kJ/mol' 
SpeedMax 
The current speed of the fastest
atom in the simulation in m/s 
Pi 
The value of Pi, 3.14159265359 
Pid 
The ID of the current process
(helpful if you create temporary files) 
LeftButton 
1 if the left mouse button is
currently pressed 
MiddleButton 
1 if the middle mouse button is
currently pressed 
RightButton 
1 if the right mouse button is
currently pressed 
FirstName 
Your first name, type Print
'Hi (FirstName)!' to greet yourself. 
LastName 
Your last name 
ScrSizeX 
The width of the YASARA window in
pixels 
ScrSizeY 
The height of the YASARA window in
pixels 
PixToA 
Conversion factor from pixels to
Ås 
EyeDis 
Distance between the eye and the
viewplane in Ås 

°

Yanaconda macros can include each
other

Sometimes a certain macro is needed at
more than one place. Instead of copying macros manually between files,
you can use the 'include' statement to let a macro include other macros:
# Solve an NMR structure # First fold it from the stretched out conformation include nmr_fold # Then refine it in vacuo include nmr_refinevac # And then in water include nmr_refinewat
 The 'include' statement does not have to be placed
in the first
column (YASARA will instead automatically indent the included file as
well).
 YASARA includes the other macros BEFORE running the
macro. As a consequence, the line numbers reported in case of errors
refer
to the complete macro, with all the others included.
°

Calls to built in functions can be
placed anywhere within an expression

Yanaconda supports a number of builtin
functions, mainly for doing math. These functions can appear anywhere
in an expression. If the function argument is itself an expression, you
must enclose it in parentheses. Remember to leave a space between the
function name and the opening parenthesis.
for i = 0 to 180 step 60 j = sqrt i k = cos (i) Print 'Sqrt of (i) = (j), Cos of (i) = (k)' Sqrt of 0 = 0.00000000000000e+00, Cos of 0 = 1.00000000000000e+00 Sqrt of 60 = 7.74596669241483e+00, Cos of 60 = 5.00000000000015e01 Sqrt of 120 = 1.09544511501033e+01, Cos of 120 = 4.99999999999969e01 Sqrt of 180 = 1.34164078649987e+01, Cos of 180 = 1.00000000000000e+00
Unlike C and Python, trigonometric
functions expect their arguments in normal degrees.
The following functions are available:

abs X 
Absolute value of X 
acos X 
Arc cosine of X, returned in degrees 
asin X 
Arc sine of X, returned in degrees 
atan X 
Arc tangent of X, returned in degrees 
cos X 
Cosine of X, X in degrees 
count X 
The number of occurances of
variables with root name X and different terminal numbers 
cube X 
Volume of a cube with length X
= X*X*X 
curt X 
Cubic root 
exp X 
e (the base of natural logarithms)
raised to the power X 
log X 
Natural logarithm of X 
log10 X 
Base10 logarithm of X 
max X 
The maximum value in list X
(all variables with root name X) 
mean X 
The mean value of list X
(all variables with root name X) 
min X 
The minimum value in list X
(all variables with root name X) 
onein X 
A random element in list X
(all variables with root name X) 
ord X 
The ASCII code of string X, summed
up if string contains more than one character 
rnd X 
A random number in the range [0..X[ 
round X 
X rounded to the closest integer 
sign X 
The sign of X, either 1, 0 or 1. 
sin X 
Sine of X, X in degrees 
sqr X 
Area of a square with length X = X*X 
sqrt X 
Square root 
stddev X 
The standard deviation of list X
(all variables with root name X) 
sum X 
The sum of all values in list X
(all variables with root name X) 
tan X 
Tangent of X, X in degrees 
trunc X 
The integer part of X, rounded
towards zero. 

°

Calls to YASARA commands must appear
one per line

The most important part of any macro are
the YASARA commands.
Yanaconda is merely used to guide the control flow and call YASARA
commands
with the right parameters. Almost every example in this section used
YASARA's
'Print' command to print results.
YASARA commands
know which arguments to expect. E.g. the DelAtom command expects a
selection. To save your time, selections are not enclosed by any quotes.
This will obviously delete all CA
(=Calpha) atoms. Now let's put the atom name in a variable:
Name = 'CA' DelAtom (Name)
Note that you must use an explicit
evaluator so that
(Name) is replaced with CA, otherwise YASARA would delete all atoms
named 'Name'. If you look at previous examples, you can see that all
Print commands that printed variables used explicit evaluators to
insert the content of the variable. Otherwise just its name would have
been printed.
You can of course also use variables for
more complicated selections, e.g. for saltbridges:
selection = 'Lys Atom NZ with distance < 4 from Asp Glu' ShowRes (selection) ColorRes (selection),blue
This brings us to the final golden rule
for Yanaconda programmers:
ALWAYS USE EXPLICIT EVALUATORS AROUND
YANACONDA EXPRESSIONS THAT APPEAR AS ARGUMENTS TO YASARA COMMANDS.
Some YASARA commands return values that
can be assigned to variables. This example stores the X/Y/Z coordinates
of atom
500 in three variables x,y and z:
If a command returns more results than
variables present, the additional return values will be lost. In this
case, the Y and Z coordinates are discarded:
It is also possible to put the return
values in a list by appending two parentheses to the variable name:
pos() = PosAtom 500 Print X=(pos(1)) Y=(pos(2)) Z=(pos(3))
This feature is especially useful to
store selections returned by the List command, e.g. the command
ColorAtom CA,Red can be expressed as:
selection() = ListAtom CA for atom in selection ColorAtom (atom),Red
If you want to know if a command returns
something, look at the examples given for the command.
