The
Programming
Language
Version 1.6.2.0
Contents
Introduction
The Nytril Language
..............................................................................................................................
5
Basic Syntax
..........................................................................................................................................
6
Create a new project
............................................................................................................................
8
Revision = {Properties + Elements}
.......................................................................................................
9
Functions
............................................................................................................................................
13
The 'each' operator
.............................................................................................................................
16
Namespaces
........................................................................................................................................
17
Numbers
.............................................................................................................................................
19
Strings
.................................................................................................................................................
21
Percentages
........................................................................................................................................
22
Dates
...................................................................................................................................................
23
Units
....................................................................................................................................................
24
Currency
.............................................................................................................................................
26
Arrays
..................................................................................................................................................
26
Ranges
................................................................................................................................................
29
Classes and Objects
............................................................................................................................
30
Formatting
Boxes
..................................................................................................................................................
33
Colors and Fills
....................................................................................................................................
35
Shapes
.................................................................................................................................................
39
Transforms
..........................................................................................................................................
46
Charts
..................................................................................................................................................
50
Tables
..................................................................................................................................................
57
Trees
...................................................................................................................................................
58
Creating a Document
..........................................................................................................................
62
Formatting Properties
........................................................................................................................
63
Number Formatting
............................................................................................................................
67
Math Formatting
................................................................................................................................
71
Paragraph Formatting
.........................................................................................................................
77
Image Formatting
...............................................................................................................................
83
Hyperlinks and Tips
.............................................................................................................................
88
Mathematics
User defined symbols
.........................................................................................................................
91
Algebra
................................................................................................................................................
91
Statistics
..............................................................................................................................................
94
Vectors
................................................................................................................................................
98
Matrices
..............................................................................................................................................
99
Automatic Equation Typesetting
......................................................................................................
102
Local Resources
Processes
..........................................................................................................................................
103
File System
........................................................................................................................................
103
Genetics
Bases
.................................................................................................................................................
107
Proteins
.............................................................................................................................................
110
Mutations
.........................................................................................................................................
111
Staining
.............................................................................................................................................
112
Page 5 of
114
Introduction
The Nytril Language
Nytril is a high-level, general purpose programming language. The standard output of a Nytril program is one
or more typeset documents that can be published. This Tutorial document is written entirely in Nytril.
Nytril has a 'C' style, with insignificant white space, strings in double-quotes, expressions separated by a
semi-colon (;), and scope enclosed by curly braces {}. It uses all but one of the standard C operators and flow
statements ('mod' is used for integer modulus instead of %). It supports both dynamic and static typing or a mix
of the two. Namespaces can be created and used to organize symbols. It is an object oriented language with
classes, single-inheritance, virtual functions and templates. Memory is managed, with automatic garbage
collection.
Nytril contains built-in support for creating complex typeset documents, including alignments, tables, charts,
drawings, and complex math layout, in the spirit of
LaT
E
X
. Nytril is not a markup language like HTML or
Markdown, but the grammar has a unique property called 'affinity' that allows the fluid mixing of calculations
and text with a minimum of operators and escapes. Because it is a conventional programming language, Nytril
allows for arbitrarily complex calculations to be performed with the usual mix of classes and methods, and then
inserted inline with the text with minimal punctuation.
Design Philosophy
A guiding principle of Nytril development is the DRY principle in programming (i.e. Don't Repeat Yourself). To
make a large number of similar documents, without repeating information, the data and text must be separated
from the style and the organization of the documents themselves. In this pattern, the documents are only a
temporary representation of the text and data, and they can be discarded and rebuilt from source automatically,
in the same way that an executable program can be rebuilt from source. When this source changes, the entire
corpus of documents is rebuilt from scratch, which guarantees that every document is always up to date.
By combining the best aspects of programming, markup and data storage languages, Nytril allows technical
document authors, engineers and scientists to build documents that contain embedded data and calculations
quickly and easily. This can be as simple as a quick "what-if" calculation that fits on a sheet of paper or it can be
much more advanced, like technical one-sheets for every item in an inventory of products, from a set of product
facts and narrative.
Nytril source files are UTF-8 text files compatible with Git, and several authors can collaborate on different
parts of the corpus of documents, in the same way that they would collaborate on different parts of a large
software project. Raw information can be stored in Nytril source files in a structured way, minimizing the need
for data to be stored in different formats like JSON and XML. All changes to data and style are tracked by source
control in the same way.
Portability
Nytril is portable across operating systems and CPU architectures. Currently Nytril runs on computers running
Windows 10-11 and MacOS 13 and later (x64 and M-series). The compiler, runtime library and math functions
are identical on all platforms. Typesetting layout may differ marginally on different platforms due to the use of
different underlying graphics frameworks.
The compiler
Nytril is a compiled language and the code for an entire nytril program is compiled before any of the
Introduction
Page 6 of
114
statements are executed. The program is compiled at project load and in the background as the programmer
types. The compiled program resides in memory and is discarded and rebuilt in the background each time the
program is opened or changed. The compile time for a program is usually less than one second.
Nytril has a 2-pass compiler. Pass 1 gathers any included files and libraries and then builds namespaces and
class definitions. Pass 2 compiles global and class functions. Two passes allow the programmer to reference
classes and variables before they are declared in code, as in modern C++ variants like C# and Typescript. Classes
and member functions are defined together in one scope, in a single source file.
There are no 'Project Files' in Nytril. Instead, a project's functionality is determined entirely by its main source
file. The compiler simply follows the chain of included files starting with the main file, with redundant include
files being ignored. All symbols are visible to every included file, unless they are marked private.
There is not a single entry point for a Nytril program (i.e. no
main()
function). Once compiled, various parts of
the program can run when called. This is usually in the form of producing typeset output. For instance, an object
can override methods to show itself in a document or a popup tip.
Each program should include a Main.Documents collection that lists one or more document objects. These are
the documents that are available for the program to view on-screen or publish.
A program may also include a Main.Configurations collection. This is a list of variations of the whole program
that the programmer wishes to build for publication. Only one of these is active at a time, and the programmer
may selectively define a namespace for certain configuration properties.
readonly
namespace
Lang
if
(Language
==
Languages
.
English) {
Hello
=
"Hello"
;
}
readonly
namespace
Lang
if
(Language
==
Languages
.
Spanish) {
Hello
=
"Hola"
;
}
readonly
Greeting
=
Lang
.
Hello;
Nytril supports compiling and publishing alternate configurations for different languages, measurment units
and paper sizes. This provides a way to create a set of documents for every reader, without repeating text or
data.
Configurations
You can conditionally build your program with the the Configuration feature. Use Configurations to create
several versions of the same documents that have different global properties such as style, paper size,
measurement units. language and culture. This works directly with the publishing feature, to present each
viewer with a document that is customized for their preferences.
Publishing
Once you have created a set of documents, you can publish all documents, in all configurations in a variety of
output formats in one step. The community edition supports limited publishing to a local drive. The professional
edition supports publishing locally and online in one step. When viewed online, the viewer is presented with a
unique 'sliding-pane' interface that allows them to move easily between documents, make bookmarks, and
share content with others. The presentation feature allows the user to present a document as an online
slideshow.
Basic Syntax
Nytril syntax is broadly similar to 'C' style languages like C#, Java and TypeScript. Literal strings are
The Nytril
®
Programming Language
Page 7 of
114
delimited by double quotation marks and have a standard syntax for escape characters.
HelloWorld
=
Span
{
"Hello World"
;
"Line\nFeed"
;
"\tTab"
;
" Quotes \"\" are escaped"
;
};
Hello WorldLine
Feed
Tab Quotes "" are escaped
Outside of quoted text, white space, including newlines and indentation, has no effect on the code.
This tutorial and the included examples use a modified K&R bracing style, but this is a matter of
personal taste.
Spacing
=
Span
{
"White space"
;
/* and comments */
" between "
;
"expressions has no effect. "
;
// Neither do single-line comments
};
White space between expressions has no effect.
Nytril is a two-pass compiler. The first pass gathers up namespace, class and function definitions. The
second pass compiles the bodies of functions. This means that you can reference a function or variable
in a namspace or class before it is defined. This makes it simple to move and reorganize code.
Variable2
=
Variable1
;
Variable1
=
"A string"
;
A string
To create complex formatted text in an easy way, Nytril introduces the affinity operator. In most
programming languages, two operands must be seperated by a binary operator or else there is a
syntax error. In Nytril, if the compiler encounters two operands without a binary operator between
them, it inserts an invisible binary 'affinity' operator and continues without error. At runtime, the type
of the two operands is assessed and if an affinity exists between the two types, the operation is
executed. If there is no affinity between the types, there is a runtime error. The affinity action should
be intuitive, but you can use an explicit binary operator if you find that it makes the code clearer.
Affinity
=
Block
{
Paragraph
{
"Line"
;
Bold
};
// + affinity between format objects and revisions
"1"
2;
// + affinity between strings and other objects
"123"
"abc"
;
// + affinity
3
meters
;
// There is a * affinity between numbers and units
};
Line
12
123abc
3 meters
Introduction
Page 8 of
114
Create a new project
Like all compiled languages, Nytril reads source code stored in plain-text files stored on your computer. The
source code is Unicode, and files are saved in the UTF8 format (unix style \n line endings, without a
byte-order-mark). This makes them interchangeable between Windows, Mac and Linux systems. Nytril works
well with Git and other source-control systems and some Git repository operations are built-in to the IDE and
can be accessed through the
Git
menu.
Nytril has a native source editor with syntax highlighting and multi-level undo/redo, but source files can be
edited with any plain-text editor. Each time the Nytril IDE is brought into focus, the opened source files are
checked and reloaded if they have changed.
Nytril does not produce an executable file (like an .exe or .app file). Instead, the code is compiled into memory
in the background any time the code changes. When you exit Nytril there are no residual or temporary files.
When you open Nytril, the last project will load, compile and run automatically.
The typical output of a Nytril program is one or more typeset documents. Most simple programs contain just
one document, but it is easy to create projects that can generate dozens of different documents. To keep things
simple, we will focus on creating a program with a single document.
To make a new program, you must first create a new project and set the path of the 'main' source file.
•
Select the menu
File..New..Project
•
Double-click on a project template.
•
Specify a name for your project.
•
Select OK.
You should see the following on the screen:
Start from scratch
Your project settings are saved automatically and this new project will now be listed under the
Project
menu.
You can make changes to the code, and select
Build..Refresh documents
to update the document. When you
switch projects using the
Project
menu, the previous settings and tabs will be restored, and the project will
rebuilt and refreshed automatically.
A key feature of Nytril is that text and figures in the Document can be traced back to source code easily. Hold
down the control-key and click on the text in any document, including this one. The IDE will take you to the
immediate antecedant of that text in the code. That is, the expression that gave rise to that content. Usually this
means a literal string in quotes, but sometimes it can mean a number, date or even an operator like a '+' sign.
Hold down the control and shift key together, and hover over any part of the document. You will see the
typesetting layout lines that Nytril uses to align text and figures.
A Nytril project is defined entirely by its main source file. As this file is compiled, every other source file will be
added to the project by any
include
statements in the main file, and in turn, by any of the included source files.
There are no separate project files in Nytril, as there are in other development environments. Instead, all
repository and project settings are stored in a single
settings.ini
file on your system. This file contains the
repository and project settings for you on your system, and is not shared in source control.
The Nytril
®
Programming Language
Page 9 of
114
Revision = {Properties + Elements}
Revisions are the backbone of coding in Nytril. A revision is a collecion of properties and elements inside curly
braces {} that are separated by semi-colons (;}.
A property is the combination of a field name, a colon (:) and a compatible value.
BigText
=
TextHeight
:
16pt;
// A single property
An element is any other expression, including variables and values returned from function calls,
separated by a ';'. The properties and elements of a revision are computed at runtime, so a revision
"executes" just like a scope in a function.
RevisionWithElements
=
{1; 1
+
2;
Math
.
Sqrt
(4
+
1)};
RevisedBlock
=
Block
RevisionWithElements
;
// Format and Revision joined by affinity
1
3
2.23606797749979
You 'apply' a revision to a formatting object to give it content and properties.
Elements
are placed in a
revision in the order that they are encountered in code.
Properties
, on the other hand, can appear
anywhere inside a revision and have the same effect. In other words, placing the property before or
after any element (or another property) makes no difference. In the code below, the TextColor
property is placed after the 'Text' element, but it still affects the entire revision.
Revision
=
{
"Text"
;
// Element
TextColor
:
Colors
.
Red
;
// Property
4
*
(1
+
2);
// Element
};
Text
12
A revision acts on the format object to its left, without modifying it. In the code below, a Span is
revised by an inline revision - the lines of code between curly braces {}. It is critical to understand that
although this example revision comprises several lines of code, it is a single revision object. This
revision object is then applied to the Span to add content.
FirstSum
=
Span
{
// Inline revision defined over the next 10 lines of code
var
x
;
// Variable declaration (not added)
x
=
9;
// Variable assignment (not added)
++
x
;
// Increment variable (not added)
x
+=
2;
// Increment/assignment (not added)
// White space (not added)
null
;
// null (not added)
x
+
5;
// Expression (added)
" is the sum of 5 + "
;
// Constant (added)
x
;
// Variable (added)
}
// End of revision
Introduction
Page 10 of
114
;
// End of expression
17 is the sum of 5 + 12
Each single expression (separated by ';') inside the curly braces '{}' is evaluated, and then added to the revision.
But there are two important exceptions. The following types of expressions (determined at runtime) are NOT
added to a revision:
•
The value
null
, whether literal or as a return value from a function.
•
A variable declaration / assignment expression.
The latter comes in handy when you need to create 'helper' variables inside a revision to do calculations or make
the code easier to understand.
Revisions can be added together to create a new revision that combines the elements and properties
of both (in left-right order). It is important to remember that adding revisions has no effect on the
revisions being added. In the code below the previous revised span gets some text added at the end.
NextSum
=
FirstSum
{
// Add old revision to new revision in {}
", and then some. "
;
// New element
};
17 is the sum of 5 + 12, and then some.
A revision can contain properties as well as elements. Here the previous span is revised to change its
formatting properties.
FormattedSpan
=
NextSum
{
BigText
;
// References to property variables work the same as inline properties
TextColor
:
Colors
.
Red
;
};
17 is the sum of 5 + 12, and then some.
A revision can also revise existing properties. Again, this has no effect on the original, but instead
creates a new revision that substitutes the properties of the right-hand revision for those of the left.
ChangedSpan
=
FormattedSpan
{
TextColor
:
Colors
.
Blue
;
// Change the TextColor property that was added above
TextWeight
:
TextWeights
.
Bold
;
// Add a new property
};
17 is the sum of 5 + 12, and then some.
A revision can contain conditional statements that optionally add elements or properties.
ScoreText
(
score
)
=
Span
{
"A score of
{0}
will recieve the grade "
(
score
);
if
(
score
>=
90) {
TextColor
:
Colors
.
Green
;
"A"
;
}
else
if
(
score
>=
80) {
TextColor
:
Colors
.
Blue
;
"B"
;
The Nytril
®
Programming Language
Page 11 of
114
}
else
if
(
score
>=
70) {
TextColor
:
Colors
.
Yellow
;
"C"
;
}
else
if
(
score
>=
60) {
TextColor
:
Colors
.
Orange
;
"D"
;
}
else
{
TextColor
:
Colors
.
Red
;
"F"
;
}
"."
;
};
TheScores
=
Block
{
// Call the function above
ScoreText
(95);
ScoreText
(83);
ScoreText
(55);
};
A score of 95 will recieve the grade A.
A score of 83 will recieve the grade B.
A score of 55 will recieve the grade F.
A revision can contain a
for
,
foreach
,
do
or
while
loop. In this situation, the expressions inside the loop
acts the same way as expressions inside a revision, except they are repeated each time the loop
repeats. This allows revisions to contain a programmable number of elements.
ShowSet
(
count
)
=
Span
{
"The set has
{0}
members ["
(
count
);
// Repeat 'count' times
for
(
var
i
=
1;
i
<=
count
;
++
i
) {
if
(
i
>
1)
", "
;
// Add this element
i
;
// Add this element
}
"]."
;
};
TheSets
=
Block
{
ShowSet
(2);
ShowSet
(5);
ShowSet
(10);
};
The set has 2 members [1, 2].
The set has 5 members [1, 2, 3, 4, 5].
The set has 10 members [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].
Certain properties can add implicit elements to a revision. The properties
Begin
,
End
,
Separator
,
PairSeparator
, and
LastSeparator
act after the revision gets all of its explicit elements. This allows you
to create formatting styles that insert elements in certain places.
CommaList
=
Span
{
Introduction
Page 12 of
114
Begin
:
"["
;
// Add this element at the beginning
End
:
"]."
;
// Add this element at the end
Separator
:
", "
;
// Add this element between each element
PairSeparator
:
" and "
;
// Use as a separator only if there are 2 items
LastSeparator
:
", and "
;
// Use this as the last separator
};
ShowArray
(
count
)
=
CommaList
{
for
(
var
i
=
1;
i
<=
count
;
++
i
)
i
;
// Add this element
};
AllArrays
=
Block
{
ShowArray
(1);
ShowArray
(2);
ShowArray
(4);
};
[1].
[1 and 2].
[1, 2, 3, and 4].
Important:
If an array is an element of a revision then all of the elements of the array are added, as if
they were placed directly in the revision. This may seem counter-intuitive at first, but this convention
makes it easy to add iterated content.
ArrayElements
=
Span
{
"Elements are "
;
Span
{
Separator
:
CommaSpace
;
[1, 2, 3];
// Add 3 elements instead of 1 array
4
..
10
step
1;
// This expression is the same as [4, 5, 6, 7, 8, 9, 10]
};
};
Elements are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
You can use the rules of revisions to construct layers of related formatting styles. By stacking and
combining revisions, heirarchical style dictionaries can be created easily in a manner that is similar to
CSS or to the way word processors allow styles to inherit from each other and override properties.
BaseStyle
=
Paragraph
{
TextFamily
:
TextFamilies
.
Calibri
;
TextHeight
:
11pt;
};
BodyStyle
=
BaseStyle
{
FirstIndent
:
16pt;
};
HeaderStyle
=
BaseStyle
{
TextFamily
:
TextFamilies
.
TimesNewRoman
;
TextHeight
:
120%;
Bold
;
Underline
;
SpaceAfter
:
8pt;
};
The Nytril
®
Programming Language
Page 13 of
114
Document
=
Block
{
HeaderStyle
{
"Introduction"
;
};
BodyStyle
{
"The rain in Spain lies mainly on the plane."
;
};
};
Introduction
The rain in Spain lies mainly on the plane.
Functions
There are some important syntactic differences between Nytril and other C-style languages regarding function
definitions, consistent with the goal of having a minimum of operators to increase readability.
•
Nytril allows, but does not require, an empty set of parenthesis () after functions that take no
parameters, either on declaration or at the call site.
•
Nytril has an optional inline function declaration syntax that uses an equal (=) sign and a single
expression, in lieu of a full {} scope with a return statment.
•
A function that returns a value does not need to have a declared return type.
If the return type declaration is missing, the return type is assumed to be 'any'.
A void return type means that the function returns no value.
•
Nytril requires an '@' operator whenever a function reference is used as a closure.
•
Nytril allows global functions that do not belong to a class and have no 'this' pointer, although they can
be defined inside of a namespace.
Functions can be declared in the global scope or inside a namespace.
F1
(
x
)
=
x
+
1;
// F1 defined globally
N1
.
F2
(
x
)
=
x
+
2;
// F2 defined inside the namespace N1
namespace
N2
{
F3
(
x
)
=
x
+
3;
// F3 defined inside the namespace N2
}
If a global function is marked as readonly, then the function is run the first time it is called anywhere in
the program, and the return value is cached. If the function is called again anywhere, the cached value
from the first run is returned immediately. This is useful when loading large constant values such as
images or the results of database queries or REST calls, where the intention is usually to retrieve
information once and then use the same copy for many calculations.
ComplexSlowQuery
{
// Slow process...
return
0;
}
readonly
Data
=
ComplexSlowQuery
;
// Run only once
readonly
Cost
=
Data
.
Quantity
*
Data
.
Price;
// Use like a variable
Functions can be declared without a specific (i.e. 'any') return type. This allows the flexible use of an
abstract expression to return different types of results.
Introduction
Page 14 of
114
SquareNumber
(
x
) {
return
x
*
x
;
}
ShowSquares
=
Block
{
SquareNumber
(4);
SquareNumber
(
Symbol
(
"x"
));
};
16
x
2
Note that each separate expression is terminated by a semicolon (;). If the statement is followed by a
closing brace '}' then the ';' is optional. Branch statements (such as
if
,
else
and
foreach
), class
definitions and regular function blocks are not terminated by a semicolon.
ExampleFunction
{
var
s
=
"Statements are terminated by a semicolon"
;
return
s
+
";"
;
}
Statements are terminated by a semicolon;
Functions can also be declared with a return type. This allows the compiler to more easily check for
common errors. Furthermore, if the returned value is an object, a return type on the function will
increase performance and compile-time error checking. This is because the calling expression knows
the class of the return value, it can do a compile-time checking/binding of any members referenced on
that object.
int
TypedFunction
{
return
7;
// Must match return type of function
}
7
A function can be declared using a direct "=" syntax. The code for the function can be on more than
one source line, but must be a single expression terminated by a ';'. This type of function does not run
faster, but the more compact representation might be easier to understand.
Power
=
3;
Cube
(
x
)
=
x
^
Power
;
OneThousand
=
Cube
(10);
1000
Unlike other C-Style languages, a function without parameters does not require an empty set of parens
'()' either on declaration or when it is used. This can cause some confusion to programmers used to the
other convention. It is important to remember that although a function taking no parameters 'looks'
like a simple variable access, it is a function call that is executed each time it is referenced (unless it is
marked
const
or it is a global function marked as
readonly
).
RandomNumber
=
Math
.
Random
(1
..
100);
// Function taking no parameters
The Nytril
®
Programming Language
Page 15 of
114
ShowRandom
=
Paragraph
{
Separator
:
CommaSpace
;
for
(
int
i
=
0;
i
<
10;
++
i
)
RandomNumber
;
// Called 10 times in a row, generating a new value each time
};
39, 5, 96, 68, 21, 55, 6, 38, 94, 27
If a global or static function without parameters is declared using the keyword
readonly
, the return
value is cached when it is evaluated for the first time in the program's execution. After that, the same
value is returned without re-evaluation. If the function is called more than once, this will result in
speed improvements. Use this option with care, as it can lead to confusion, but there are many
scenarios where readonly functions are the right choice. For instance, when loading an image from a
file or loading data from a database, you may wish to read the data once, and refer to it many times
throughout your code. This feature allows you to accomplish that goal without creating another
variable to hold the cached value.
readonly
Measurement
=
8.65
*
Math
.
Sin
(
Math
.
Random
(0
..
90)
degrees
);
// Run once
ShowMeasurements
=
Paragraph
{
Separator
:
CommaSpace
;
for
(
int
i
=
0;
i
<
3;
++
i
)
Measurement
;
// Function body executed only once, after which the same value is returned
};
1.5020567368189475, 1.5020567368189475, 1.5020567368189475
Values that are known at compile time can be declared using the keyword
const
. These values are
substituted directly into the code during compilation. This speeds up runtime performance and
prevents accidental modification of the symbol's value.
const
g
=
9.8m
per
second
^
2;
// Can be calculated at compile time
ShowGravity
=
Paragraph
{
TextAbbreviate
:
true
;
g
;
};
9.8
m
s
2
Global variables can be declared using the keyword
var
. These variables can be changed throughout
the execution of the program.
var
Number
=
1;
ShowNumbers
=
Block
{
"Number = "
+
Number
++
;
"Number = "
+
Number
;
};
Number = 1
Number = 2
Variables can be declared with a type, which can help the compiler catch common errors and possibly
Introduction
Page 16 of
114
improve performance.
var
double
TypedNumber
=
2.7;
ShowTypedNumber
=
Paragraph
{
"Number = "
;
TypedNumber
;
};
Number = 2.7
A feature called 'affinity' allows for more natural and compact expression of common pairs of values.
Values placed side-by-side without an operator in-between them are combined using an implied
(binary) affinity operator. Each pair of values will be joined based on their actual types at runtime. As
shown below, the first line shows a normal expression using the '+' operator. Here, as you would
expect, the '4' and '1000' are added together. On the next line, the '4' and 'inches' are placed together
without an operator between them. At runtime, the compiler determines that an integer and a unit
should be multiplied together.
ShowAffinity
=
Block
{
Paragraph
{
"Numbers summed: "
;
4
+
1000;
// Using the '+' operator
};
Paragraph
{
"Numbers multiplied: "
;
4
inches
;
// Using an implied 'affinity' operator
};
};
Numbers summed: 1004
Numbers multiplied: 4 inches
Other examples are show below.
AffinityExample
=
Block
{
"String-"
"String"
;
// Append
"Example "
2;
// Append
3
meters
;
// Multiply
CiteOptions
.
AddSuffix
CiteOptions
.
ShowDate
;
// Binary or
};
String-String
Example 2
3 meters
ShowDate
AddSuffix
The 'each' operator
The
each
operator is used to call a function with a parameter, once for every item in an array. The
resulting expression is an array of function return values.
Square
(
x
)
=
x
*
x
;
SquareNumbers
=
Paragraph
{
The Nytril
®
Programming Language
Page 17 of
114
Separator
:
CommaSpace
;
Square
(
each
[1, 2, 3, 4]);
};
1, 4, 9, 16
If a function has more than 1 parameter, the
each
operator can be used on more than 1 argument. This
raises the dimension of the output array.
Power
(
x
,
power
)
=
x
^
power
;
PowerNumbers
=
Block
{
var
result
=
Power
(
each
[2, 3, 4],
each
[1, 2, 3]);
// Returns 2-d array
foreach
(
var
r
in
result
) {
Paragraph
{
Separator
:
CommaSpace
;
r
;
}
}
};
2, 4, 8
3, 9, 27
4, 16, 64
Most unary and binary operators can also be used in conjunction with the
each
operator to provide a
very compact expression. The code below shows the number 2 being raised to the power of an array of
numbers using the
^
power operator.
PowerVector
=
Vector
.
Convert
(2
^
(
each
1
..
8));
[2, 4, 8, 16, 32, 64, 128, 256]
If you use an
each
expression on both sides of a binary operator, you get a 2-dimensional array result.
The code below shows an array of numbers being raised to the power of another array of numbers
using the
^
power operator and the results are converted to a matrix.
PowerMatrix
=
Matrix
.
Convert
((
each
[2, 3, 4])
^
(
each
[2, 3, 4]));
4
8
16
9
27
81
16
64
256
Namespaces
A namespace is a collection of global variables, functions and classes. A namespace can be declared
using the keyword
namespace
. If the namespace does not already exist, it will be created. The
variables declared within the space will be added in the order encountered.
namespace
Products
{
Apple
=
"Gala"
;
Lemon
=
"Meyer"
;
}
ShowProducts
=
Block
{
Introduction
Page 18 of
114
Products
.
Apple
;
Products
.
Lemon
;
};
Gala
Meyer
Namespaces can also be declared with an indentifier followed by a dot and then the identifier to add
to that namespace. As in the case of the of the explicity declared namespace, a namespace will be
created if it does not already exist.
Handbags
.
LouisVuitton
=
"Louis Vuitton"
;
// Added to the existing 'Handbags' namespace above
namespace
Handbags
{
Gucci
=
"Gucci"
;
Prada
=
"Prada"
;
}
ShowAllHandbags
=
Block
{
Table
(0.5,
null
, [1", 1"]) {
Row
{
Background
:
80%;
"Variable"
;
"Value"
;
};
foreach
(
var
a
in
attribute
Handbags
)
Row
{
a
.
Name;
a
.
Value;
}
}
};
Variable
Value
LouisVuitton
Louis Vuitton
Gucci
Gucci
Prada
Prada
Namespaces can be used to accumulate data into a common container. The container can then be
used to make charts, tables or do other calculations.
namespace
Revenue
{
Year1
=
20_000_000;
Year2
=
670_000_000;
Year3
=
1220_000_000;
}
ShowRevenue
=
Chart
(3", 2") {
var
revenue
=
attribute
(
Revenue
)
.
Children
;
ChartType
:
ChartTypes
.
Column
;
XLabel
:
Bold
"Year"
;
XAxis
:
ChartAxis
{
(
each
revenue
)
.
Name
;
};
ValueLabel
:
Bold
"Revenue\n(Millions)"
;
ValueAxis
:
ChartAxis
;
ChartSeries
{
The Nytril
®
Programming Language
Page 19 of
114
foreach
(
var
r
in
revenue
)
new
DataPoint
(
each0
,
r
.
Value
*
0.000001);
};
};
Year
Revenue
(Millions)
Year1
Year2
Year3
0
200
400
600
800
1000
1200
1400
Numbers
An integer is a simple sequence of decimal digits without a decimal point
IntegerValue
=
42;
42
An unsigned integer is an integer that cannot have a negative value
UnsignedValue
=
33U;
33
Here is a list of the numeric types that can be specified with a special suffix
NumberTypeList
=
Block
{
typeof
(2);
typeof
(2L);
typeof
(2U);
typeof
(2UL);
typeof
(2.0F);
typeof
(2.0D);
typeof
(2.0M);
};
int
long
uint
ulong
float
double
decimal
Hexadecimal values can be specified by preceeding the number with 0x
HexValue
=
0x15;
Introduction
Page 20 of
114
21
Binary values can be specified by preceeding the number with 0b
BinaryValue
=
0b1101;
13
Real numbers are a sequence of decimal digits containing a decimal point
RealValue
=
3.14;
3.14
Ratios of integers can be created using the operator
over
OneThird
=
1
over
3;
FractionSum
=
OneThird
+
5
over
6;
1
1
6
Operations that mix real and fractional or integer values will be converted to real numbers
DerivedValue
=
RealValue
*
FractionSum
;
3.6633333333333336
Real numbers can be formatted to the desired number of decimal places
FormattedValue
=
{
TextDigits
:
3}
DerivedValue
;
3.663
Digit groups for large numbers can be seperated using an underscore
_
SegmentedValue
=
2_164_843;
2164843
Imaginary numbers can be expressed in a variety of forms
Imaginary1
=
Symbolic
.
Sqrt
(
-
1)
+
1i
+
Math
.
I
+
(
-
1)
^
(1
over
2);
4
i
Imaginary numbers can be added
Imaginary2
=
3i;;
ISum
=
Imaginary1
+
Imaginary2
;
7
i
The Nytril
®
Programming Language
Page 21 of
114
Complex numbers are also supported, and real and imaginary parts are automatically aggregated
Complex1
=
3i
+
2i
+
5
+
3;
8
+
5
i
Complex multiplication and powers are supported
Complex2
=
Complex1
*
(2i
+
4);
22
+
36
i
Get the real part of a complex number using the function:
RealPart(
x
)
For example:
Real2
=
Math
.
RealPart
(
Complex2
);
22
Get the imaginary part of a complex number using the function:
ImaginaryPart(
x
)
For example:
Imaginary3
=
Math
.
ImaginaryPart
(
Complex2
);
36
Get the modulus of a complex number using the function:
Abs(
x
)
For example:
ComplexModulus
=
Math
.
Abs
(
Complex2
);
445
2
Strings
A
string
is an array of characters enclosed in quotation marks ("...") in source code.
SimpleString
=
"This is an array of characters"
;
This is an array of characters
All array operations work on strings, in the same way
SimpleString
=
"This is an array of characters"
;
StringSlice
=
SimpleString
[10
..
15];
StringNew
=
SimpleString
.
Insert(5
..
11,
"really "
);
This is an array of characters
Introduction
Page 22 of
114
array
This really is an array of characters
Strings can be concatenated by simply placing them together or by using using the operator
+
JoinString
=
SimpleString
", and some more"
+
", and some more still"
;
This is an array of characters, and some more, and some more still
Strings can contain numbered sections that allow for substitutions supplied by arguments to the string
Message
=
"There is an error in \"
{0}
\""
;
FileError
=
Message
(
"file.txt"
);
There is an error in "file.txt"
The sections can be out of order in the string, but they will still correspond to the order of the
arguments
Warning
=
"Please wait
{1}
seconds for
{0}
"
;
WaitWarning
=
Warning
(
"the report to generate"
, 5);
Please wait 5 seconds for the report to generate
The arguments to a string format can be any type, including equations or pictures
RootFormat
=
"The inverse square root of
{0}
is
{1}
"
;
RootFunction
(
x
)
=
RootFormat
(
x
, 1
/
Symbolic
.
Sqrt
(
x
));
RootArray
=
Span
{
Separator
:
", "
;
RootFunction
(
each
[2,
Symbol
(
"x"
),
"two"
])};
The inverse square root of 2 is
1
2
, The inverse square root of
x
is
1
x
, The inverse square root of two is
1
two
Percentages
Percentages are specified using the operator
%
BaseRate
=
10%;
10%
Percentages can be added together like normal numbers
BonusRate
=
4%;
TotalRate
=
BaseRate
+
BonusRate
;
14.000000000000002%
Percent values can be multiplied to yield a plain numeric value
Sales
=
$
1000;
Payment
=
TotalRate
*
Sales
;
The Nytril
®
Programming Language
Page 23 of
114
$
140.00
Some properties behave differently when a percent value is used.
BigText
=
Span
{
TextHeight
:
200%;
// Percentage of existing TextHeight
TextColor
:
50%;
// Gray scale
"Big Text"
;
};
Big Text
Dates
A
DateTime
is specified using #YYYY-M-D:H:M:S# in source code.
const
DayOfBirth
=
#2016-1-31#
;
// YYYY-MM-DD
2016-01-31
A constant date can be specified directly in source code. A date value carries with it an indicator of the
precision of its specification
const
TimeOfBirth
=
#2016-01-31 03:10:37.513#
;
2016-01-31 03:10:37.513
Dates can be formatted with the field
TextFormat
FormatDate
=
Paragraph
{
DateTime
.
Now
;
TextFormat
:
"dddd, MMMM dd, yyyy"
;
};
Monday, August 03, 2026
Dates can be operated on with time units
TwinBirth
=
TimeOfBirth
+
1
minute
+
41
seconds
;
2016-01-31 03:12:18.513
A time span is specified with
TimeSpan
TimeInHospital
=
new
TimeSpan
(2, 4);
2d04:00:00
Time spans can be added to dates
FirstDayHome
=
TwinBirth
+
TimeInHospital
;
Introduction
Page 24 of
114
2016-02-02 07:12:18.513
Subtracting two dates gives a TimeSpanClass
TimeDifference
=
#2016-1-31 6:10:37.5#
-
#2012-1-31#
;
1461d
TimeSpanClass members can be used to extract real numeric values for various units of time
Difference
=
Block
{
"
{0}
Years"
(
TimeDifference
.
Years);
"
{0}
Days"
(
TimeDifference
.
Days);
"
{0}
Hours"
(
TimeDifference
.
Hours);
"
{0}
Minutes"
(
TimeDifference
.
Minutes);
"
{0}
Seconds"
(
TimeDifference
.
Seconds);
};
4.000704663852765 Years
1461.2573784722222 Days
35070.177083333336 Hours
2104210.625 Minutes
126252637.5 Seconds
Units
Measurment units are handled natively
Distance
=
16";
16 inches
You can convert between compatible units using the operator
tounit
MetricDistance
=
Distance
tounit
centimeters
;
40.64 centimeters
Common units can be combined with a literal number using a special suffix.
ViewCommonUnits
=
Block
{
foreach
(
var
u
in
CommonUnits
) {
Paragraph
(
null
, [0.9"]) {
SourceSelection
(
u
);
"\t = "
;
u
;
}
}
};
4"
= 4 inches
4.25"
= 4.25 inches
6'
= 6 feet
The Nytril
®
Programming Language
Page 25 of
114
6'2
= 74 inches
6'3"
= 75 inches
6'3.5
= 75.5 inches
6'3.25"
= 75.25 inches
5g
= 5 grams
5kg
= 5 kilograms
5cg
= 5 centigrams
5mg
= 5 milligrams
5l
= 5 liters
5ml
= 5 milliliters
6.25m
= 6.25 meters
5km
= 5 kilometers
5mm
= 5 millimeters
5cm
= 5 centimeters
5ft
= 5 feet
5in
= 5 inches
5mi
= 5 miles
5pt
= 5 pts
5px
= 5 pixels
Values with different, but compatible, units can be added together
LongerDistance
=
3"
+
25.4cm
+
1';
25 inches
Units can be multiplied together to form units of higher dimension
Area
=
Distance
*
2
yards
;
Volume
=
Area
*
14.0"
tounit
centimeters
^
3;
264,291 centimeters
3
Common conversions of higher dimension units are handled in the same way
LiquidMeasure
=
Volume
tounit
gallons
;
69.8181818182 gallons
Multiplications factor out the correct units
WaterDensity
=
1
kilogram
per
liter
;
LiquidWeight
=
WaterDensity
*
Volume
tounit
pounds
;
583 pounds
The power of water flowing over Niagra falls
WaterFlow
=
1
mile
^
3
per
year
;
// from the book "Energy" by Richard Rhodes
FallsHeight
=
170
feet
;
g
=
9.8
meters
per
second
^
2;
Power
=
(
WaterFlow
*
WaterDensity
*
FallsHeight
*
g
)
tounit
megawatts
;
67 megawatts
Introduction
Page 26 of
114
Currency
Monetary quantities are supported natively
PocketChange
=
47
¢
;
TotalChange
=
PocketChange
+
3
Cents
+
$
0.05;
55¢
Compatible currency values can be added together
WalletCash
=
$
12;
TotalMoney
=
(
WalletCash
+
TotalChange
)
tounit
Dollars
;
$
12.55
Simple accruals can be calculated with a user-defined function
Compound
(
amount
,
rate
,
times
) {
while
(
times
>
0) {
amount
+=
amount
*
rate
;
--
times
;
}
return
amount
;
}
Payments
=
Block
{
TextGroup
:
true
;
Compound
(
$
200_000, 4.1%, 5);
};
$
244,502.69
Arrays
An array is an ordered container of objects
[0, 1, 2, 3,
x
,
y
, A, B, C,
π
2
,
i
]
Get the value of a child in the array using a zero-based index inside square brackets
[]
ArraySub
=
Numbers
[1];
1
A slice of the start of the array is obtained by putting a right range inside square brackets
[]
[0, 1, 2, 3]
A negative subscript represents the index obtained by subtracting the subscript from the length of the
array
The Nytril
®
Programming Language
Page 27 of
114
[0, 1, 2, 3,
x
,
y
, A, B, C]
A slice of the middle of the array is obtained by putting a full range inside square brackets
[]
[2, 3,
x
,
y
]
A slice of the end of the array is obtained by putting a left range inside square brackets
[]
[3,
x
,
y
, A, B, C,
π
2
,
i
]
An arbirtary slice of a array can be obtained by putting an array of ranges inside square brackets
[]
[0, 1, 3,
y
, A,
i
]
Return a new array missing elements from the target array using the function:
public
[]
Array
.Remove(
range
)
For example:
[0,
x
,
y
, A, B, C,
π
2
,
i
]
Delete elements from an index to the end of the array by omitting the second argument
[0, 1, 3,
x
,
y
, A, B, C,
π
2
,
i
]
Negative numbers in the range represent the number of items from the end of the array
[0, 1, 2, 3,
x
,
y
, A, B]
Find items in a array that match a value using the function:
public
object
Array
.FindIndex(
delegate
bool
FindDelegate
(
value
)
predicate
,
int
maxcount
=
null
)
For example:
[0]
Find the indexes of items in an array that match criteria by specifying a boolean function that takes 1
argument
[1..2, 5]
Create an array of items that match a predicate using the function:
public
[]
Array
.FindSlice(
delegate
bool
FindDelegate
(
value
)
predicate
,
int
maxcount
=
null
)
Introduction
Page 28 of
114
For example:
[10, 7, 8]
Arrays can be sorted in ascending or descending order using the function:
public
[]
Array
.ToSortedArray(
bool
descending
=
false
,
delegate
int
CompareDelegate
(
v1
,
v2
)
comparedelegate
=
null
)
For example:
[2, 4, 5, 7, 8, 10]
Change the sort direction by setting the descending parameter to true
[10, 8, 7, 5, 4, 2]
Use a comparison function to sort complex structures
readonly
ValueClass
[]
Structures
=
[
new
(3),
new
(5),
new
(2),
new
(0),
new
(1),
];
int
CompareStructure
(
ValueClass
a
,
ValueClass
b
)
=
a
.
Value
.
Compare
(
b
.
Value
);
readonly
SortedStructures
=
Structures
.
ToSortedArray
(
false
,
@
CompareStructure
);
ShowStructureArray
=
Paragraph
{
Separator
:
", "
;
SortedStructures
;
};
0, 1, 2, 3, 5
An array can contain data of all types, including variables and formulas
[2,
1
3
,
π
,
x
2
+
y
2
a
]
An array can include other arrays
[A simple sentence, 0, 1, 2, 3,
x
,
y
, A, B, C,
π
2
,
i
, 2,
1
3
,
π
,
x
2
+
y
2
a
]
The contents of two arrays can be joined together to make a larger array using the operator
+
The Nytril
®
Programming Language
Page 29 of
114
[0, 1, 2, 3,
x
,
y
, A, B, C,
π
2
,
i
, 2,
1
3
,
π
,
x
2
+
y
2
a
]
You can create another array which contains the result of the operation performed on each item in the
array using the operator
each
[3,
1
1
3
,
π
+
1
,
x
2
+
y
2
a
+
1
]
This works for all operators and can be daisy-chained to apply to more than one operation
[
4
a
2
,
1
9
a
2
,
(
π
a
)
2
,
x
2
+
y
2
]
Function arguments can also be expanded using the operator
each
[
8
,
1
27
,
π
3
,
x
2
+
y
2
a
3
]
Ranges
A range is an ordered, inclusive pair of values using the operator
..
SmallRange
=
1
..
5;
1..5
A range can also use variables for the min or max values
Min
=
1;
Max
=
5;
MinMax
=
Min
..
Max
;
1..5
An array can be created with a range using the operator
step
[1, 3, 5, 7, 9, 10]
Make the array enumerate backwards by using a negative step
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Non-numeric arrays can be created from a range, as long as the range limits can be compared
[
x
,
x
+
1
,
x
+
2
,
x
+
3
,
x
+
4
,
x
+
5
]
Introduction
Page 30 of
114
Exclude the low end of the range using the operator
>..
[2, 3, 4, 5]
Exclude the high end of the range using the operator
..<
[1, 2, 3, 4]
A slice of an array can be created using a range
[A, B, C]
A low open range can be used to specify the beginning of an array
[A, B, C, D]
A high open range can be used to specify the end of an array
[D, E, F, G]
Negative numbers denote the distance from the end of the array
[E, F, G]
A slice can include an arbitrary array of indices and ranges
[A, B, C, E, F, G]
Classes and Objects
Class definitions can be used for a more formal approach to design. A class may have 1 special function
called "Constructor" which initializes the members.
class
LocationClass
{
var
X
,
Y
;
Constructor
(
x
,
y
) {
X
=
x
;
Y
=
y
;
}
override
GetLayoutSpan
=
Span
{
X
;
CommaSpace
;
Y
;
};
}
ShowObjects
=
Block
{
var
p1
=
new
LocationClass
(1, 2);
// Constructor called here
var
p2
=
new
LocationClass
(1, 2);
// ..
p1
;
// LocationClass.GetLayoutSpan called here
The Nytril
®
Programming Language
Page 31 of
114
p2
;
// ..
};
1, 2
1, 2
A class may inherit one other class and add members and methods.
class
CircleClass
:
LocationClass
{
var
Radius
;
Constructor
(
x
,
y
,
r
) {
super
.
Constructor
(
x
,
y
);
Radius
=
r
;
}
override
GetLayoutSpan
=
Span
{
"("
;
super
.
GetLayoutSpan
;
")["
;
Radius
;
"]"
;
};
}
SomeObjects
=
[
new
LocationClass
(1, 2),
new
CircleClass
(4, 5, 8)];
ShowObjectArray
=
Block
{
SomeObjects
;
};
1, 2
(4, 5)[8]
You can add custom left and right affinity between objects of different types to make the creation of
compound data types more intuitive.
class
BaseClass
{
var
Name
;
Constructor
(
name
) {
Name
=
name
;
}
static
operator
Affinity
(
BaseClass
b
,
int
number
) {
return
new
CompoundClass
(
b
,
number
);
}
static
operator
Affinity
(
int
number
,
BaseClass
b
) {
return
new
GroupClass
(
new
CompoundClass
(
b
),
number
);
}
override
GetLayoutSpan
=
Name
;
}
class
CompoundClass
{
var
BaseClass
Base
;
var
int
Number
;
Constructor
(
BaseClass
b
,
int
n
=
0) {
Base
=
b
;
Number
=
n
;
}
Introduction
Page 32 of
114
static
operator
Affinity
(
int
number
,
CompoundClass
c
) {
return
new
GroupClass
(
c
,
number
);
}
override
GetLayoutSpan
=
Number
>
0
?
Base
sub
Number
:
Base
;
}
class
GroupClass
{
var
CompoundClass
Compound
;
var
int
Number
;
Constructor
(
CompoundClass
c
,
int
n
=
0) {
Compound
=
c
;
Number
=
n
;
}
override
GetLayoutSpan
{
if
(
Number
>
0) {
return
Nary
{
PreUpper
:
Number
;
Operator
:
Span
{
"("
;
Compound
;
")"
};
};
}
return
Compound
;
}
}
CompoundTypes
=
Block
{
var
b
=
new
BaseClass
(
"B"
);
// Make a base
var
c
=
b
2;
// Make a compound from the base
var
g
=
3
c
;
// Make a group from the compound
Table
(
null
,
null
, [1", 1"]) {
Row
{
"Base"
;
b
};
Row
{
"Compound"
;
c
};
Row
{
"Group"
;
g
};
};
};
Base
B
Compound
B
2
Group
(B
2
)
3
Page 33 of
114
Formatting
Boxes
Values can be enclosed in different types of horizontal boxes using the formatter:
DocFormatter
HBox(
width
=
null
,
height
=
null
,
Border
border
=
null
)
For example:
RedBox
(
i
)
=
Canvas
(20pt,
null
,
new
Edge
(0.25pt, 0,
Colors
.
Red
)) {
HAlign
:
Center
;
i
;
};
HBoxSet
=
HBox
(
null
,
null
,
new
Edge
(3, 4,
Colors
.
LightGray
)) {
VAlign
:
Center
;
RedBox
(
each
1
..
3);
};
1
2
3
Values can be enclosed in different types of vertical boxes using the formatter:
DocFormatter
VBox(
width
=
null
,
height
=
null
,
Border
border
=
null
)
For example:
VBoxSet
=
VBox
(
null
,
null
,
new
Edge
(3, 4,
Colors
.
LightGray
)) {
HAlign
:
Center
;
RedBox
(
each
1
..
3);
};
1
2
3
Separators can be used to add an item between each item in the revision
BoxesWithSeparators
=
Paragraph
{
HBoxSet
{
Separation
:
10pt;
Separator
:
"+"
;
LastSeparator
:
"="
;
};
Space
;
VBoxSet
{
Separation
:
2pt;
Separator
:
SolidBox
(
Colors
.
Blue
);
LastSeparator
:
SolidBox
(
Colors
.
Red
);
};
};
Formatting
Page 34 of
114
1
+
2
=
3
1
2
3
Margins can be added outside any box to put distance between it and ajacent figures
BoxesWithMargins
=
Paragraph
{
Separator
:
Space
*
4;
MarginBox
(
each
ThicknessCombos
);
};
Left, Top, Right, Bottom
Top
Bottom
Left
Right
Left, Right
Top, Bottom
Border padding puts distance between the border and its contents
BoxesWithPadding
=
Paragraph
{
PaddingBox
(
each
BorderCombos
);
};
Left, Top, Right, Bottom
Top
Bottom
Left
Right
Left, Right
Top, Bottom
A fixed separation can be put between each child element with the field
Separation
AddChildren
(
sep
)
=
HBox
{
VAlign
:
Center
;
HBox
(150) {
Separation
:
sep
;
foreach
(
var
i
in
1
..
3) {
Canvas
(20, 20,
new
Edge
(0.5, 0,
Colors
.
Blue
)) {
HAlign
:
Center
;
i
;
}
}
};
"Separation
{0}
"
(
sep
);
};
HBoxWithSeparation
=
GraphPaper
.
Show
(
new
Size
(130, 70),
new
Size
(10)) {
VBox
{
AddChildren
(
each
[0, 5, 10]);
}
};
1
2
3
Separation 0
1
2
3
Separation 5
1
2
3
Separation 10
Rounded corners can be specified using the
BorderRadius
field.
Chicklet
(
text
)
=
HBox
(
null
,
null
,
new
Edge
(2, 0,
Colors
.
Blue
)) {
The Nytril
®
Programming Language
Page 35 of
114
TextHeight
:
30pt;
HAlign
:
Center
;
Background
:
Colors
.
AliceBlue
;
text
;
};
AllChicklets
=
Paragraph
{
Separator
:
Space
*
3;
Chicklet
(
"Rounded"
) {
BorderRadius
:
10};
Chicklet
(
"Flat"
) {
BorderRadius
:
new
Size
(20, 10)};
Chicklet
(
"TL-BR"
) {
BorderRadius
:
new
BorderRadius
(6, 0, 6, 0)};
Chicklet
(
"Top"
) {
BorderRadius
:
new
BorderRadius
(20, 20, 0, 0)};
Chicklet
(
"Right"
) {
BorderRadius
:
new
BorderRadius
(0,
new
Size
(10, 20),
new
Size
(10, 20), 0)};
};
Rounded
Flat
TL-BR
Top
Right
A shadow effect can be specified using the
Shadow
field.
ShadowBox
(
text
,
edge
,
Edge
shadow
)
=
HBox
(
null
,
null
,
new
Edge
(
edge
, 5)) {
Shadow
:
shadow
;
TextHeight
:
20pt;
HAlign
:
Center
;
Background
:
90%;
text
;
};
AllShadows
=
Paragraph
{
Separator
:
Space
*
3;
ShadowBox
(
"Shadow 0"
, 0,
new
Edge
(1, 0,
Colors
.
DarkGreen
));
ShadowBox
(
"Shadow 1"
, 1,
new
Edge
(1, 0,
Colors
.
DarkGray
));
ShadowBox
(
"Shadow 2"
, 1,
new
Edge
(2, 0,
Colors
.
Brown
));
ShadowBox
(
"Shadow 3"
, 1,
new
Edge
(3, 0,
Colors
.
DarkBlue
));
};
Shadow 0
Shadow 1
Shadow 2
Shadow 3
Colors and Fills
The
Colors
namespace contains a variety of commonly used colors.
ShowFill
(
Attribute
prop
)
=
Canvas
(20, 20) {
Background
:
prop
.
Value
;
Tip
:
new
ColorTipClass
(
prop
);
};
ColorsSpace
=
Span
{
ShowFill
(
each
attribute
(
Colors
)
.
Children
);
};
Formatting
Page 36 of
114
The
Color
represents a color with specific RGBA value.
ShowColor
(
r
,
g
,
b
,
a
)
=
HBox
{
var
color
=
new
Color
(
r
,
g
,
b
,
a
);
VAlign
:
Center
;
Canvas
(15, 15) {
Background
:
color
;
};
Separation
:
3;
Paragraph
{
TextHeight
:
14;
TextNumPadding
:
2;
TextRadix
:
16;
Separator
:
Space;
color
.
R
;
color
.
G
;
color
.
B
;
color
.
A
;
Space
;
};
};
ColorsConstructor
=
Span
{
ShowColor
(0, 0, 0, 20%);
ShowColor
(0x3F, 50%, 255, 100%);
ShowColor
(128, 128, 128, 100%);
};
00 00 00 33
3f 7f ff ff
80 80 80 ff
Colors can also be constructed from HSLA values using the function:
public
static
Color
Color
.FromHSLA(
hue
,
saturation
,
lightness
,
alpha
=100%)
For example:
ShowHSLA
=
HBox
{
var
color
=
Color
.
FromHSLA
(170, 0.25, 0.5);
TextDigits
:
2;
Separation
:
3;
VAlign
:
Center
;
Canvas
(15, 15) {
Background
:
color
;
};
Paragraph
{
Separator
:
Space
*
3;
color
.
H
;
color
.
S
;
color
.
L
;
};
};
170.00 0.25 0.50
An even color gradient can be formed using the function:
public
static
LinearGradient
LinearGradient
.FromColorArray(
Color
[]
colors
)
For example:
The Nytril
®
Programming Language
Page 37 of
114
readonly
Heatmap
=
LinearGradient
.
FromColorArray
([
Colors
.
Blue
,
Colors
.
Cyan
,
Colors
.
Yellow
,
Colors
.
Red
]);
ShowHeatmap
=
HBox
(200, 20) {
Background
:
Heatmap
;
};
An interpolated color can be formed from a percentge using the function:
public
readonly
Color
LinearGradient
.InterpolateColor(
percent
)
For example:
ShowHeatmap2
=
HBox
{
for
(
double
i
=
0;
i
<=
1.0;
i
+=
0.04) {
HBox
(8, 20,
BorderR
(
new
(1, 0, 89%))) {
Background
:
Heatmap
.
InterpolateColor(
i
);
}
}
};
A 2-dimensional color image can be created from values in a matrix using the function:
public
Matrix
.GetImage(
delegate
Color
ColorDelegate
(
int
row
,
int
col
,
value
)
color
,
altname
=
null
)
For example:
Color
HeatColor
(
int
_
,
int
_1
,
double
value
) {
return
Heatmap
.
InterpolateColor(
value
);
}
GetMapImage
{
int
size
=
200;
double
xfactor
=
2
*
Math
.
PI2
/
size
;
double
yfactor
=
0.5
/
size
;
var
m
=
new
Matrix
<
double
>
(
size
,
size
, 0);
for
(
int
i
=
0;
i
<
size
;
++
i
) {
for
(
int
j
=
0;
j
<
size
;
++
j
)
m
[
i
,
j
]
=
0.5
+
yfactor
*
i
*
Math
.
Sin
(
j
*
xfactor
);
}
return
m
.
GetImage
(
@
HeatColor
,
"Sinusoidal Heat Map"
)
}
Formatting
Page 38 of
114
Sinusoidal Heat Map
Get the bar colors used in charts using the function:
public
static
Color
Color
.ChartColor(
index
)
For example:
ShowChartColors
=
HBox
{
Separation
:
8;
for
(
int
i
=
1;
i
<
20;
++
i
) {
HBox
(8, 20) {
Background
:
Color
.
ChartColor
(
i
);
}
}
};
Use
LinearGradient
to create a linear gradient brush.
ShowFigures
(
name
,
fill
)
=
HBox
{
VAlign
:
Center
;
Separation
:
10;
VBox
(60) {
name
;
};
Shape
(
fill
) {
OpenPath
(0) {
LineTo
(25, 50);
LineTo
(50, 20);
LineTo
(75, 40);
LineTo
(100, 0);
}
};
Canvas
(50, 50) {
Background
:
fill
;
};
Shape
(
fill
) {
EllipsePath
(
new
(
new
(0),
new
(70, 50)));
}
};
The Nytril
®
Programming Language
Page 39 of
114
ColorStop
[]
ColorStops
=
[
new
(10%,
Colors
.
Orange
),
new
(25%,
Colors
.
Blue
),
new
(50%,
Colors
.
Red
),
new
(80%,
Colors
.
Green
),
];
FillLinearGradient
=
Block
{
ShowFigures
(
"Vertical"
,
new
LinearGradient
(0, 0, 0, 1,
ColorStops
));
ShowFigures
(
"Horizontal"
,
new
LinearGradient
(0, 0, 1, 0,
ColorStops
));
ShowFigures
(
"Diagonal"
,
new
LinearGradient
(0, 0, 1, 1,
ColorStops
));
};
Vertical
Horizontal
Diagonal
Use
RadialGradient
to create a radial gradient brush.
FillRadialGradient
=
Block
{
ShowFigures
(
"Top Left"
,
new
RadialGradient
(0, 0, 0, 0, 1, 1,
ColorStops
));
ShowFigures
(
"Top Right"
,
new
RadialGradient
(1, 0, 1, 0, 1, 1,
ColorStops
));
ShowFigures
(
"Centered"
,
new
RadialGradient
(0.5, 0.5, 0.5, 0.5, 1, 1,
ColorStops
));
ShowFigures
(
"Bottom Left"
,
new
RadialGradient
(0, 1, 0, 1, 1, 1,
ColorStops
));
ShowFigures
(
"Bottom Right"
,
new
RadialGradient
(1, 1, 1, 1, 1, 1,
ColorStops
));
};
Top Left
Top Right
Centered
Bottom
Left
Bottom
Right
Shapes
Create a self-contained shape using:
DocFormatter
Shape(
Fill
fill
=
null
,
Stroke
stroke
=
null
,
FillRules
fillrule
=
null
,
width
=
null
,
height
=
null
)
For example:
Formatting
Page 40 of
114
ZigZag
=
Shape
(
null
,
new
(3pt,
Colors
.
Black
,
LineStyles
.
Solid
,
LineCaps
.
Round
,
LineJoins
.
Round
)) {
OpenPath
(0) {
LineTo
(20, 20);
LineTo
(40, 0);
LineTo
(60, 20);
}
};
Use the stroke parameter to change the outline of the shape to a particular size and pattern.
LineStyleTable
=
EnumTable
(
LineStyles
,
attribute
DrawLineStyle
);
Solid
Dashed
Dotted
DashDot
DashDotDot
Use the linejoin parmeter to change the way line segments join together.
LineJoinTable
=
EnumTable
(
LineJoins
,
attribute
DrawLineJoin
);
Miter
Round
Bevel
Use the endcap parameter to change the end-cap of the line.
LineCapTable
=
EnumTable
(
LineCaps
,
attribute
DrawLineCap
);
Flat
Square
Round
Use the miterlimit parameter to limit ratio of the extent of a miter to the stroke size (default: 4.0).
LineMiterTable
=
MiterTable
([10, 1]);
Miter Limit
Effect
10
1
Automatically complete the path with a line segment using the function:
DocFormatter
ClosedPath(
x
,
y
=
null
)
For example:
The Nytril
®
Programming Language
Page 41 of
114
TwoLines
(
closed
)
=
(
closed
?
ClosedPath
(1)
:
OpenPath
(1)) {
LineTo
(1, 20);
LineTo
(20, 20);
};
OpenClose
=
Paragraph
{
ShowClose
(
Colors
.
Red
,
false
);
Tab
;
ShowClose
(
Colors
.
Green
,
true
);
};
Closed:
false
Closed:
true
Adding a second closed path in the same shape will 'cut a hole' in the first shape.
Triangle
=
TwoLines
(
true
);
TriangleFigure
=
Shape
(
Colors
.
Green
) {
Triangle
;
EllipsePath
(
new
(
new
(3, 10),
new
(6)))
};
ShowTriangleFigure
=
GraphPaper
.
Show
(
new
Size
(30),
new
Size
(5)) {
TriangleFigure
};
Add a Bezier curve to the shape using the function:
CurveTo(
Point
p1
,
Point
p2
,
Point
end
)
For example:
Smile
=
OpenPath
(0, 2) {
LineTo
(4, 0);
CurveTo
(
new
(12, 20),
new
(28, 20),
new
(36, 0));
LineTo
(40, 2);
};
SmileShape
=
Shape
(
null
,
new
(2pt,
Colors
.
Red
,
LineStyles
.
Solid
,
LineCaps
.
Round
,
LineJoins
.
Round
)) {
Smile
;
};
ShowSmileShape
=
GraphPaper
.
Show
(
new
(50, 20),
new
(5)) {
SmileShape
;
};
Create a drawing with several shapes at arbitrary locations using:
DocFormatter
Canvas(
width
=
null
,
height
=
null
,
Border
border
=
null
)
For example:
ShowFace
=
GraphPaper
.
Show
(
new
(100, 100),
new
(5)) {
Formatting
Page 42 of
114
Face
;
};
You can specify offsets and sizes using percentages of the exclosing size canvas.
DrawDot
(
x
,
y
)
=
EllipsePath
(
new
(
new
(
x
,
y
),
new
(8%, 8%)));
DrawWatch
(
height
,
color
)
=
Canvas
(
height
,
height
) {
Shape
(
color
) {
ClosedPath
(40%, 0) {
LineTo
(60%, 0);
LineTo
(60%, 6%);
LineTo
(53%, 6%);
LineTo
(53%, 12%);
ArcTo
(
new
(47%, 12%),
new
(44%), 0,
true
,
true
);
LineTo
(47%, 6%);
LineTo
(40%, 6%);
LineTo
(40%, 0%);
};
EllipsePath
(
new
(
new
(11.5%, 17.5%),
new
(77%)));
DrawDot
(46%, 23%);
// top
DrawDot
(16%, 53%);
// left
DrawDot
(46%, 83%);
// bottom
DrawDot
(76%, 53%);
// right
ClosedPath
(50%, 40%) {
LineTo
(53%, 57%);
LineTo
(73%, 77%);
LineTo
(46%, 57%);
};
};
Shape
(
color
) {
DrawDot
(68%, 13%);
// button
};
};
StopWatches
=
HBox
{
VAlign
:
Center
;
Separation
:
20pt;
DrawWatch
(1.25",
#0000FF#
);
DrawWatch
(20mm,
#9F0000#
);
DrawWatch
(24pt,
#008000#
);
};
The Nytril
®
Programming Language
Page 43 of
114
Create a drawing with a repeated tiling pattern.
Tooth
(
x
,
height
)
=
[
LineTo
(
x
,
height
),
LineTo
(
x
,
height
*
0.5),
];
Saw
(
width
,
height
)
=
Shape
(
Colors
.
Silver
) {
OpenPath
(0) {
Tooth
(
each
0
..
width
step
height
,
height
);
LineTo
(
width
, 0)
}
};
Sawtooth
=
Saw
(6", 0.25");
Create a drawing with computed points.
NGons
=
HBox
{
VAlign
:
Top
;
Separation
:
10;
NGon
(30,
each
3
..
10);
};
3
4
5
6
7
8
9
10
Bezier curves use two end points and two control points. The following examples show how the control
points bend the curve.
Quadratic curves have a single control point.
Formatting
Page 44 of
114
Elliptic arcs flow between two end points, around an invisible ellipse rotated at the specified angle. The
following examples show how the angle effects the curve.
large
false
clockwise
false
-30 degrees
0 degrees
30 degrees
clockwise
true
-30 degrees
0 degrees
30 degrees
large
true
clockwise
false
-30 degrees
0 degrees
30 degrees
clockwise
true
-30 degrees
0 degrees
30 degrees
If you want to create a circular arc (such as for a pie wedge), set the radius(width, height) to the same number.
There are four different paths that are determined by the two boolean parameters large and clockwise. Imagine
two circles drawn along the major axis. If large is set to true, then the larger of the two possible arcs will be
selected.
The Nytril
®
Programming Language
Page 45 of
114
large
false
clockwise
false
clockwise
true
large
true
clockwise
false
clockwise
true
Use the 'fillrule' parameter to change the way of determining which points are inside the shape. The
following values determine the 'insideness' of a point in the shape. This determines which areas will be
filled.
EvenOdd
: Default
Imagine drawing a ray from a point in the shape to infinity in any direction, and then examining the
places where a segment of the shape crosses the ray. If this number is even, the point is outside.
→
←
NonZero
Imagine drawing a ray from any point in the shape to infinity in any direction and counting the number
of path segments from the given shape that the ray crosses. Starting with a count of zero, add one
each time a path segment crosses the ray from left to right and subtract one each time a path segment
crosses the ray from right to left. After counting the crossings, if the result is zero then the point is
outside.
→
←
Use two concentric ellipses to create a hollow shape.
Formatting
Page 46 of
114
BigMouth
=
GraphPaper
.
Show
(
new
(110, 40),
new
(5)) {
Shape
(
Colors
.
Red
) {
EllipsePath
(
new
(
new
(5),
new
(100, 30)));
EllipsePath
(
new
(
new
(15, 13),
new
(80, 10)));
};
};
Transforms
An affine 2D transform is represented by a sparse 3x3 matrix (3 of the elements are zero)
m11
m12
0
m21
m22
0
x
y
0
The matrix is commonly represented more compactly as:
[m11 m12 m21 m22 x y]
The following shows mirror transforms about the origin
Mirror - X
[-1 0 0 1 0 0]
Mirror - Y
[1 0 0 -1 0 0]
You can use other functions for common transforms like translation, rotation, scaling and skewing.
RotateCanvas
=
Canvas
(1", 0.5",
new
Edge
(0.5pt)) {
Canvas
{
TextHeight
:
14pt;
Transform
:
Transform
.
Rotate
(20
degrees
)
Transform
.
Translate
(30, 10);
"Rotate"
}
};
Rotate
The Nytril
®
Programming Language
Page 47 of
114
All angles are specified in radians. Convert from degrees to radians using the operator
degrees
.
Angle
=
90
degrees
;
1.5707963267948966
Below is a list of common transforms and their effects.
public
static
Transform
Translate(
x
,
y
=
null
)
=> [1 0 0 1 x y]
Translate(10, 10)
[1 0 0 1 10 10]
Translate(-10, 10)
[1 0 0 1 -10 10]
Translate(10, -20)
[1 0 0 1 10 -20]
Translate(-10, -20)
[1 0 0 1 -10 -20]
public
static
Transform
Scale(
x
,
y
=
null
)
=> [x 0 0 y 0 0]
Scale(0.5, 0.75)
[0.5 0 0 0.8 0 0]
Scale(0.75, 0.5)
[0.8 0 0 0.5 0 0]
Scale(0.5, 1.5)
[0.5 0 0 1.5 0 0]
Scale(1.5, 0.5)
[1.5 0 0 0.5 0 0]
public
static
Transform
Rotate(
double
angle
)
=> [cos(angle) size(angle) -
sin(angle) cos(angle) 0 0]
Rotate(30 degrees)
[0.9 0.5 -0.5 0.9 0 0]
Rotate(-30 degrees)
[0.9 -0.5 0.5 0.9 0 0]
Formatting
Page 48 of
114
public
static
Transform
Skew(
x
,
y
=
null
)
=> [1 tan(x) tan(y) 1 0 0]
Skew(20, 10)
[1 0.4 0.2 1 0 0]
Skew(-20, -10)
[1 -0.4 -0.2 1 0 0]
Transforms can be combined by listing them together, but the order is significant. Applying the same
list of transforms in a different order will yield different results.
Start
Translate
Rotate
Scale
Scale
Rotate
Translate
Set the
TransformFit
field to
true
to add an additional translation that brings a figure back to the origin
of its container. This is handy for chart legends, and picture rotations. It has the same effect as rotating
the object about its center, rather than its upper left corner.
RotateFit
(
name
,
fit
)
=
Canvas
(1", 0.75",
new
Edge
(0.5pt, 0, 80%)) {
Margin
:
PadR
(20pt);
Canvas
{
TextHeight
:
14pt;
Transform
:
Transform
.
Rotate
(75
degrees
);
TransformFit
:
fit
;
name
;
}
};
ShowFitComparison
=
Paragraph
{
HBox
{
RotateFit
(
"Normal"
,
false
);
RotateFit
(
"Fit"
,
true
);
}
The Nytril
®
Programming Language
Page 49 of
114
};
Normal
Fit
Use the
Transform
field to apply a transform to any element.
BackwardsCanvas
=
Canvas
{
TextHeight
:
20pt;
Transform
:
new
Transform
(
-
1, 0, 0, 1, 0, 0);
TransformFit
:
true
;
"Backwards"
};
Backwards
Use a different transform to flip the canvas vertically.
UpsideDownCanvas
=
Canvas
{
TextHeight
:
20pt;
Transform
:
new
Transform
(1, 0, 0,
-
1, 0, 0);
TransformFit
:
true
;
"Upside Down"
};
Upside Down
Use the
ClipPath
to set the clipping path of the canvas or frame
ClippedText
=
Canvas
{
var
r
=
new
Rect
(
new
(15pt),
new
(210pt, 35pt));
Canvas
{
TextHeight
:
50pt;
"Clipped Text"
;
ClipPath
:
r
;
};
Shape
(
null
) {
RectanglePath
(
r
)
};
};
Clipped Text
Clipping paths can be set to be figures of arbitrary complexity
TextArt
=
Canvas
{
TextFigure
(
new
(1));
Frame
(2.2") {
Formatting
Page 50 of
114
ClipPath
:
TextFigure
(
null
);
Paragraph
{
ParBackground
:
Colors
.
Blue
..
Colors
.
Orange
;
TextHeight
:
16;
TextColor
:
Colors
.
White
;
"Clip "
*
42;
};
}
};
Clip Clip Clip Clip Clip Clip Clip
Clip Clip Clip Clip Clip Clip Clip
Clip Clip Clip Clip Clip Clip Clip
Clip Clip Clip Clip Clip Clip Clip
Clip Clip Clip Clip Clip Clip Clip
Clip Clip Clip Clip Clip Clip Clip
Charts
A chart can be created from a series of data points using:
DocFormatter
Chart(
width
,
height
,
Border
border
=
null
)
For example:
DataPoint
RainPoint
(
RainClass
rain
)
=
new
RainPointClass
(
each0
,
rain
) {
Marker
:
Markers
.
Circle
(
Colors
.
Blue
);
};
RainPoints
=
RainPoint
(
each
Rainfall
);
RainAxis
=
ChartAxis
{(
each
CalendarMonth
.
MonthsOfTheYear
)
.
ShortName
};
RainChart
=
VBox
{
HAlign
:
Center
;
CloudTitle
;
Chart
(89%, 30%) {
Smoothing
:
0.75;
ChartType
:
ChartTypes
.
Area
;
XLabel
:
"Month"
{
TextHeight
:
14pt};
XAxis
:
RainAxis
;
ValueLabel
:
HBox
{
attribute
(
RainUnit
)
.
UnitPlural
;
TextHeight
:
14pt;
Transform
:
Transform
.
Rotate
(90
degrees
);
TransformFit
:
true
;
};
ValueAxis
:
ChartAxis
{
MinorTics
:
true
};
ChartSeries
(
new
LinearGradient
(0, 0, 0, 1, [
new
(0.0,
Colors
.
LightGray
),
new
(0.9,
Colors
.
SkyBlue
),
new
(1,
Colors
.
DarkGreen
)]),
new
(1,
Colors
.
DarkGreen
)) {
RainPoints
;
};
};
};
The Nytril
®
Programming Language
Page 51 of
114
Yearly Rainfall
Month
inches
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
0
2
4
6
8
10
12
14
16
18
20
A pie chart can be created by changing the chart type
PieChart
=
Chart
(5", 2.5") {
TextDigits
:
2;
ChartType
:
ChartTypes
.
Pie
;
XAxis
:
RainAxis
;
Legend
:
ChartLegend
{
Direction
:
Directions
.
Vertical
;
Placement
:
Placements
.
Right
};
ChartSeries
{
WedgeGap
:
2;
RainPoints
;
};
};
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
The data used for a chart can come from an equation represented by a function
Formatting
Page 52 of
114
Quadratic
(
x
)
=
x
^
2
-
50;
ParabolaChart
=
VBox
{
Paragraph
{
TextEquation
:
true
;
Symbol
(
"y"
)
Tex
.
Equals
Quadratic
(
Symbol
(
"x"
));
};
HAlign
:
Center
;
Chart
(90%, 2") {
ChartType
:
ChartTypes
.
Line
;
Marker
:
Markers
.
Square
;
XAxis
:
ChartAxis
{
Start
:
-
15;
Stop
:
15;
};
ChartSeries
{
foreach
(
var
x
in
-
10
..
10)
new
DataPoint
(
x
,
Quadratic
(
x
)) {
Reference
:
x
};
};
};
};
y
=
x
2
−
50
-15
-13
-11
-9
-7
-5
-3
-1
0
2
4
6
8
10
12
14
-50
-30
-10
10
30
50
Use the X field of the datapoint to set a specific x coordinate for a scatter plot
RandomNumber
=
Math
.
Random
(0.0
..
10.0);
RandomSeries
(
name
)
=
ChartSeries
{
Label
:
name
;
foreach
(
var
r
in
0
..
50)
new
DataPoint
(
RandomNumber
,
RandomNumber
);
};
ScatterChart
=
VBox
{
Paragraph
{
"Random Points"
;
};
HAlign
:
Center
;
Chart
(89%, 30%,
new
Edge
(0, 5)) {
ChartType
:
ChartTypes
.
Scatter
;
Legend
:
ChartLegend
(0.5pt) {
Direction
:
Directions
.
Vertical
;
Placement
:
Placements
.
Right
;
};
RandomSeries
(
"One"
);
RandomSeries
(
"Two"
);
};
The Nytril
®
Programming Language
Page 53 of
114
};
Random Points
One
Two
0
1
2
3
4
5
6
7
8
9
10
0
1
2
3
4
5
6
7
8
9
10
More than one series can be specified in the same chart
AngleRange
=
0
..
Symbolic
.
PI2
;
AllAngles
=
AngleRange
step
Symbolic
.
PI
/
12;
FuncSeries
(
Attribute
func
,
marker
)
=
ChartSeries
{
Label
:
func
.
Prototype
;
Marker
:
marker
;
foreach
(
var
a
in
AllAngles
)
new
DataPoint
(
a
,
func
.
Value
(
a
));
};
TrigChart
=
VBox
{
HAlign
:
Center
;
"Trig Functions"
;
Chart
(89%, 30%) {
ChartType
:
ChartTypes
.
Line
;
Legend
:
ChartLegend
{
Placement
:
Placements
.
Right
;
Direction
:
Directions
.
Vertical
;
};
XAxis
:
ChartAxis
{
VAlign
:
Center
;
LabelEach
:
2;
AllAngles
;
};
FuncSeries
(
attribute
Symbolic
.
Sin
,
Markers
.
Circle
);
FuncSeries
(
attribute
Symbolic
.
Cos
,
Markers
.
Square
);
}
};
Formatting
Page 54 of
114
Trig Functions
Cos(
x
)
Sin(
x
)
0
1
6
π
1
3
π
1
2
π
2
3
π
5
6
π
π
1
1
6
π
1
1
3
π
1
1
2
π
1
2
3
π
1
5
6
π
2
π
-1.0
-0.8
-0.6
-0.4
-0.2
-0.0
0.2
0.4
0.6
0.8
1.0
Use a stacked chart to compare data from different series
ActivationChart
(
type
,
rotation
,
legend
=
false
)
=
VBox
{
HAlign
:
Center
;
Paragraph
{
SpaceAfter
:
8pt;
type
;
};
BaseChart
(
type
,
rotation
,
legend
);
};
ActivationCharts
(
left
,
right
)
=
Paragraph
{
SpaceAfter
:
8pt;
ActivationChart
(
left
, 45
degrees
);
Space
*
5;
ActivationChart
(
right
,
null
)
};
ActivationGallery
=
Block
{
ActivationCharts
(
ChartTypes
.
Line
,
ChartTypes
.
Area
);
ActivationCharts
(
ChartTypes
.
Column
,
ChartTypes
.
Bar
);
ActivationCharts
(
ChartTypes
.
StackedColumn
,
ChartTypes
.
StackedBar
);
ActivationCharts
(
ChartTypes
.
StackedColumn100
,
ChartTypes
.
StackedBar100
);
ActivationChart
(
ChartTypes
.
Doughnut
,
null
,
true
)
};
The Nytril
®
Programming Language
Page 55 of
114
Line
pcDNA4
TW
p65
Both
dWR
d194
0
100
200
300
400
Area
pcDNA4
TW
p65
Both
dWR
d194
0
100
200
300
400
Column
pcDNA4
TW
p65
Both
dWR
d194
0
100
200
300
400
Bar
0
100
200
300
400
pcDNA4
TW
p65
Both
dWR
d194
Formatting
Page 56 of
114
StackedColumn
pcDNA4
TW
p65
Both
dWR
d194
0
100
200
300
400
500
600
StackedBar
0
100
200
300
400
500
600
pcDNA4
TW
p65
Both
dWR
d194
StackedColumn100
pcDNA4
TW
p65
Both
dWR
d194
0
10
20
30
40
50
60
70
80
90
100
StackedBar100
0
10
20
30
40
50
60
70
80
90
100
pcDNA4
TW
p65
Both
dWR
d194
The Nytril
®
Programming Language
Page 57 of
114
Doughnut
% IL7
% IL8
Tables
A table can be created from a fixed set of values using:
DocFormatter
Table(
Border
border
=
null
,
Border
cellborder
=
null
,
Column
[]
columns
=
null
)
For example:
RainfallTable
=
Table
(
new
Edge
(1, 0,
Colors
.
LightGray
),
PadLR
(3), [0.8", 1", 1"]) {
TextDigits
:
1;
TextHeight
:
9pt;
NytrilStyle
.
HeaderRow
{
Cell
(
null
, 3) {
ParAlignment
:
Center
;
"Rainfall"
};
};
Row
{
Background
:
Colors
.
DarkGray
;
TextColor
:
Colors
.
White
;
"Month"
;
"Value"
;
"Error"
};
RainRow
(
each
Rainfall
)
};
Rainfall
Month
Value
Error
January
12.0 inches
-1.0 +1.0
February
13.2 inches
-1.0 +1.0
March
14.6 inches
-1.0 +1.2
April
18.5 inches
-1.0 +1.0
May
12.6 inches
-0.6 +0.4
June
7.2 inches
-1.0 +1.0
July
4.0 inches
-1.0 +1.0
August
4.7 inches
-0.4 +1.2
September
5.0 inches
-1.0 +1.0
October
6.0 inches
-1.0 +1.0
November
12.6 inches
-1.0 +1.0
December
15.1 inches
-1.0 +1.0
Table cells can contain any type of formatter, including other tables.
Attribute
[]
TrigFunctions
=
[
attribute
Symbolic
.
Sin
,
attribute
Symbolic
.
Cos
,
attribute
Symbolic
.
Tan
];
TrigRow
(
angle
)
=
Row
{
HAlign
:
Center
;
Formatting
Page 58 of
114
VAlign
:
Center
;
angle
;
foreach
(
var
f
in
TrigFunctions
) {
f
.
Value
(
angle
);
}
};
Angles
=
0
..
Symbolic
.
PI
/
2
step
Symbolic
.
PI
/
12;
TrigTable
=
Table
(
new
Edge
(1, 0,
Colors
.
LightGray
),
PadAll
(1), [1", 1.5"]) {
TextHeight
:
10pt;
Row
{
TextHeight
:
14pt;
Background
:
95%;
Cell
(
null
, 4) {
ParAlignment
:
Center
;
"Trig Functions"
;
}
};
Row
{
VAlign
:
Center
;
HAlign
:
Center
;
Background
:
70%;
TextColor
:
Colors
.
White
;
TextHeight
:
12pt;
"Angle"
;
foreach
(
var
f
in
TrigFunctions
) {
Span
{
f
.
Prototype
;
Tip
:
f
};
}
};
TrigRow
(
each
Angles
)
};
Trig Functions
Angle
Sin
(
x
)
Cos
(
x
)
Tan
(
x
)
0
0
1
0
1
12
π
0.25881904510252074
0.9659258262890683
0.2679491924311227
1
6
π
1
2
3
2
1
3
1
4
π
1
2
1
2
1
1
3
π
3
2
1
2
3
5
12
π
0.9659258262890683
0.258819045102521
3.7320508075688736
1
2
π
1
0
∞
Trees
A tree is a structure comprising nested nodes, each one having its own branch length.
MyTree
=
new
Node
(
"Root"
, 0.5) {
new
Node
(
"A"
, 1) {
new
Node
(
"A1"
, 0.3);
new
Node
(
"A2"
, 0.4);
};
new
Node
(
"B"
, 2);
The Nytril
®
Programming Language
Page 59 of
114
new
Node
(
"C"
, 1);
};
ShowTree
=
TreeBox
(3",
null
) {
Default
:
new
Node
(
null
) {
Curvature
:
50%;
Bevel
:
50%;
Marker
:
Markers
.
Circle
(
Colors
.
Red
);
};
Root
:
MyTree
;
};
Root
A
A1
A2
B
C
Some or all of a tree's contents may be calculated.
Circle
(
r
,
fill
)
=
Shape
(
fill
) {
EllipsePath
(
new
(
new
(0),
new
(
r
)))
};
NumberNode
(
i
)
=
new
Node
(
Radical
{
i
},
Sqrt
(
i
)) {
Marker
:
Circle
(
i
*
5,
new
Color
((
i
*
15)
%
, 0, 0));
Stroke
:
new
Stroke
(
i
,
new
Color
(0, 0, (
i
*
15)
%
),
LineStyles
.
Solid
,
LineCaps
.
Round
);
};
CalcTree
=
new
Node
{
Bevel
:
80%;
NodeGap
:
10pt;
new
Node
(
"A"
);
new
Node
(
"B"
) {
NumberNode
(
each
1
..
6);
};
new
Node
(
"C"
);
};
ShowTree2
=
TreeBox
(3", 2") {
Root
:
CalcTree
;
};
A
B
1
2
3
4
5
6
C
A tree's contents may be generated recursively.
Attribute
[]
TreeMarkers
=
[
attribute
Markers
.
Circle
,
attribute
Markers
.
Square
,
attribute
Markers
.
TriangleUp
,
attribute
Markers
.
Diamond
];
Formatting
Page 60 of
114
TreeColors
=
[
Colors
.
Red
,
Colors
.
Green
,
Colors
.
Purple
,
Colors
.
Blue
];
MaxDepth
=
TreeMarkers
.
Length
-
1;
RecurseNode
(
depth
,
number
)
=
new
Node
(
"
{0}{1}
"
(
'A'
+
depth
,
number
), 1
/
(
depth
+
1)) {
Stroke
:
new
Stroke
(
MaxDepth
-
depth
+
1,
depth
*
25%);
NodeGap
:
6pt;
if
(
depth
>
0) {
Bevel
:
depth
*
0.25;
Curvature
:
depth
*
0.25;
}
else
Bevel
:
100%;
Marker
:
TreeMarkers
[
depth
]
.
Value
(
TreeColors
[
depth
]);
if
(
depth
<
MaxDepth
)
RecurseNode
(
depth
+
1,
each
0
..
(
depth
+
1));
};
ShowTree3
=
TreeBox
(
null
, 1.5") {
Placement
:
Placements
.
Bottom
;
TextHeight
:
10pt;
Root
:
RecurseNode
(0, 0);
};
A0
B0
C0
D0
D1
D2
D3
C1
D0
D1
D2
D3
C2
D0
D1
D2
D3
B1
C0
D0
D1
D2
D3
C1
D0
D1
D2
D3
C2
D0
D1
D2
D3
The structure of a math expression may be shown using the function:
public
object
.GetExpressionTree
For example:
Equation
=
((
x
-
y
*
2)
/
sigma
)
^
2
+
5;
ShowEquation
=
HBox
(
null
,
null
,
new
Edge
(0.5, 8pt)) {
Separation
:
16pt;
VAlign
:
Center
;
Paragraph
{
HBox
{
VAlign
:
Center
;
"Equation = "
;
Equation
;
};
};
TreeBox
(3",
null
) {
Default
:
new
Node
(
null
) {
Curvature
:
20%;
Bevel
:
20%;
NodeGap
:
10pt;
};
Root
:
Equation
.
GetExpressionTree
;
The Nytril
®
Programming Language
Page 61 of
114
};
};
Equation =
−
x
σ
2
+
5
Add
Power
Divide
Multiply
-1
x
σ
2
5
Tree structures can be read directly from a data file.
ShowTrees
=
Block
{
ShowTreeName
(
each
TreeFile
.
Trees
);
};
tree name
tree0
A
B
tree1
A
B
C
tree3
A
B
C
D
tree4
F
A
B
E
C
D
tree5
tree6
tree7
A
B
C
D
Formatting
Page 62 of
114
tree8
F
A
B
E
C
D
tree9
F
A
B
E
C
D
Tree structures can be formatted in a variety of ways using
Bevel
and
Curvature
settings
FormattedTrees
=
Block
{
ShowNexusTree
(
TreeFile
.
FindTree
(
"tree4"
));
ShowNexusTree
(
TreeFile
.
FindTree
(
"tree5"
));
};
tree4
Curvature
Bevel
0%
50%
100%
0
F
A
B
E
C
D
F
A
B
E
C
D
F
A
B
E
C
D
50%
F
A
B
E
C
D
F
A
B
E
C
D
F
A
B
E
C
D
100%
F
A
B
E
C
D
F
A
B
E
C
D
F
A
B
E
C
D
tree5
Curvature
Bevel
0%
50%
100%
0
50%
100%
Creating a Document
A document is made by creating a new class that inherits
DocumentEntry
. Overload the function
GetDocument
and add new content.
The Nytril
®
Programming Language
Page 63 of
114
class
HelloDocClass
:
DocumentEntry
{
Constructor
{
super
.
Constructor
(
#ab6ec337-2885-4777-b223-855509822fa5#
,
"Hello"
);
}
override
GetDocument
=
Document
{
"Hello World"
;
};
}
Formatting Properties
Use a wide variety of formatting properties to program the look of the content
in your document. Together with the revision mechanism, you can create
named styles and combine them with your data to create beautiful, accurate
documents.
Revisions are used to alter the typesetting of any Span or Paragraph.
FormatPar
=
Span
{
TextFamily
:
TextFamilies
.
TimesNewRoman
;
"The following text is: "
;
}
;
ShowRevision
=
Block
{
FormatPar
{
Span
{
TextHeight
:
120%;
"Large"
}};
FormatPar
{
Span
{
Bold
;
"Bold"
}};
FormatPar
{
Span
{
Italic
;
"Italic"
}};
FormatPar
{
Span
{
TextHeight
:
120%;
Bold
;
Italic
;
"Large, Bold, Italic"
}};
};
The following text is:
Large
The following text is:
Bold
The following text is:
Italic
The following text is:
Large, Bold, Italic
If you want to change color of the text in a Span, use the
TextColor
property.
ShowTextColor
=
Paragraph
{
"The following item is "
;
Span
{
TextColor
:
Colors
.
Red
;
"important"
;
};
" to note. "
;
};
The following item is
important
to note.
The background color of text can be set with the
TextBackground
property.
ShowTextBackground
=
Paragraph
{
"The following item is "
;
Span
{
Formatting
Page 64 of
114
TextBackground
:
Colors
.
Yellow
;
"marked"
;
};
" with a highlighter. "
;
};
The following item is
marked
with a highlighter.
Make the font italic by setting the
TextItalic
property to true.
ShowItalic
=
Paragraph
{
"Make "
;
Span
{
TextItalic
:
true
;
"sure"
;
};
" to read the instructions. "
;
};
Make
sure
to read the instructions.
Apply the special Italic revision directly to a string for a more concise expression.
ShowItalic2
=
Paragraph
{
"Make "
;
Italic
"sure"
;
" to read the instructions. "
;
};
Make
sure
to read the instructions.
Make the font bold by setting the
TextWeight
property to Bold.
ShowBold
=
Paragraph
{
"Use "
;
Span
{
TextWeight
:
Bold
;
"extreme"
;
};
" caution. "
;
};
Use
extreme
caution.
Apply the special Bold revision directly to a string for a more concise expression.
ShowBold2
=
Paragraph
{
"Use "
;
Bold
"extreme"
;
" caution. "
;
};
Use
extreme
caution.
Use the
TextFace
property to change the font face to one of the built-in styles.
ShowFace
=
Block
{
"Normal Text"
;
Span
{
TextFace
:
TextFaces
.
Mono
;
The Nytril
®
Programming Language
Page 65 of
114
"Monospaced Text"
;
};
};
Normal Text
Monospaced Text
Use the
TextFamily
property to change the font family to a specific installed family.
ShowFamily
=
Paragraph
{
TextFamily
:
TextFamilies
.
LibertinusSerif
;
"Classic font for journal articles"
;
};
Classic font for journal articles
Use the
TextUnderline
property to underline text in a variety of styles.
ShowUnderline
=
Paragraph
{
Separator
:
Space
*
3;
foreach
(
var
u
in
TextUnderlines
) {
Span
{
TextUnderline
:
u
;
u
.
Name
;
};
}
};
None
Single
Words
Dotted
Dashed
DotDash
DotDotDash
Thick
Double
Wave
WavyDouble
Use the
TextStrike
property to strike-out sections of text.
StrikeText
=
Paragraph
{
Separator
:
Space
*
3;
foreach
(
var
s
in
TextStrikes
) {
Span
{
TextStrike
:
s
;
s
.
Name
;
};
}
};
None
Single
Double
You can control the mixture of uppercase and lowercase letters with the
TextCase
property.
ShowTextCase
=
Table
(
null
,
PadLR
(3), [
Column
.
Fit
(50%)]) {
foreach
(
var
tc
in
TextCases
) {
Row
{
tc
.
Name
;
Span
{
TextCase
:
tc
;
"hello Hello HELLO!"
;
};
};
}
};
Formatting
Page 66 of
114
None
hello Hello HELLO!
AllUpper
HELLO HELLO HELLO!
AllLower
hello hello hello!
WordUpper
Hello Hello Hello!
FirstUpper
Hello Hello HELLO!
FirstLower
hello Hello HELLO!
SmallCaps
hello Hello HELLO!
Change how much space is allocated between letters with the
TextLetterSpace
property.
ShowTextLetterSpace
=
Block
{
foreach
(
var
space
in
1
..
5) {
Paragraph
(
null
, [5%]) {
space
;
Tab
;
Span
{
TextLetterSpace
:
space
;
"The quick brown fox"
;
};
Span
{
TextColor
:
Colors
.
Green
;
" jumped over the lazy dog."
};
};
}
};
1
The quick brown fox
jumped over the lazy dog.
2
The quick brown fox
jumped over the lazy dog.
3
The quick brown fox
jumped over the lazy dog.
4
The quick brown fox
jumped over the lazy dog.
5
The quick brown fox
jumped over the lazy dog.
Text can be compressed or stretched with the
TextStretch
property.
ShowLetterScale
=
Block
{
foreach
(
var
stretch
in
[50%, 75%, 100%, 150%, 200%]) {
Paragraph
(
null
, [8%]) {
stretch
;
Tab
;
Span
{
TextStretch
:
stretch
;
"Stretch"
;
};
Span
{
TextColor
:
Colors
.
Green
;
" -> goal."
};
}
}
};
50%
Stretch
-> goal.
75%
Stretch
-> goal.
100%
Stretch
-> goal.
150%
Stretch
-> goal.
200%
Stretch
-> goal.
Insert content between elements with the
Separator
property.
ShowSeparator
=
Paragraph
{
Separator
:
", "
;
The Nytril
®
Programming Language
Page 67 of
114
1
..
5
step
1;
};
1, 2, 3, 4, 5
Change the final separator in the revision with the
LastSeparator
property.
ShowLastSeparator
=
Paragraph
{
Separator
:
", "
;
LastSeparator
:
" and "
;
1
..
5
step
1;
};
1, 2, 3, 4 and 5
To handle lists that have exactly two items, use the
PairSeparator
property.
OxfordList
=
Span
{
Separator
:
", "
;
LastSeparator
:
", and "
;
// Oxford comma
PairSeparator
:
" and "
;
};
ShowLists
=
Block
{
OxfordList
{1};
OxfordList
{1; 2};
OxfordList
{1; 2; 3};
};
1
1 and 2
1, 2, and 3
Number Formatting
Use a large selection of different number formatting properties to add data to
your documents.
To show an integer, simply include the literal number as one of the elements inside a span.
IntegerLiteral
=
Span
{
42
;
};
42
Functions that return integers or variables containing integers, like the function X shown here, will be
formatted the same way.
X
(
i
)
=
i
*
i
+
3;
IntegerVariable
=
Span
{
"The output of X(5) is "
;
X
(5);
};
Formatting
Page 68 of
114
The output of X(5) is 28
To format an integer in hexadecimal, change the
TextRadix
to 16.
IntegerHexadecimal
=
Span
{
TextRadix
:
16
;
129579;
};
1fa2b
To have the hex digits shown in upper-case, change the
TextCase
property to AllUpper.
IntegerHexadecimalUpper
=
Span
{
TextRadix
:
16;
TextCase
:
AllUpper
;
671277;
};
A3E2D
To format a number in binary, use 2 as the
TextRadix
.
IntegerBinary
=
Span
{
TextRadix
:
2
;
127;
};
1111111
Use the
TextNumPadding
property to set the minimum width of a number. This is handy for text
sorting and creating tables with aligned numbers.
IntegerHexadecimal4
=
Block
{
TextRadix
:
16;
TextNumPadding
:
4
;
4;
27;
12245;
};
0004
001b
2fd5
To format an integer with a group separator, set the
TextGroup
property to true.
IntegerGroup
=
Span
{
TextGroup
:
true
;
1234567.89;
};
1,234,567.89
The Nytril
®
Programming Language
Page 69 of
114
Use the
TextCulture
property to ensure the formatting is correct for the intended readership.
IntegerGroupCulture
=
Span
{
TextCulture
:
CultureInfo
.
FindCulture
(
"de-DE"
);
TextGroup
:
true
;
8912345.67;
};
8.912.345,67
As with integers, to a format a number of type
double
, include it as an element in the revision.
DoubleFormatting
=
Span
{
4325.1245
;
};
4325.1245
Formatting a return value from a function works the same way.
DoubleReturn
=
Span
{
Math
.
Sqrt
(1
+
1)
;
};
1.4142135623730951
Use the
TextDigits
property to fix the number of fractional digits in the number.
DoubleDigits
=
Span
{
TextDigits
:
3
;
Math
.
PI
;
};
3.142
Set the
TextPercent
property to true to show numbers as percentages.
Percentage
=
Block
{
TextPercent
:
true
;
0.04;
1.5;
};
4%
150%
Set
TextSignificant
to true, to make TextDigits refer to 'significant' figures, rather than decimal digits.
SignificantDigits
=
Block
{
TextSignificant
:
true
;
TextDigits
:
3
;
// 3 significant figures
4325.1245;
5.4193;
0.0006427;
1.215e10;
1.2e-10;
Formatting
Page 70 of
114
};
4330
5.42
0.000643
12200000000
0.000000000120
Format the number in scientific notation by setting
TextScientific
to true.
ScientificNotation
=
Span
{
TextScientific
:
true
;
TextDigits
:
2;
175_000;
};
1.75x10
5
Notice that the
TextSignificant
property controls the total number of significant figures with scientific
notation.
ScientificNotationSig
=
Span
{
TextScientific
:
true
;
TextSignificant
:
true
;
TextDigits
:
2
;
8_175_400;
};
8.2x10
6
You can use a custom tab stop in a paragraph to align numbers on decimal point.
readonly
AlignedPar
=
Paragraph
(
null
, [
new
(5%,
Decimal
)]);
AlignedPars
=
Block
{
AlignedPar
{
Tab
; 1.2 };
AlignedPar
{
Tab
; 123.99};
AlignedPar
{
Tab
; 0.5544};
};
1.2
123.99
0.5544
Use the
TextDenominator
property to convert a number to a fraction, with a maximum denominator,
in lowest terms.
Denominator
=
Block
{
TextDenominator
:
16
;
0.125;
0.5;
12.75;
1.04125;
};
The Nytril
®
Programming Language
Page 71 of
114
1
8
1
2
12
3
4
1
1
16
Math Formatting
Create professionally typeset math equations using a small number of
formatting primitives.
Use the
Symbol
function to create objects that behave like algebraic symbols. The second argument is
the tip that pops up when the mouse is hovered over the symbol.
x
=
Symbol
(
"x"
,
"The independent variable 'x'"
);
y
=
Symbol
(
"y"
,
"The independent variable 'y'"
);
RaisePower
(
a
,
b
)
=
Span
{
a
;
" raised to the power of "
;
b
;
" is "
;
a
^
b
;
};
Powers
=
Block
{
RaisePower
(2, 5);
// Perform calculation with numbers
RaisePower
(
x
,
y
);
// Create formula
};
2 raised to the power of 5 is 32
x
raised to the power of
y
is
x
y
The independent variable 'y'
Create several different types of common fractions with the
Fraction
formatter.
FormatFraction
=
Fraction
{
x
;
y
+
1;
};
x
y
+
1
Format the fraction with a diagonal slash by setting the diagonal argument to true.
SlantedFraction
=
Fraction
(
true
) {
x
;
y
^
2;
};
x
y
2
Create a more compact fraction layout by setting the compact argument to true.
ThreeQuarters
=
Fraction
(
false
,
true
) {3; 4};
Formatting
Page 72 of
114
CompactFraction
=
Span
{
"Add "
;
ThreeQuarters
;
" of a cup of flour. "
;
};
Add
3
4
of a cup of flour.
For numeric fractions, get a more concise expression by using a rational number.
OneHalf
=
1
over
2;
CompactShortcut
=
Span
{
"Add "
;
OneHalf
;
" teaspoon of sugar and stir. "
;
};
Add
1
2
teaspoon of sugar and stir.
Change the default rational number display to a diagonal bar by settting the
TextDiagonal
property to
true.
CompactSlanted
=
Span
{
TextDiagonal
:
true
;
"Mix in "
;
4
over
3;
" tablespoons of warm water if the dough is too firm. "
;
};
Mix in
1
1
3
tablespoons of warm water if the dough is too firm.
Add a subscript to a symbol by using the
sub
operator.
X1
=
x
sub
1;
x
1
Use the
sup
operator in the same way to make superscripts.
E
=
Symbol
(
"E"
,
"Energy"
);
m
=
Symbol
(
"m"
,
"Mass"
);
c
=
Symbol
(
"c"
,
"The speed of light"
);
MassEnergy
=
Span
{
E
;
Tex
.
Equals
;
m
;
c
sup
2};
E
=
m
c
2
The speed of light
Square-root symbols can be created with the
Radical
formatter.
Solution
=
Paragraph
{
"The solution is: "
;
Tex
.
pm
;
Radical
{
x
;
Tex
.
Plus
;
2;
The Nytril
®
Programming Language
Page 73 of
114
};
};
The solution is:
±
x
+
2
Change the degree of the radical by setting the
Degree
property
V
=
Symbol
(
"V"
,
"Volume"
);
Cube
=
Paragraph
{
"The edge of a cube of volume "
;
V
;
" is given by "
;
Radical
{
V
;
Degree
:
3
;
};
};
The edge of a cube of volume
V
is given by
V
3
The
Nary
is the most complex formatter covering a wide variety of math expressions.
NaryComponents
=
Nary
{
Operator
:
"Operator"
;
PreUpper
:
"pre-upper"
;
PreLower
:
"pre-lower"
;
Upper
:
"upper"
;
Lower
:
"lower"
;
"[Body Elements]"
;
};
[Body Elements]
Operator
pre-upper
pre-lower
upper
lower
Set the
Operator
property to one of the built-in symbols appropriate for your expression.
s
=
Symbol
(
"s"
,
"Zeta argument (complex number)"
);
n
=
Symbol
(
"n"
,
"Integer"
);
ZetaSum
=
Nary
{
Operator
:
Tex
.
sum
;
TextStacked
:
true
;
Fraction
{1;
n
^
s
};
};
1
n
s
Use the
Upper
and
Lower
properties to set the superscript and subscript of the Operator.
InverseSquareIntegral
=
Paragraph
{
TextEquation
:
true
;
Symbol
(
"f"
);
"("
;
x
;
")"
;
Tex
.
Equals
;
Nary
{
Operator
:
Tex
.
Integral1
;
Upper
:
Tex
.
infty
;
Formatting
Page 74 of
114
Lower
:
x
Tex
.
Equals
1
;
};
Fraction
{
1;
x
^
2;
};
Tex
.
nbsp
;
Tex
.
derivative
;
x
;
};
f
(
x
)
=
∞
x
=
1
1
x
2
d
x
Place the superscripts and subscripts above and below the Operator by setting the
TextStacked
property to true.
StackedNary
=
InverseSquareIntegral
{
TextStacked
:
true
;
};
f
(
x
)
=
∞
x
=
1
1
x
2
d
x
Use
PreUpper
and
PreLower
to specify the operator prefixes.
Isotope
(
weight
,
element
,
name
)
=
Nary
{
PreUpper
:
weight
;
PreLower
:
element
;
Operator
:
HBox
{
Margin
:
PadL
(0.1%);
TextHeight
:
150%;
name
};
};
Thorium232
=
Isotope
(232, 90,
"Th"
);
Th
232
90
The child elements of an Nary formatter are shown to the right of the Operator.
p
=
Symbol
(
"p"
,
"Prime number"
);
ZetaProduct
=
Nary
{
TextStacked
:
true
;
Operator
:
Tex
.
prod
;
Fraction
{
p
^
s
;
p
^
s
-
1;
};
};
p
s
p
s
−
1
If you set the
TextEquation
property to true, the math font is used for all of the symbols, and the
expression will stay together across line breaks.
The Nytril
®
Programming Language
Page 75 of
114
LineEquation
=
Paragraph
{
TextEquation
:
true
;
TextStacked
:
true
;
};
ZetaEquivalence
=
LineEquation
{
Tex
.
zeta
;
"("
;
s
;
")"
;
Tex
.
Equals
;
ZetaSum
;
Tex
.
Equals
;
ZetaProduct
;
};
ζ
(
s
)
=
1
n
s
=
p
s
p
s
−
1
Here is an example of a loop inside a revision, to generate a combination of polynomial terms.
Polynomial
(
int
degree
)
=
LineEquation
{
for
(
var
i
=
degree
;
i
>=
0;
--
i
)
{
Symbol
(
'a'
+
(
degree
-
i
));
if
(
i
>
0) {
x
^
i
;
Tex
.
Plus
;
}
}
};
FifthDegree
=
Polynomial
(5);
a
x
5
+
b
x
4
+
c
x
3
+
d
x
2
+
e
x
+
f
Use the
Bracket
property to wrap an expression in scaled brackets.
Term
(
index
)
=
Fraction
{
x
^
index
;
index
;
Tex
.
factorial
};
Series
=
HBox
{
Bracket
:
Brackets
.
Round
;
Separator
:
Tex
.
Plus
;
LastSeparator
:
Tex
.
Plus
Tex
.
cdots
Tex
.
Plus
;
1;
Term
(
each
[1, 2, 3,
n
]);
// A term for each item in the array
};
EulerNumber
=
LineEquation
{
Symbolic
.
E
^
x
;
Tex
.
Equals
;
Nary
{
Operator
:
Tex
.
lim
;
Lower
:
n
Tex
.
rightarrow
Tex
.
infty
;
};
Series
;
};
e
x
=
lim
n
→∞
1
+
x
1
!
+
x
2
2
!
+
x
3
3
!
+
⋯
+
x
n
n
!
Choose from a wide variety of arrow and bracket styles.
Formatting
Page 76 of
114
VerticalBrackets
=
HBox
{
Separation
:
20;
VBox
{
Bracket
:
Brackets
.
RightArrow
.
Over
;
"Over"
};
VBox
{
Bracket
:
Brackets
.
RightArrow
.
Under
;
"Under"
};
VBox
{
Bracket
:
Brackets
.
Bar
.
Top
;
"bar above"
};
VBox
{
Bracket
:
Brackets
.
FlatCurly
.
Bottom
;
"flat curly below"
};
VBox
{
Bracket
:
Brackets
.
Round
.
Top
;
"round above"
};
};
Over
Under
bar above
flat curly below
round above
Enclose large expressions in horizontal or vertical brackets.
BracketEnclosure
=
HBox
{
Bracket
:
Brackets
.
FlatRound
.
TopBottom
;
Separation
:
24pt;
VAlign
:
Center
;
HBox
{
Bracket
:
Brackets
.
Round
;
"parenthesis"
};
HBox
{
Bracket
:
Brackets
.
Square
;
"square brackets"
};
VBox
{
Bracket
:
Brackets
.
FlatCurly
.
Left
;
"Topic
{0}
"
(
each
1
..
3);
};
};
(
parenthesis
)
[
square brackets
]
Topic 1
Topic 2
Topic 3
Here is a complete list of the bracket types.
TestAllBrackets
=
Paragraph
{
Separator
:
Space
*
4;
foreach
(
var
b
in
attribute
Brackets
) {
HBox
{
Bracket
:
new
BracketGroup
(
b
.
Value,
null
,
b
.
Value,
null
);
VBox
{
Bracket
:
new
BracketGroup
(
null
,
b
.
Value,
null
,
b
.
Value);
NytrilStyle
.
PropName
(
b
);
};
};
}
};
None
Angle
Bar
Curly
FlatCurly
CurvedAngle
Round
FlatRound
Square
Tortoise
DoubleAngle
DoubleBar
DoubleRound
DoubleSquare
DoubleTortoise
RightArrow
LeftArrow
RightHarp
LeftHarp
The Nytril
®
Programming Language
Page 77 of
114
Use the directional member of a bracket to place arrows in specific locations.
Decay
(
type
)
=
VBox
(
null
,
null
,
PadLR
(6pt)) {
Bracket
:
Brackets
.
RightArrow
.
Under
;
Margin
:
PadLR
(4pt);
VAlignment
:
Top
;
HAlign
:
Center
;
Span
{
Space
*
2;
type
;
Space
*
2};
};
ThoriumDecay
=
HBox
{
VAlign
:
Center
;
Thorium232
;
Decay
(
Tex
.
alpha
);
Isotope
(228, 88,
"Ra"
);
Decay
(
Tex
.
beta
sup
Tex
.
Minus
);
Isotope
(228, 89,
"Ac"
);
};
Th
232
90
α
Ra
228
88
β
−
Ac
228
89
Matrices are created with the
MatrixBox
formatter. They contain a list of rows and cells automatically
sized to fit the contents.
PlainMatrix
=
MatrixBox
{
VAlign
:
Center
;
HAlign
:
Center
;
ColumnGap
:
6pt;
Row
{1;
Fraction
{
Tex
.
pi
; 2}; 3};
Row
{4; 1;
Symbolic
.
Sqrt
(
x
+
2)};
Row
{
y
+
5; 8; 1}
};
WithBraces
=
HBox
{
Separation
:
16pt;
PlainMatrix
;
PlainMatrix
{
Bracket
:
Brackets
.
FlatRound
};
PlainMatrix
{
Bracket
:
Brackets
.
Square
};
};
1
π
2
3
4
1
x
+
2
y
+
5
8
1
1
π
2
3
4
1
x
+
2
y
+
5
8
1
1
π
2
3
4
1
x
+
2
y
+
5
8
1
Paragraph Formatting
Paragraphs wrap content inside the body of a document or frame. They are the
fundamental container for free flowing text in your documents. A paragraph
inherits the properties of a Span formatter, and adds borders, tabs and
indenting.
Let's review some basics. A
Block
contains Paragraph or Table elements. If those elements are not
Formatting
Page 78 of
114
already Paragraphs, they will be automatically placed inside a Paragraph. A Block can have formatting
properties, which will serve as the default properties of the child elements.
SimpleBlock
=
Block
{
// Explicit paragraph
Paragraph
{
"Paragraph One"
;
};
// Non-paragraph elements turned into a paragraphs
"Paragraph Two"
;
Span
{
Bold
;
Math
.
Sqrt
(2)
+
1};
};
Paragraph One
Paragraph Two
2.414213562373095
A Block can be included inside another Block, but this does not create a nested structure. Instead, the
parent Block will simply include the child Block's formatted content.
NestedBlock
=
Block
{
TextColor
:
Colors
.
Red
;
Block
{
"Line 1"
;
};
"Line 2"
;
Block
{
TextColor
:
Colors
.
Blue
;
"Line 3"
;
};
};
Line 1
Line 2
Line 3
Default block format
Overridden format
A
Paragraph
is a formatter that puts its child elements end-to-end into horizontal lines. The text will
wrap at the edge of the available space, and may continue onto the next page of the document.
Success
=
Paragraph
{
"I've missed more than 9000 shots in my career. "
;
"I've lost almost 300 games. "
;
"26 times I've been trusted "
;
"to take the game winning shot and missed. "
;
"I've failed over and over and over again in my life. "
;
"And that is why I succeed. "
;
"–Michael Jordan"
;
};
I've missed more than 9000 shots in my career. I've lost almost 300 games. 26 times
I've been trusted to take the game winning shot and missed. I've failed over and over
and over again in my life. And that is why I succeed. –Michael Jordan
Use the
LeftIndent
,
RightIndent
, and
FirstIndent
properties to control the margins of the paragraph.
Notice that you may revise an existing paragraph with new properties, without changing the original.
The Nytril
®
Programming Language
Page 79 of
114
Greatness
=
Paragraph
{
"Be not afraid of greatness. "
;
"Some are born great, "
;
"some achieve greatness, "
;
"and others have greatness thrust upon them. "
;
};
Quote
=
Block
{
Greatness
{
RightIndent
:
10pt;
LeftIndent
:
16pt;
FirstIndent
:
-
8pt
;
// Relative to LeftIndent
TextHeight
:
120%;
};
Italic
"― William Shakespeare, Twelfth Night"
;
};
Be not afraid of greatness. Some are born great, some
achieve greatness, and others have greatness thrust
upon them.
― William Shakespeare, Twelfth Night
Alignment of the text can be controlled with the
ParAlignment
property.
SmallBlock
=
Block
{
Paragraph
{
ParAlignment
:
Left
;
"Left"
};
Paragraph
{
ParAlignment
:
Center
;
"Center"
};
Paragraph
{
ParAlignment
:
Right
;
"Right"
};
};
Left
Center
Right
The Justify alignment stretches the spaces in the line so that it fits evenly on the right.
JustifiedBlock
=
Paragraph
{
ParAlignment
:
Justify
;
"As the light changed from red to green to yellow and back to red again, "
;
"I sat there thinking about life. "
;
"Was it nothing more than a bunch of honking and yelling? "
;
"Sometimes it seemed that way. "
;
Tex
.
EmDash
;
" Jack Handey"
;
};
As the light changed from red to green to yellow and back to
red again, I sat there thinking about life. Was it nothing
more than a bunch of honking and yelling? Sometimes it
seemed that way. — Jack Handey
The tabstops argument is an array of TabStop objects that determine how the tab character is
interpreted inside a paragraph.
TabStop
[]
TabList
=
[
5%,
// Left align (default)
new
(20%,
TabTypes
.
Bar
),
// Place vertical bar (no stop)
Formatting
Page 80 of
114
new
(30%,
TabTypes
.
Center
),
// Center text around tab
new
(60%,
TabTypes
.
Decimal
),
// Line up decimal point at tab
new
(95%,
TabTypes
.
Right
,
TabLeaders
.
Dot
),
// Right align at tab
];
TabStopExample
=
Block
{
Paragraph
(
null
,
TabList
) {
Tab
;
"Left"
;
Tab
;
"Center"
;
Tab
;
"3.1415"
;
Tab
;
"Right"
;
};
Paragraph
(
null
,
TabList
) {
Tab
;
"Left Align"
;
Tab
;
"Center Align"
;
Tab
;
"527.10"
;
Tab
;
"Right Align"
;
};
};
Left
Center
3.1415
....................................................
Right
Left Align
Center Align
527.10
...............................................
Right Align
A
Frame
is a rectangular box that can contain Paragraphs and Tables, but it acts like a large character
when placed inside a Paragraph.
FrameExample
=
Paragraph
{
"Quote "
;
// Acts like a big single character
Frame
(30%,
null
,
new
Edge
(1, 4pt)) {
"Luck is what happens when preparation meets opportunity."
;
"—Seneca "
;
};
" of the day. "
;
};
Quote
Luck is what happens when
preparation meets opportunity.
—Seneca
of the day.
Large 'character' in the text
A
ListSpan
formatter can be used to create a numbered list inside a paragraph with a variety of
numbering styles. Notice that the "Topics" array variable is automatically expanded inside the revision
to become a part of the numbered list.
Topics
=
[
"Point one"
,
"Point two"
,
"Point three"
];
NumberedSpan
=
Paragraph
{
"Main discussion points: "
;
ListSpan
(
@
Enumerators
.
NumberParens
) {
Separator
:
"; "
;
End
:
DotSpace
;
Topics
;
};
};
Main discussion points:
(1)
Point one;
(2)
Point two;
(3)
Point three.
Paragraphs have an optional background color which can be set with the
ParBackground
property.
HeaderPar
=
Paragraph
{
ParBackground
:
Colors
.
Blue
;
TextColor
:
Colors
.
White
;
The Nytril
®
Programming Language
Page 81 of
114
ParAlignment
:
Center
;
Bold
;
"Header"
;
};
Header
Add extra space before the start of a paragraph using the
SpaceBefore
property.
ParSpaceBefore
=
Block
{
Bold
"Header"
;
Paragraph
{
"First line"
;
SpaceBefore
:
200%
;
};
};
Header
First line
Space before the paragraph
Add extra space after the end of a paragraph using the
SpaceAfter
property.
ParSpaceAfter
=
Block
{
Paragraph
{
SpaceAfter
:
200%
;
TextHeight
:
120%;
Bold
;
"Title"
;
};
"Body text"
;
};
Title
Body text
Space after the paragraph
Set the border argument for a Paragraph to display a border on any combination of sides.
BorderPar
(
Border
border
)
=
Paragraph
(
border
) {
ParAlignment
:
Center
;
ParBackground
:
95%;
};
BorderExamples
=
Block
{
Separator
:
Paragraph
;
BorderPar
(4pt) {
"all sides"
};
BorderPar
(
BorderTB
(4pt)) {
"top - bottom"
};
BorderPar
(
BorderLR
(4pt)) {
"left - right"
};
};
all sides
top - bottom
Formatting
Page 82 of
114
left - right
Paragraph borders can also have different colors and padding
ColorBorder
=
Paragraph
(
new
Edge
(3pt, 5pt,
Colors
.
Red
)) {
ParAlignment
:
Center
;
ParBackground
:
#FCFCF4#
;
LeftIndent
:
16pt;
RightIndent
:
15pt;
Bold
;
"Very Important Notice"
;
};
Very Important Notice
Change the default line height using the
LineHeight
property.
LegalText
=
Block
{
LineHeight
:
200%
;
TextFace
:
Mono
;
Paragraph
{
Bold
;
TextCase
:
AllUpper
;
Underline
;
"Memorandum of Points"
;
};
"Statement of Relevant Facts"
;
};
MEMORANDUM OF POINTS
Statement of Relevant Facts
Double-spaced lines
Use global variables to create styles with familiar names. You can even use a named style to serve as
the root template for another style, as show below.
Normal
=
Paragraph
{
TextFamily
:
TextFamilies
.
CMUSerif
};
Heading1
=
Normal
{
ParAlignment
:
Center
;
TextFace
:
Serif
;
TextHeight
:
140%;
Bold
};
Heading2
=
Normal
{
TextHeight
:
110%;
Underline
};
Body
=
Normal
{
FirstIndent
:
8pt;
TextFamily
:
ParAlignment
:
Justify
};
Chapter1
=
Block
{
Heading1
{
"Chapter 1"
};
Heading2
{
"Introduction"
};
Body
{
"Consider the curious case of Dr. Jeckle. "
};
};
Chapter 1
Introduction
Consider the curious case of Dr. Jeckle.
Once you have a set of styles, you can use them consistently throughout your content. Now, all of your
style information is in one place, separated from your content.
The Nytril
®
Programming Language
Page 83 of
114
Emphasis
=
Span
{
Italic
;
TextColor
:
Colors
.
Red
};
Chapter2
=
Block
{
Heading1
{
"Chapter 2"
};
Heading2
{
"Introduction"
};
Body
{
"I would like to "
;
Emphasis
{
"emphasize"
};
" the following points. "
};
};
Chapter 2
Introduction
I would like to
emphasize
the following points.
You can also build manageable blocks of content in the same way, for reuse in different documents,
limited only by your imagination. A global style change, across all content and all documents is now
almost instant.
Book
=
Block
{
Chapter1
;
Chapter2
;
};
Chapter 1
Introduction
Consider the curious case of Dr. Jeckle.
Chapter 2
Introduction
I would like to
emphasize
the following points.
Image Formatting
Images loaded from external files are an important part of most documents.
To use an image find the path relative to your source code. Then, load the
image into a variable. Next, you can scale and format the image, and place it
into a Paragraph.
Bitmap pictures are represented with an
Image
object which accepts a path to a local file. Placing the
res
operator in front of the file name to causes the compiler to search for the path at compile time.
This causes a missing file to be a compile error, rather than a runtime error.
readonly
Image
Zombie
=
new
(
res
"Zombie.png
");
ZombieText
=
Paragraph
{
"Zombies eat brains! "
;
FitBox
(
Zombie
, 20%, 20%);
};
Formatting
Page 84 of
114
Zombies eat brains!
Scalable drawings like SVG files are represented with a
Drawing
object. Whether an
Image
or
Drawing
,
it is a good practice to load images into a variable with the
readonly
attribute to ensure that the file is
loaded only once.
readonly
Drawing
NytrilBug
=
new
(
res
"Figure.svg
");
ScaleFigure
=
Paragraph
{
FitBox
(
NytrilBug
, 10%);
};
Use the
Baseline
property to set the baseline of the image for alignment with other text.
ChangeBaseline
=
Block
{
Paragraph
{
"No baseline adjustment: "
;
FitBox
(
NytrilBug
, 5%);
};
Paragraph
{
"Baseline at 70%: "
;
FitBox
(
NytrilBug
, 5%) {
Baseline
:
70%
};
};
};
No baseline adjustment:
Baseline at 70%:
You can fit an image to a given size using the
FitBox
formatter. Here we set the width parameter to fit
an image to a given width, while scaling the height proportionately.
PictureWidth
=
FitBox
(
Zombie
,
4%
);
The Nytril
®
Programming Language
Page 85 of
114
Set the height parameter to fit an image to a given height, while scaling the width proportionately.
PictureHeight
=
FitBox
(
Zombie
,
null
,
10%
);
Fit an image inside both a given width and height, while maintaining proportion.
PictureBoth
=
FitBox
(
Zombie
,
10%, 20%
);
Force an image to a given size without preserving the image aspect ratio by setting the skew parameter
to true.
PictureSkew
=
FitBox
(
Zombie
, 20%, 10%,
null
,
true
);
Out of proportion
Use the
Opacity
property to change how opaque the contents of a formatter appear.
PictureOpacity
(
opacity
)
=
VBox
{
Opacity
:
opacity
;
HAlign
:
Center
;
TextDigits
:
0;
opacity
;
FitBox
(
Zombie
, 5%);
};
ShowPictureOpacity
=
Paragraph
{
Separator
:
Space
*
5;
Formatting
Page 86 of
114
PictureOpacity
(
each
(10%
..
100%
step
10%))
};
10%
20%
30%
40%
50%
60%
70%
80%
90%
100%
Use the
ScalingMode
property to change how the pixels of the bitmap scale and resolve.
ImageMode
(
ScalingModes
mode
)
=
VBox
{
Margin
:
PadR
(10pt);
HAlign
:
Center
;
mode
;
FitBox
(
Zombie
, 7%) {
ScalingMode
:
mode
};
};
ShowPictureMode
=
Paragraph
{
ImageMode
(
each
ScalingModes
);
};
None
Pixelated
MediumQuality
HighQuality
Clip an image inside a border by setting the
BorderClip
property to true.
readonly
Image
Sally
=
new
(
res
"../Examples/Family Tree/SallyJones.jpg
");
FrameFigure
(
Image
image
,
w
)
=
Canvas
(
null
,
w
*
1.6,
new
Edge
(
w
*
10%, 0,
#DCBC93#
)) {
Background
:
95%;
BorderRadius
:
w
*
50%;
BorderClip
:
true
;
FitBox
(
image
,
null
,
w
*
1.4);
};
SallyFrame
=
FrameFigure
(
Sally
,
Math
.
Max
(
ExtentWidth
,
ExtentHeight
)
*
10%);
Rotate and skew an image by setting the
Transform
property.
The Nytril
®
Programming Language
Page 87 of
114
readonly
Image
Michael
=
new
(
res
"../Examples/Family Tree/MichaelJones.jpg
");
RotateFrame
(
Image
image
,
w
,
angle
)
=
FrameFigure
(
image
,
w
) {
Transform
:
Transform
.
Rotate
(
angle
)
Transform
.
Skew
(
angle
,
angle
);
TransformFit
:
true
;
};
Locket
=
HBox
{
VAlign
:
Top
;
var
w
=
Math
.
Max
(
ExtentWidth
,
ExtentHeight
)
*
5%;
RotateFrame
(
Sally
,
w
,
-
8
degrees
);
Canvas
(
w
*
5%,
w
*
50%) {
Margin
:
PadT
(
w
*
60%);
Background
:
#C9AC87#
};
RotateFrame
(
Michael
,
w
, 8
degrees
);
};
The
Icons
namespace has a library of common material icons.
MenuItem
=
Paragraph
{
TextHeight
:
200%;
Span
{
Icons
.
folder
;
TextColor
:
Colors
.
Gold
};
Space
;
"Open the folder"
;
};
Open the folder
Here we place the icon in a box with a hoverable tip, by applying the
Canvas
formatter with a
TipAction
property.
YouTube
(
height
,
URL
url
)
=
Canvas
(
height
*
1.4,
height
) {
TipAction
:
url
;
HAlign
:
Center
;
VAlign
:
Center
;
BorderRadius
:
height
*
20%;
Background
:
#FF0033#
;
TextColor
:
Colors
.
White
;
TextHeight
:
height
*
0.85;
TextOffset
:
4%;
Baseline
:
83%;
Icons
.
play_arrow
;
};
IconFigure
=
Paragraph
{
YouTube
(
ExtentWidth
*
3%,
new
(
"www.youtube.com/@Nytril"
));
Space
;
"Follow us on YouTube"
;
};
Follow us on YouTube
https://www.youtube.com/@Nytril
Formatting
Page 88 of
114
Hyperlinks and Tips
Use hyperlinks to create content that is connected to your other documents
and to the outside world. Connect user input to different types of custom
actions to create dynamiclly generated content.
You can create a hyperlink to a web address simply by placing a
URL
inside a Span.
readonly
URL
WebAddress
=
new
(
"www.nytril.com"
);
LinkText
=
Span
{
WebAddress
;
};
www.nytril.com
Underlined on mouse-over
If you want different text for the link, use the
Action
property to specify the link that applies to the
entire Span.
Message
=
Span
{
TextColor
:
Colors
.
Blue
;
"Visit us on the web"
;
Action
:
WebAddress
;
};
Visit us on the web
Hidden URL, underlined text on mouse-over
Use the
Tip
property to specify a formatted popup when the user hovers the mouse over the text in
the Span.
TheAnswer
=
Span
{
TextColor
:
Colors
.
DarkGreen
;
"The answer is "
;
Bold
42;
};
PopupMessage
=
Span
{
"The answer"
;
Tip
:
new
Tip
(
TheAnswer
)
;
};
The answer
The answer is
42
Use the
TipAction
property to specify a both a tip and an action at the same time.
ActionTip
=
Span
{
"Here's a tip: "
;
Span
{
"Visit us on the web"
;
Underline
;
TipAction
:
WebAddress
;
}
The Nytril
®
Programming Language
Page 89 of
114
};
Here's a tip:
Visit us on the web
www.nytril.com
To create links within a single document, you must first give the target Paragraphs a reference name
using the
Anchor
function. The anchor name of each Paragraph must be unique in the document.
Location1
=
"Location 1"
;
AnchoredPar
=
Paragraph
{
"Important paragraph with the \"
{0}
\" anchor. "
(
Location1
);
DocFields
.
Anchor
(
Location1
);
};
Important paragraph with the "Location 1" anchor.
Once the anchor name is assigned to a paragraph, you can create an action that links to that paragaph,
no matter where it is placed in the document.
HelpLink
=
Span
{
Action
:
new
Action
(
Actions
.
ToAnchor
,
Location1
);
"Find out more in the help section. "
;
};
Find out more in the help section.
To label products or printed documents, QR codes can be added with the
QRBox
formatter. Notice that
there is always a white border around the QR code which is required by the QR readers.
QRCode
=
VBox
{
HAlign
:
Center
;
"Follow us online"
;
QRBox
(
WebAddress
, 1.5");
};
Follow us online
https://www.nytril.com
"Quiet zone"
Change the level of error correction in the QR code by setting the error parameter to a number from 0
to 3.
QRLink
=
VBox
{
HAlign
:
Center
;
Span
{
TextHeight
:
70%;
"Community Edition"
;
};
Formatting
Page 90 of
114
QRBox
(
WebAddress
, 1.5",
3
) {
TipAction
:
WebAddress
;
};
};
Community Edition
https://www.nytril.com
More complex pattern includes more error correction
Create an action to browse to a local file with the
ToFile
action type. This will bring up File Explorer on
Windows (or Finder on the Mac) and point it to the specified path.
FileLink
=
Span
{
"Open in File System"
;
Tip
:
"Browse the File"
;
Action
:
new
Action
(
Actions
.
ToFile
,
IO
.
Folders
.
Source
IO
.
FileName
(
"Hyperlinks.nytril"
));
};
Open in File System
Browse the File
Create a complex custom action by inheriting the
Action
class and overriding the Execute function.
class
CustomAction
:
Action
{
var
Text
;
Constructor
(
text
) {
super
.
Constructor
(
Actions
.
Execute
);
Text
=
text
;
}
override
EventResponse
Execute
{
System
.
TextToClipboard
(
Text
);
return
EventResponses
.
MessageTip
(
"Text copied to the clipboard"
);
}
}
CustomLink
=
Span
{
Icons
.
copy
;
Space
;
"Copy Text"
;
TipAction
:
new
CustomAction
(
"Custom Text"
);
};
Copy Text
Text copied to the clipboard
Page 91 of
114
Mathematics
User defined symbols
Symbols are special values that can represent constants or variables
x
=
Symbol
(
"x"
);
x
The typeset representation of a symbol can differ from its variable name
sigma
=
Symbol
(
"σ"
);
σ
You can create symbols with subscripts and superscripts
SigmaNaught
=
sigma
sub
0;
XSquared
=
x
sup
2;
SymbolSum
=
XSquared
+
SigmaNaught
;
x
2
+
σ
0
Algebra
Addition is carried out using the operator
+
Number
=
1
+
3;
Sum
=
Number
+
x
;
4
+
x
Subtraction is carried out using the operator
-
Difference
=
5
-
7;
-2
Multiplication is carried out using the operator
*
Product
=
5
*
3;
15
Rational division is carried out using the operator
over
Ratio
=
3
over
5;
3
5
Mathematics
Page 92 of
114
Floating point division is carried out using the operator
/
, the result is a floating point number.
RealDivision
=
3
/
5;
0.6
Integer division (even division without a remainder) is carried out using the operator
div
IntResult
=
8
div
5;
1
The remainder after integer division can be found using the operator
mod
Remainder
=
8
mod
5;
3
A value can be raised to a power using the operator
^
Power
=
4
^
2;
16
Symbols obey the rules of algebra when combined with other symbols and numbers
Polynomial
=
a
x
^
2
+
b
x
+
c
;
a
x
2
+
b
x
+
c
Basic algebra is performed automatically when symbols are multipled or added
AddX
=
2
x
+
5
x
+
3;
7
x
+
3
Combined terms can be expanded using the function:
public
object
.GetExpandedTerms
For example:
CompareAll
=
[
CompareEquations
(14),
CompareEquations
((3
x
+
y
)
*
x
*
y
),
CompareEquations
(2
*
(6
+
y
)
*
y
),
CompareEquations
((3
x
+
1)
*
1
*
x
),
];
14
=> 14
(
3
x
+
y
)
x
y
=>
3
x
2
y
+
y
2
x
2
(
6
+
y
)
y
=>
12
y
+
2
y
2
(
3
x
+
1
)
x
=>
3
x
2
+
x
The Nytril
®
Programming Language
Page 93 of
114
The operator between common types can be ommited in simple expressions
ThreeX
=
3
x
;
g
=
9.8
meters
per
second
^
2;
Palindrome
=
"was it "
"a car "
"or a cat I saw"
;
3
x
9.8
meters
second
2
was it a car or a cat I saw
Get the minimum of two values using the function:
Min(
x
,
y
)
For example:
CheckMin1
=
Math
.
Min
(
-
5, 2);
CheckMin2
=
Math
.
Min
(
Symbolic
.
PI
, 4);
-5
π
Get the maximum of two values using the function:
Max(
x
,
y
)
For example:
CheckMax1
=
Math
.
Max
(
-
5,
-
2);
CheckMax2
=
Math
.
Max
(
Math
.
E
, 2);
-2
2.718281828459045
Get the absolute value of a number using the function:
Abs(
x
)
For example:
CheckAbs1
=
Math
.
Abs
(5);
CheckAbs2
=
Math
.
Abs
(
-
10);
CheckAbs3
=
Math
.
Abs
(
-
x
);
5
10
−
x
Get the logarithm of a number using the function:
double
Log(
x
,
double
base
=
null
)
For example:
CheckLog1
=
{
TextDigits
:
5}
Math
.
Log
(5.345);
CheckLog2
=
Math
.
Log
(
Math
.
E
);
CheckLog3
=
Math
.
Log
(
Math
.
E
*
2);
CheckLog4
=
Math
.
Log
(1000, 10);
CheckLog5
=
Math
.
Log
(16, 2);
1.67616
1
1.6931471805599452
2.9999999999999996
Mathematics
Page 94 of
114
4
Get the factorial of a number using the function:
Factorial(
x
)
For example:
FactArray
=
Span
{
Separator
:
", "
;
Math
.
Factorial
(
each
1
..
6)};
1, 2, 6, 24, 120, 720
Statistics
Statistics functions operate on arrays of double values. For example suppose we define the following
arrays:
NumberSet
=
[3.6, 4.0, 4.5, 5.5, 6.4, 8.5];
[
3.6
,
4
,
4.5
,
5.5
,
6.4
,
8.5
]
The
sum
of an array is defined as:
S
=
x
i
n
i
=
1
where
n
is the length of the array and
x
i
is the
i
th
element.
It can be computed using the function:
double
Sum(
double
[]
values
)
For example:
SumData
=
Math
.
Sum
(
NumberSet
);
32.5
The
product
of an array is defined as:
P
=
x
i
n
i
=
1
where
n
is the length of the array and
x
i
is the
i
th
element.
It can be computed using the function:
double
Product(
double
[]
values
)
For example:
ProductData
=
Math
.
Product
(
NumberSet
);
19388.16
The
arithmetic mean
of an array is defined as:
x
=
x
i
n
i
=
1
n
where
n
is the length of the array and
x
i
is the
i
th
element.
It can be computed using the function:
The Nytril
®
Programming Language
Page 95 of
114
double
Mean(
double
[]
values
)
For example:
MeanData
=
Math
.
Mean
(
NumberSet
);
5.416666666666667
The
harmonic mean
of an array is defined as:
H
=
n
1
x
i
n
i
=
1
where
n
is the length of the array and
x
i
is the
i
th
element.
It can be computed using the function:
double
HarmonicMean(
double
[]
values
)
For example:
HarmonicMeanData
=
Math
.
HarmonicMean
(
NumberSet
);
4.976299376299376
The
geometric mean
of an array is defined as:
H
=
x
i
n
i
=
1
n
where
n
is the length of the array and
x
i
is the
i
th
element.
It can be computed using the function:
double
GeometricMean(
double
[]
values
)
For example:
GeometricMeanData
=
Math
.
GeometricMean
(
NumberSet
);
5.183098144673662
The
median
of an array can be computed using the function:
double
Median(
double
[]
values
)
For example:
[5]
The
mode
of an array can be computed using the function:
double
[] Mode(
double
[]
values
)
For example:
DoubleData
=
Math
.
Mode
([1.0, 2.0, 3.0, 2.0, 4.0]);
2
The
variance
of an array is defined as:
Mathematics
Page 96 of
114
σ
2
=
(
x
i
−
x
)
2
n
i
=
1
n
where
x
is the mean.
It can be computed using the function:
double
Variance(
double
[]
values
)
For example:
VarianceData
=
Math
.
Variance
(
NumberSet
);
2.771388888888889
The
standard deviation
of an array is defined as:
σ
=
(
x
i
−
x
)
2
n
i
=
1
n
It can be computed using the function:
double
StandardDeviation(
double
[]
values
)
For example:
StdDevData
=
Math
.
StandardDeviation
(
NumberSet
);
1.6647488966474462
The
standard scores
(Z-scores) for every element in an array can be calculated
Z
=
x
−
x
σ
It can be computed using the function:
double
[] StandardScores(
double
[]
values
)
For example:
[-1.0912556664402422, -0.850979189425877, -0.5506335931579205, 0.05005759937799258,
0.5906796726603146, 1.8521311769857318]
The
Quantiles
of an array can be computed using the function:
double
[][] Quantiles(
double
[]
values
,
percent
)
For example:
[3.6, 4, 4.5, 5.5, 6.4, 8.5]
The
Chi Squared Statistic
of two datasets is defined as:
χ
2
=
(
O
i
−
E
i
)
2
E
i
n
i
=
1
The Nytril
®
Programming Language
Page 97 of
114
Where O
i
is the
i
th
observed value and E
i
is the
i
th
expected value.
It can be computed using the function:
double
ChiSquare(
double
[]
values
,
double
[]
expected
)
For example:
ObservedValues
=
[1.0, 3.0, 5.0, 4.0, 7.0];
ExpectedValues
=
[1.0, 4.0, 3.0, 4.0, 8.0];
ChiSquaredData
=
Math
.
ChiSquare
(
ObservedValues
,
ExpectedValues
);
1.7083333333333333
You can perform a simple regression analysis on two datasets using:
sealed
class
Math
.
LinearRegression
For example:
Temperature
=
[88.6, 71.6, 93.3, 84.3, 80.6, 75.2, 69.7, 82, 69.4, 83.3,79.6,82.6,80.6];
ChirpsPerSec
=
[20, 16, 19.8, 18.4, 17.1, 15.5, 14.7, 17.1, 15.4, 16.2, 15, 17.2, 16];
//Data from "The Song of Insects" by Dr. G.W. Pierce, Harvard College Pre
Math
.
LinearRegression
Regression
=
new
Math
.
LinearRegression
(
Temperature
,
ChirpsPerSec
);
The LinearRegression also has a method to predict the value at different points:
ValueAt95
=
Regression
.
GetYValue
(95.0);
19.86279259953732
The
Correlation Coefficient
of two datasets is defined as:
r
=
(
x
i
−
x
)
(
y
i
−
y
)
n
i
=
1
(
x
i
−
x
)
2
n
i
=
1
(
y
i
−
y
)
2
n
i
=
1
It can be computed using the function:
public
readonly
double
Math
.
LinearRegression
.Correlation
For example:
Correlation
=
Regression
.
Correlation
;
0.8506559172499765
Here is an example of how to add regression lines to a chart
CricketChart
=
VBox
{
Paragraph
{
TextHeight
:
16pt;
"Cricket Chirps vs. Temperature"
;
};
HAlign
:
Center
;
Chart
(
ExtentWidth
*
0.75, 3") {
ChartType
:
ChartTypes
.
Scatter
;
XAxis
:
ChartAxis
;
ValueLabel
:
"Cricket\nChirps"
;
XLabel
:
"Temperature (F)"
;
ChartSeries
{
new
LinearTrend
;
Mathematics
Page 98 of
114
Label
:
"Temperature"
;
foreach
(
var
x
in
Temperature
)
new
DataPoint
(
x
,
ChirpsPerSec
[
each0
]);
};
}
};
Cricket Chirps vs. Temperature
Temperature (F)
Cricket
Chirps
68
70
72
74
76
78
80
82
84
86
88
90
92
94
0
2
4
6
8
10
12
14
16
18
20
Vectors
Vector objects represent a 1 dimensional array of values of a fixed size.
x
=
Symbol
(
"x"
);
y
=
Symbol
(
"y"
);
z
=
Symbol
(
"z"
);
a
=
Symbol
(
"a"
);
b
=
Symbol
(
"b"
);
c
=
Symbol
(
"c"
);
d
=
Symbol
(
"d"
);
N1
=
Vector
.
Convert
([4.0, 2.0]);
N2
=
Vector
.
Convert
([1.0, 9.0]);
V1
=
Vector
.
Convert
([
a
,
b
]);
V2
=
Vector
.
Convert
([
c
,
d
]);
[4, 2]
[1, 9]
[
a
,
b
]
[
c
,
d
]
Vectors can be initialize with uniform contents
Vector
I10
=
new
Vector
(5,
a
);
[
a
,
a
,
a
,
a
,
a
]
Vectors of the same size can be added together using the operator
+
The Nytril
®
Programming Language
Page 99 of
114
VAdd
=
V1
+
V2
;
NAdd
=
N1
+
N2
;
[
a
+
c
,
b
+
d
]
[5, 11]
Vectors of the same size can be subtracted using the operator
-
VSub
=
V1
-
V2
;
NSub
=
N1
-
N2
;
[
a
−
c
,
b
−
d
]
[3, -7]
The dot product of two vectors is calculated using the function:
public
Vector
.Dot(
vector
)
For example:
VDot
=
V1
.
Dot(
V2
);
NDot
=
N1
.
Dot(
N2
);
a
c
+
b
d
22
The cross product of two 3-vectors is calculated using the function:
public
Vector
.Cross(
vector
)
For example:
VCross
=
Vector
.
Convert
([
a
,
b
,
c
])
.
Cross
([
x
,
y
,
z
]);
NCross
=
Vector
.
Convert
([1.0, 2.0, 3.0])
.
Cross
([4.0, 5.0, 6.0]);
[
b
z
−
c
y
,
c
x
−
a
z
,
a
y
−
b
x
]
[-3, 6, -3]
The norm of a vector is calculated using the function:
public
Vector
.Norm
For example:
VNorm
=
V1
.
Norm;
NNorm
=
N1
.
Norm;
a
2
+
b
2
4.47213595499958
The normalize form of a vector is calculated using the function:
public
Vector
.Normalize
For example:
VNormalize
=
V1
.
Normalize;
NNormalize
=
N1
.
Normalize;
[
a
a
2
+
b
2
,
b
a
2
+
b
2
]
[0.8944271909999159, 0.4472135954999579]
Matrices
Matrix objects represent a 2 dimensional array of numbers or symbols of a fixed size.
Mathematics
Page 100 of
114
x
=
Symbol
(
"x"
);
y
=
Symbol
(
"y"
);
z
=
Symbol
(
"z"
);
a
=
Symbol
(
"a"
);
b
=
Symbol
(
"b"
);
c
=
Symbol
(
"c"
);
d
=
Symbol
(
"d"
);
e
=
Symbol
(
"e"
);
f
=
Symbol
(
"f"
);
g
=
Symbol
(
"g"
);
h
=
Symbol
(
"h"
);
N1
=
Matrix
.
Convert
([[1.0, 4.0], [3.0, 1.0]]);
N2
=
Matrix
.
Convert
([[7.0, 5.0], [8.0, 9.0]]);
V1
=
Matrix
.
Convert
([[
a
,
b
], [
c
,
d
]]);
V2
=
Matrix
.
Convert
([[
e
,
f
], [
g
,
h
]]);
1
4
3
1
7
5
8
9
a
b
c
d
e
f
g
h
Matrices can be initialized with uniform contents and an optional diagonal element for square matrices
I52
=
new
Matrix
(4, 4, 0.0, 1.0);
1
0
0
0
0
1
0
0
0
0
1
0
0
0
0
1
Matrices of the same size can be added together using the operator
+
VAdd
=
V1
+
V2
;
NAdd
=
N1
+
N2
;
a
+
e
b
+
f
c
+
g
d
+
h
8
9
11
10
Matrices of the same size can be subtracted using the operator
-
VSub
=
V1
-
V2
;
NSub
=
N1
-
N2
;
a
−
e
b
−
f
c
−
g
d
−
h
-6
-1
-5
-8
The determinant of a matrix is calculated using the function:
public
Matrix
.Determinant
For example:
The Nytril
®
Programming Language
Page 101 of
114
VDet
=
V1
.
Determinant;
NDet
=
N1
.
Determinant;
a
d
−
b
c
-11
The inverse of a matrix is calculated using the function:
public
Matrix
<
any
>
Matrix
.Inverse
For example:
VInv
=
V1
.
Inverse;
NInv
=
N1
.
Inverse;
d
a
d
−
b
c
−
b
a
d
−
b
c
−
c
a
d
−
b
c
a
a
d
−
b
c
-0.09090909090909091
0.36363636363636365
0.2727272727272727
-0.09090909090909091
The transposition of a matrix is calculated using the function:
public
Matrix
<
any
>
Matrix
.Transpose
For example:
VTran
=
V1
.
Transpose;
NTran
=
N1
.
Transpose;
a
c
b
d
1
3
4
1
The normalize form of a matrix is calculated using the function:
public
Matrix
<
any
>
Matrix
.Normalize
For example:
VNormalize
=
V1
.
Normalize;
NNormalize
=
N1
.
Normalize;
a
a
d
−
b
c
b
a
d
−
b
c
c
a
d
−
b
c
d
a
d
−
b
c
-0.09090909090909091
-0.36363636363636365
-0.2727272727272727
-0.09090909090909091
The cofactor matrix of a given square matrix is calculated using the function:
public
Matrix
<
any
>
Matrix
.CofactorMatrix
For example:
VCofactor
=
V1
.
CofactorMatrix;
NCofactor
=
N1
.
CofactorMatrix;
TCofactor
=
Matrix
.
Convert
([[1, 2, 3], [0, 4, 5], [1, 0, 6]])
.
CofactorMatrix
;
d
−
c
−
b
a
1
-3
-4
1
Mathematics
Page 102 of
114
24
5
-4
-12
3
2
-2
-5
4
Automatic Equation Typesetting
Unresolved square roots are automatically typeset
x
=
Symbol
(
"x"
);
y
=
Symbol
(
"y"
);
SquareRoot
=
x
^
(1
over
2);
x
Higher roots are also typeset
CubeRoot
=
x
^
(1
over
3);
x
3
Equations of arbitray complexity will be typeset
Part1
=
(
x
/
y
)
^
(1
over
3);
Part2
=
Part1
+
x
/
y
+
x
^
2
/
y
+
(
x
^
3
/
y
^
5)
^
(1
over
3)
+
x
;
x
y
3
+
x
y
+
x
2
y
+
x
3
y
5
3
+
x
Expressions can be combined to form larger formulas
LargeEquation
=
Symbolic
.
Sqrt
(
Part1
/
Part2
);
x
y
3
x
y
3
+
x
y
+
x
2
y
+
x
3
y
5
3
+
x
Page 103 of
114
Local Resources
Processes
An executable file can be run using
Process
Console
=
Paragraph
{
TextFace
:
Mono
;
TextHeight
:
12pt;
TextColor
:
Colors
.
White
;
ParBackground
:
Colors
.
Black
;
Process
process
;
if
(
System
.
OperatingSystem
==
OperatingSystems
.
Mac
)
process
=
new
Process
(
"/bin/ls"
);
else
process
=
new
Process
(
Folders
.
System
FileName
(
"netstat.exe"
),
"-e"
);
var
result
=
process
.
Run
;
if
(
result
.
ExitCode
==
0)
result
.
StandardOutput
;
else
result
.
ErrorMessage
;
};
Interface Statistics
Received Sent
Bytes 1872272320 1814403950
Unicast packets 10115256 17189496
Non-unicast packets 205008 13446
Discards 0 0
Errors 0 0
Unknown protocols 0
File System
Get a listing of files using the function:
FileEntry
[] EnumerateFiles(
folder
,
filter
=
null
)
For example:
FileListing
=
Table
(0.5,
PadLR
(3), [3
inch
, 1",
new
(1",
null
,
null
,
HAligns
.
Right
)]) {
TextHeight
:
11pt;
var
list
=
EnumerateFiles
(
RootFolderPath
,
"*.nytril"
);
Row
{
Background
:
NytrilPalette
.
TableTitleBack
;
TextColor
:
NytrilPalette
.
TableTitleFore
;
"File Name"
;
"Created"
;
"Size"
;
Local Resources
Page 104 of
114
};
foreach
(
var
e
in
list
) {
Row
{
if
(
each0
mod
2
==
0)
Background
:
95%;
e
.
FileName
;
Cell
{
TextFormat
:
"MM-dd-yyyy"
;
e
.
Created
;
};
e
.
Size
;
}
}
};
File Name
Created
Size
Angle Calculator.nytril
02-16-2025
7624
Body Mass Index.nytril
09-24-2025
1873
Chemistry.nytril
09-24-2025
4316
Color Picker.nytril
09-20-2023
1662
Data Tables.nytril
09-24-2025
3885
Doc With Sidebar.nytril
11-29-2021
849
Embedded Data.nytril
11-29-2021
1604
Equations.nytril
06-18-2025
9619
Examples Home.nytril
05-05-2026
2094
Finance.nytril
09-16-2025
899
Finger Binary.nytril
05-10-2026
3313
FizzBuzz.nytril
02-08-2024
650
Font Families.nytril
05-06-2026
1196
Hello World.nytril
10-06-2018
247
Input Form.nytril
09-24-2025
6443
International.nytril
05-26-2026
3038
Mad Lib.nytril
09-24-2025
5050
Matrix Calculations.nytril
03-08-2022
1955
Mortgage Calculator.nytril
09-24-2025
6781
Opacity Examples.nytril
09-24-2025
3296
Paragraph Examples.nytril
11-03-2021
1277
Party Signs.nytril
09-24-2025
1827
Random Walk.nytril
09-24-2025
7265
Read Text File.nytril
10-01-2023
308
SieveOfEratosthenes.nytril
02-09-2024
1213
Simple Document.nytril
09-24-2025
807
Source Reflection.nytril
09-24-2025
1192
Split The Bill.nytril
11-29-2021
3913
Sub Realm United States.nytril
05-06-2026
456
Table Edges.nytril
09-06-2020
4798
Time Sheet.nytril
09-24-2025
4021
White Paper.nytril
03-25-2026
12433
Get a listing of folders using the function:
The Nytril
®
Programming Language
Page 105 of
114
FileEntry
[] EnumerateFolders(
folder
,
filter
=
null
)
For example:
FolderListing
=
Table
(0.5,
PadLR
(3), [3
inch
, 1"]) {
TextHeight
:
11pt;
var
list
=
IO
.
EnumerateFolders
(
RootFolderPath
);
Row
{
Background
:
NytrilPalette
.
TableTitleBack
;
TextColor
:
NytrilPalette
.
TableTitleFore
;
"Folder Name"
;
"Created"
;
};
foreach
(
var
e
in
list
) {
Row
{
if
(
each0
mod
2
==
0)
Background
:
90%;
e
.
FileName
;
Cell
{
TextFormat
:
"MM-dd-yyyy"
;
e
.
Created
;
};
}
}
};
Folder Name
Created
Citations
07-23-2021
Database
06-13-2024
Documentation Workflow
02-22-2026
Family Tree
08-07-2020
History
11-23-2021
Import
09-16-2025
JSON
04-22-2024
Mail Merge
07-14-2020
Map
08-09-2024
Math Homework
07-23-2021
Phylo
07-14-2020
Quotations
04-02-2025
Recipes
07-14-2020
Resumes
06-18-2020
Scuba Watch
06-03-2025
Web
04-29-2025
XML
09-25-2023
Page 107 of
114
Genetics
Bases
Bases can be specified by using built-in symbols joined together with a + sign to form a sequence
Base1
=
Dna
.
Cytosine
+
Dna
.
Guanine
;
CG
Bases can be combined into a base set using the binary or operator
|
Set1
=
Dna
.
Thymine
|
Dna
.
Guanine
;
K
Longer sequences can be input by using the correct string prefix
DNA1
=
dna
"ACTG"
;
RNA1
=
rna
"UGAC"
;
Codons1
=
codon
"<MDI><AIHHPWIRR>"
;
Protein1
=
protein
"MDIAIHHPWIRR"
;
ACTG
UGAC
<MDI><AIHHPWIRR>
MDIAIHHPWIRR
Use string functions to generate several variations of a sequence
DNAFunc
=
dna
"AC
{0}
TG"
;
Call
=
DNAFunc
(
Dna
.
N
);
Iterate
=
DNAFunc
(
each
[
dna
"-AA-"
,
dna
"-CC-"
,
dna
"-TT-"
,
dna
"-GG-"
]);
AC
N
TG
AC-AA-TG
AC-CC-TG
AC-TT-TG
AC-GG-TG
Sequences can be repeated by using using the operator
*
with an integer
Promoter
=
dna
"TATAAA"
;
Repeats
=
Promoter
+
Dna
.
Gap
*
4
+
dna
"-ACTG-"
*
5
+
10;
TATAAA????-ACTG--ACTG--ACTG--ACTG--ACTG-----------
Sequences can also be constructed by placing the components adjacent to each other
Gene2
=
Promoter
30
dna
"CCTCCCAGG"
;
TATAAA------------------------------CCTCCCAGG
Genetics
Page 108 of
114
Common variants can be constucted without repeating or losing information
Highlight
=
{
TextBackground
:
Colors
.
LightGray
};
Original
=
dna
"ATTGGCCTTAACCCCCGATTATCAGGAT"
;
class
VariantClass
{
var
Name
,
Sequence
;
Constructor
(
name
,
sequence
) {
Name
=
name
;
Sequence
=
sequence
;
}
}
VariantClass
[]
Variants
=
[
new
(
"Substitution"
,
Original
.
Substitute(14,
Highlight
Dna
.
Thymine
)),
new
(
"Insertion"
,
Original
.
Insert(15
..
17,
Highlight
dna
Dna
.
Gap
)),
new
(
"Deletion"
,
Original
.
Remove(15
..
17)),
new
(
"Inversion"
,
Original
.
Substitute(9
..
16,
Highlight
Original
[9
..
16]
.
Reverse
)),
new
(
"Copy Number"
,
Original
.
Remove(3
..
9)
.
Insert(3
..
16,
Highlight
Original
[3
..
9]
*
2)),
];
VarTable
=
Table
(
new
Edge
(2, 0,
Colors
.
LightGray
),
PadLR
(3), [1.5", 3"]) {
TextHeight
:
10pt;
NytrilStyle
.
HeaderRow
{
"Type"
;
"Variant"
};
foreach
(
var
v
in
Variants
) {
Row
{
v
.
Name
;
Original
;
};
Row
(
BorderB
(
new
(1pt, 0,
Colors
.
LightGray
))) {
Paragraph
{
ParAlignment
:
Right
;
RightIndent
:
5pt;
Tex
.
Rightarrow
;
};
v
.
Sequence
;
};
}
};
Type
Variant
Substitution
ATTGGCCTTAACCCCCGATTATCAGGAT
⇒
ATTGGCCTTAACCC
T
CGATTATCAGGAT
Insertion
ATTGGCCTTAACCCCCGATTATCAGGAT
⇒
ATTGGCCTTAACCCC
---
CGATTATCAGGAT
Deletion
ATTGGCCTTAACCCCCGATTATCAGGAT
⇒
ATTGGCCTTAACCCCTTATCAGGAT
Inversion
ATTGGCCTTAACCCCCGATTATCAGGAT
⇒
ATTGGCCTT
GCCCCCAA
ATTATCAGGAT
Copy Number
ATTGGCCTTAACCCCCGATTATCAGGAT
⇒
ATT
GGCCTTAGGCCTTA
ACCCCCGATTATCAGGAT
Sequences can also be read from files using the function:
ReadDocument(
path_or_blob
,
FileFormat
fileformat
=
null
)
The Nytril
®
Programming Language
Page 109 of
114
For example:
readonly
GeneFile
=
IO
.
ReadDocument
(
res
"Sequences.fasta
");
readonly
WholeGene
=
GeneFile
.
BTBSCRYR;
readonly
GeneSlice
=
WholeGene
[10
..
99];
ShowGene
=
Block
{
Paragraph
{
Underline
;
WholeGene
.
Comment;
};
GeneSlice
;
};
sample gene
atgtctaaagctggaaccaaaattactttctttgaagacaaaaactttcaaggccgccactatgacagcg
attgcgactgtgcagatttc
Revisions are used to control sequence formatting
GeneFormatted
=
Span
{
TextColumns
:
30;
TextDivision
:
5;
GeneSlice
;
};
atgtc taaag ctgga accaa aatta ctttc
tttga agaca aaaac tttca aggcc gccac
tatga cagcg attgc gactg tgcag atttc
Sections of a sequence can be formatted using the function:
public
[]
Array
.Revise(
range
,
revision
)
For example:
GeneStained1
=
GeneSlice
.
Revise([3
..
11, 72
..
74],
Stain1
);
GeneStained
=
GeneStained1
.
Revise(18
..
20,
Stain2
);
atgtctaaagctggaaccaaaattactttctttgaagacaaaaactttcaaggccgccactatgacagcg
attgcgactgtgcagatttc
RNA sequences are constructed in the same way using the operator
rna
RNASequence
=
rna
"ACUG"
+
Rna
.
Uracil
+
Rna
.
Adenine
;
ACUG
UA
DNA can be transcribed into RNA using the operator
rna
ComputedRNA
=
rna
GeneStained
;
AUGUCUAAAGCUGGAACCAAAAUUACUUUCUUUGAAGACAAAAACUUUCAAGGCCGCCACUAUGACAGCG
AUUGCGACUGUGCAGAUUUC
RNA can be converted into codons using the operator
codon
Genetics
Page 110 of
114
ComputedCodons
=
codon
ComputedRNA
;
<SKAGTKITFFEDKNFQGRHYDSDCDCADF
RNA or codons can be translated into a protein using the operator
protein
ComputedProtein
=
protein
ComputedRNA
;
SKAGTKITFFEDKNFQGRHYDSDCDCADF
Proteins can be transcribed back into RNA, creating an array of RNA sequences that could yield the
protein
[
UCU
,
AGU
,
UCC
,
AGC
,
UCA
,
UCG
,
AAA
,
AAG
,
GCU
,
GCC
,
GCA
,
GCG
,
GGU
,
GGC
,
GGA
,
GGG
,
ACU
,
ACC
,
ACA
,
ACG
,
AAA
,
AAG
,
AUU
,
AUC
,
AUA
,
ACU
,
ACC
,
ACA
,
ACG
,
UUU
,
UUC
,
UUU
,
UUC
,
GAA
,
GAG
,
GAU
,
GAC
,
AAA
,
AAG
,
AAU
,
AAC
,
UUU
,
UUC
,
CAA
,
CAG
,
GGU
,
G
GC
,
GGA
,
GGG
,
CGU
,
CGC
,
CGA
,
AGA
,
CGG
,
AGG
,
CAU
,
CAC
,
UAU
,
UAC
,
GAU
,
GAC
,
UCU
,
AGU
,
UCC
,
AGC
,
UCA
,
UCG
,
GAU
,
GAC
,
UG
U
,
UGC
,
GAU
,
GAC
,
UGU
,
UGC
,
GCU
,
GCC
,
GCA
,
GCG
,
GAU
,
GAC
,
UUU
,
UUC
]
Proteins
Proteins can be input directly using using the operator
protein
Protein1
=
protein
"AVG"
;
AVG
Proteins can also be built up from smaller segments using the same rules as for dna and rna
Protein2
=
Protein1
Amino
.
Phenylalanine
Amino
.
Aspartate
;
AVG
FD
Codons can be computed from RNA sequences
AllRNATriplets
=
rna
GUGGCGGAGGG"
GUGGCGGAGGG"
GUGGCGGAGGG"
;
RNACodons
=
codon
AllRNATriplets
;
FFLLSSSSYY>>CC>WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG
If the RNA sequence contains OR'd elements, the result will be an array of all possible codons
[A, R, N, D, C, E, Q, G, H, I, L, K, F, P, S, T, W, Y, V, >, <]
Proteins can also be created from a sequence of codons using the operator
codon
Codons
=
codon
"<FTGN>"
;
The Nytril
®
Programming Language
Page 111 of
114
Protein3
=
protein
Codons
;
FTGN
Arrays of proteins can also be created from back-to-back sequences of codons
ProteinArray
=
protein
codon
"--<FTGN>----<MQS>--"
;
FTGN
MQS
A protein can be decomposed into its corresponding RNA sequence using using the operator
rna
[
GCU
,
GCC
,
GCA
,
GCG
,
GUU
,
GUC
,
GUA
,
GUG
,
GGU
,
GGC
,
GGA
,
GGG
,
UUU
,
UUC
,
GAU
,
GAC
]
This array can, in turn, be converted to DNA using the operator
dna
[
GCT
,
GCC
,
GCA
,
GCG
,
GTT
,
GTC
,
GTA
,
GTG
,
GGT
,
GGC
,
GGA
,
GGG
,
TTT
,
TTC
,
GAT
,
GAC
]
Mutations
Long sequences can be built up from short sequences using the operator
+
CompleteRegion
=
dna
"TATAAA"
+
20
+
Gene2
;
TATAAA--------------------GCTGATTC
Sections can be inserted into existing sequences using the function:
public
[]
Array
.Insert(
range
,
value
)
For example:
InsertedRegion
=
CompleteRegion
.
Insert(10,
dna
"AACCTTGG"
);
TATAAA----A----------------GCTGATTC
Sections can be removed from existing sequences using the function:
public
[]
Array
.Remove(
range
)
For example:
DeletedRegion
=
InsertedRegion
.
Remove(16
..
28);
TATAAA----A-----TGATTC
Sections can be replaced using the function:
public
[]
Array
.Substitute(
range
,
value
)
For example:
Substitution
=
DeletedRegion
.
Substitute(12
..
17,
dna
"GGGGG"
);
Genetics
Page 112 of
114
TATAAA----A-GGGGGGATTC
Repetitive sequences like Alu elements can be encoded to highlight unique sections
AluElement
=
dna
"GCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC
{0}
GTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTC"
GTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTC"
;
Stain
=
{
TextColor
:
Colors
.
White
;
TextBackground
:
Colors
.
Red
};
AluExample
=
AluElement
(
Stain
dna
"AGCT"
)
*
5;
GCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC
AGCT
ACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTC
CAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGC
GAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC
AGCT
ACTCGGGAGGCTGAGGCTGGAG
GATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCC
TGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC
AGCT
ACTCGGGAG
GCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCA
CTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC
AGCT
ACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCG
ATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCG
TGCCTGTAGTCCC
AGCT
ACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTA
GTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTC
Sequences can be formatted to fit in regular columns
AluFormat
=
Span
{
TextColumns
:
40;
TextDivision
:
5;
TextHeight
:
8pt;
AluExample
;
};
GCCGG GCGCG GTGGC GCGTG CCTGT AGTCC C
AGCT
ACTCG
GGAGG CTGAG GCTGG AGGAT CGCTT GAGTC CAGGA GTTCT
GGGCT GTAGT GCGCT ATGCC GATCG GAATA GCCAC TGCAC
TCCAG CCTGG GCAAC ATAGC GAGAC CCCGT CTCGC CGGGC
GCGGT GGCGC GTGCC TGTAG TCCC
A GCT
AC TCGGG AGGCT
GAGGC TGGAG GATCG CTTGA GTCCA GGAGT TCTGG GCTGT
AGTGC GCTAT GCCGA TCGGA ATAGC CACTG CACTC CAGCC
TGGGC AACAT AGCGA GACCC CGTCT CGCCG GGCGC GGTGG
CGCGT GCCTG TAGTC CC
AGC T
ACTC GGGAG GCTGA GGCTG
GAGGA TCGCT TGAGT CCAGG AGTTC TGGGC TGTAG TGCGC
TATGC CGATC GGAAT AGCCA CTGCA CTCCA GCCTG GGCAA
CATAG CGAGA CCCCG TCTCG CCGGG CGCGG TGGCG CGTGC
CTGTA GTCCC
AGCT
A CTCGG GAGGC TGAGG CTGGA GGATC
GCTTG AGTCC AGGAG TTCTG GGCTG TAGTG CGCTA TGCCG
ATCGG AATAG CCACT GCACT CCAGC CTGGG CAACA TAGCG
AGACC CCGTC TCGCC GGGCG CGGTG GCGCG TGCCT GTAGT
CCC
AG CT
ACT CGGGA GGCTG AGGCT GGAGG ATCGC TTGAG
TCCAG GAGTT CTGGG CTGTA GTGCG CTATG CCGAT CGGAA
TAGCC ACTGC ACTCC AGCCT GGGCA ACATA GCGAG ACCCC
GTCTC
Staining
Use an array of proteins included from an external file
readonly
PSequenceClass
[]
ProteinArray
=
[
new
(
"Squac"
,
Proteins
.
crab_squac),
new
(
"Bovin"
,
Proteins
.
crab_bovin),
The Nytril
®
Programming Language
Page 113 of
114
new
(
"Human"
,
Proteins
.
crab_human),
new
(
"Rabbit"
,
Proteins
.
crab_rabit),
new
(
"Mouse"
,
Proteins
.
crab_mouse),
new
(
"Mesau"
,
Proteins
.
crab_mesau),
new
(
"Rat"
,
Proteins
.
crab_rat),
new
(
"Anapl"
,
Proteins
.
crab_anapl),
new
(
"Chicken"
,
Proteins
.
crab_chick)
];
readonly
ShowProteins
=
ShowSequence
(
ProteinArray
, 84);
Squac
MDIAIQHPWLRRPLFPSSIFPSRIFDQNFGEHFDPDLFPSFSSMLSPFYWRMGAPMARMPSWAQTGLSELRLDKDKFAIHLDVK
Bovin
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPASTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Human
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWFDTGLSEMRLEKDRFSVNLDVKHF
Rabbit
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Mouse
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Mesau
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHF
Rat
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHF
Anapl
MDITIHNPLIRRPLFSWLAPSRIFDQIFGEHLQESELLPASPSLSPFLMRSPIFRMPSWLETGLSEMRLEKDKFSVNLDVKHFS
Chicken
MDITIHNPLVRRPLFSWLTPSRIFDQIFGEHLQESELLPTSPSLSPFLMRSPFFRMPSWLETGLSEMRLEKDKFSVNLDVKHFS
Squac
HFTPEELRVKILGDFIEVQAQHEERQDEHGYVSREFHRKYKVPAGVDPLVITCSLSADGVLTITGPRKVADVPERSVPISRDEK
Bovin
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Human
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPA
Rabbit
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQAPGPERTIPITREEKPA
Mouse
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPA
Mesau
SPEELKVKVLGDVVEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Rat
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Anapl
PEELKVKVLGDMVEIHGKHEERQDEHGFIAREFNRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAI
Chicken
PEELKVKVLGDMIEIHGKHEERQDEHGFIAREFSRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAI
Squac
PAVAGPQQK
Bovin
VTAAPKK
Human
VTAAPKK
Rabbit
VTAAPKK
Mouse
VAAAPKK
Mesau
VTAAPKK
Rat
VTAAPKK
Anapl
AGAQRK
Chicken
AGSQRK
Search each item for a matching pattern, and highlight the results
PSequenceClass
Highlight
(
PSequenceClass
a
) {
var
s
=
a
.
Sequence
as
string
;
return
new
(
a
.
Name
,
a
.
Sequence
.
Revise(
s
.
FindString
(
protein
"EE"
),
Stain1
));
}
readonly
HArray
=
Highlight
(
each
ProteinArray
);
readonly
ShowHighlights
=
ShowSequence
(
HArray
, 84);
Squac
MDIAIQHPWLRRPLFPSSIFPSRIFDQNFGEHFDPDLFPSFSSMLSPFYWRMGAPMARMPSWAQTGLSELRLDKDKFAIHLDVK
Bovin
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPASTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Human
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWFDTGLSEMRLEKDRFSVNLDVKHF
Rabbit
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Mouse
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHF
Mesau
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHF
Rat
MDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHF
Anapl
MDITIHNPLIRRPLFSWLAPSRIFDQIFGEHLQESELLPASPSLSPFLMRSPIFRMPSWLETGLSEMRLEKDKFSVNLDVKHFS
Chicken
MDITIHNPLVRRPLFSWLTPSRIFDQIFGEHLQESELLPTSPSLSPFLMRSPFFRMPSWLETGLSEMRLEKDKFSVNLDVKHFS
Squac
HFTPEELRVKILGDFIEVQAQHEERQDEHGYVSREFHRKYKVPAGVDPLVITCSLSADGVLTITGPRKVADVPERSVPISRDEK
Bovin
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Human
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPA
Rabbit
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQAPGPERTIPITREEKPA
Mouse
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPA
Mesau
SPEELKVKVLGDVVEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Genetics
Page 114 of
114
Rat
SPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
Anapl
PEELKVKVLGDMVEIHGKHEERQDEHGFIAREFNRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAI
Chicken
PEELKVKVLGDMIEIHGKHEERQDEHGFIAREFSRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAI
Squac
PAVAGPQQK
Bovin
VTAAPKK
Human
VTAAPKK
Rabbit
VTAAPKK
Mouse
VAAAPKK
Mesau
VTAAPKK
Rat
VTAAPKK
Anapl
AGAQRK
Chicken
AGSQRK