The Programming LanguageVersion 1.6.2.0
ContentsIntroductionThe Nytril Language..............................................................................................................................5Basic Syntax..........................................................................................................................................6Create a new project............................................................................................................................8Revision = {Properties + Elements}.......................................................................................................9Functions............................................................................................................................................13The 'each' operator.............................................................................................................................16Namespaces........................................................................................................................................17Numbers.............................................................................................................................................19Strings.................................................................................................................................................21Percentages........................................................................................................................................22Dates...................................................................................................................................................23Units....................................................................................................................................................24Currency.............................................................................................................................................26Arrays..................................................................................................................................................26Ranges................................................................................................................................................29Classes and Objects............................................................................................................................30FormattingBoxes..................................................................................................................................................33Colors and Fills....................................................................................................................................35Shapes.................................................................................................................................................39Transforms..........................................................................................................................................46Charts..................................................................................................................................................50Tables..................................................................................................................................................57Trees...................................................................................................................................................58Creating a Document..........................................................................................................................62Formatting Properties........................................................................................................................63Number Formatting............................................................................................................................67Math Formatting................................................................................................................................71Paragraph Formatting.........................................................................................................................77Image Formatting...............................................................................................................................83Hyperlinks and Tips.............................................................................................................................88MathematicsUser defined symbols.........................................................................................................................91Algebra................................................................................................................................................91Statistics..............................................................................................................................................94Vectors................................................................................................................................................98Matrices..............................................................................................................................................99Automatic Equation Typesetting......................................................................................................102
Local ResourcesProcesses..........................................................................................................................................103File System........................................................................................................................................103GeneticsBases.................................................................................................................................................107Proteins.............................................................................................................................................110Mutations.........................................................................................................................................111Staining.............................................................................................................................................112
Page 5 of 114IntroductionThe Nytril LanguageNytril 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 LaTEX. 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 PhilosophyA 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. PortabilityNytril 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 compilerNytril is a compiled language and the code for an entire nytril program is compiled before any of the
IntroductionPage 6 of 114statements 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. ConfigurationsYou 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. PublishingOnce 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 SyntaxNytril syntax is broadly similar to 'C' style languages like C#, Java and TypeScript. Literal strings are
The Nytril® Programming LanguagePage 7 of 114delimited by double quotation marks and have a standard syntax for escape characters. HelloWorld = Span { "Hello World"; "Line\nFeed"; "\tTab"; " Quotes \"\" are escaped";};Hello WorldLineFeedTab Quotes "" are escapedOutside 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 stringTo 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};Line12123abc3 meters
IntroductionPage 8 of 114Create a new projectLike 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..ProjectDouble-click on a project template. Specify a name for your project. Select OK.You should see the following on the screen: Start from scratchYour 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 LanguagePage 9 of 114Revision = {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 propertyAn 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 affinity132.23606797749979You '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};Text12A 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
IntroductionPage 10 of 114; // End of expression17 is the sum of 5 + 12Each 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 LanguagePage 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 {
IntroductionPage 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, 10You 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 LanguagePage 13 of 114Document = Block { HeaderStyle { "Introduction"; }; BodyStyle { "The rain in Spain lies mainly on the plane."; };};IntroductionThe rain in Spain lies mainly on the plane.FunctionsThere 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 globallyN1.F2(x) = x + 2; // F2 defined inside the namespace N1namespace 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 oncereadonly Cost = Data.Quantity * Data.Price; // Use like a variableFunctions 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.
IntroductionPage 14 of 114SquareNumber(x) { return x * x;}ShowSquares = Block { SquareNumber(4); SquareNumber(Symbol("x"));};16x2Note 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}7A 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);1000Unlike 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 LanguagePage 15 of 114ShowRandom = 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, 27If 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 onceShowMeasurements = 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.5020567368189475Values 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 timeShowGravity = Paragraph { TextAbbreviate: true; g;};9.8 ms2Global 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 = 1Number = 2Variables can be declared with a type, which can help the compiler catch common errors and possibly
IntroductionPage 16 of 114improve performance. var double TypedNumber = 2.7;ShowTypedNumber = Paragraph { "Number = "; TypedNumber;};Number = 2.7A 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: 1004Numbers multiplied: 4 inchesOther examples are show below. AffinityExample = Block { "String-" "String"; // Append "Example " 2; // Append 3 meters; // Multiply CiteOptions.AddSuffix CiteOptions.ShowDate; // Binary or};String-StringExample 23 metersShowDate AddSuffixThe 'each' operatorThe 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 LanguagePage 17 of 114 Separator: CommaSpace; Square(each [1, 2, 3, 4]);};1, 4, 9, 16If 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, 83, 9, 274, 16, 64Most 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]));4816927811664256NamespacesA 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 {
IntroductionPage 18 of 114 Products.Apple; Products.Lemon;};GalaMeyerNamespaces 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 abovenamespace 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; } }};VariableValueLouisVuittonLouis VuittonGucciGucciPradaPradaNamespaces 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 LanguagePage 19 of 114 foreach (var r in revenue) new DataPoint(each0, r.Value * 0.000001); };};YearRevenue(Millions)Year1Year2Year30200400600800100012001400NumbersAn integer is a simple sequence of decimal digits without a decimal pointIntegerValue = 42;42An unsigned integer is an integer that cannot have a negative valueUnsignedValue = 33U;33Here is a list of the numeric types that can be specified with a special suffixNumberTypeList = Block { typeof(2); typeof(2L); typeof(2U); typeof(2UL); typeof(2.0F); typeof(2.0D); typeof(2.0M);};intlonguintulongfloatdoubledecimalHexadecimal values can be specified by preceeding the number with 0xHexValue = 0x15;
IntroductionPage 20 of 11421Binary values can be specified by preceeding the number with 0bBinaryValue = 0b1101;13Real numbers are a sequence of decimal digits containing a decimal pointRealValue = 3.14;3.14Ratios of integers can be created using the operator overOneThird = 1 over 3;FractionSum = OneThird + 5 over 6;116Operations that mix real and fractional or integer values will be converted to real numbersDerivedValue = RealValue * FractionSum;3.6633333333333336Real numbers can be formatted to the desired number of decimal placesFormattedValue = {TextDigits:3} DerivedValue;3.663Digit groups for large numbers can be seperated using an underscore _SegmentedValue = 2_164_843;2164843Imaginary numbers can be expressed in a variety of formsImaginary1 = Symbolic.Sqrt(-1) + 1i + Math.I + (-1)^(1 over 2);4iImaginary numbers can be addedImaginary2 = 3i;;ISum = Imaginary1 + Imaginary2;7i
The Nytril® Programming LanguagePage 21 of 114Complex numbers are also supported, and real and imaginary parts are automatically aggregatedComplex1 = 3i + 2i + 5 + 3;8+5iComplex multiplication and powers are supportedComplex2 = Complex1 * (2i + 4);22+36iGet the real part of a complex number using the function:RealPart(x)For example:Real2 = Math.RealPart(Complex2);22Get the imaginary part of a complex number using the function:ImaginaryPart(x)For example:Imaginary3 = Math.ImaginaryPart(Complex2);36Get the modulus of a complex number using the function:Abs(x)For example:ComplexModulus = Math.Abs(Complex2);445 2StringsA 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 charactersAll array operations work on strings, in the same waySimpleString = "This is an array of characters";StringSlice = SimpleString[10..15];StringNew = SimpleString.Insert(5..11, "really ");This is an array of characters
IntroductionPage 22 of 114 arrayThis really is an array of charactersStrings 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 stillStrings can contain numbered sections that allow for substitutions supplied by arguments to the stringMessage = "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 argumentsWarning = "Please wait {1} seconds for {0}";WaitWarning = Warning("the report to generate", 5);Please wait 5 seconds for the report to generateThe arguments to a string format can be any type, including equations or picturesRootFormat = "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 12, The inverse square root of x is 1x, The inverse square root of two is 1twoPercentagesPercentages are specified using the operator %BaseRate = 10%;10%Percentages can be added together like normal numbersBonusRate = 4%;TotalRate = BaseRate + BonusRate;14.000000000000002%Percent values can be multiplied to yield a plain numeric valueSales = $1000;Payment = TotalRate * Sales;
The Nytril® Programming LanguagePage 23 of 114$140.00Some properties behave differently when a percent value is used. BigText = Span { TextHeight: 200%; // Percentage of existing TextHeight TextColor: 50%; // Gray scale "Big Text";};Big TextDatesA DateTime is specified using #YYYY-M-D:H:M:S# in source code.const DayOfBirth = #2016-1-31#; // YYYY-MM-DD2016-01-31A constant date can be specified directly in source code. A date value carries with it an indicator of the precision of its specificationconst TimeOfBirth = #2016-01-31 03:10:37.513#;2016-01-31 03:10:37.513Dates can be formatted with the field TextFormatFormatDate = Paragraph { DateTime.Now; TextFormat: "dddd, MMMM dd, yyyy";};Monday, August 03, 2026Dates can be operated on with time unitsTwinBirth = TimeOfBirth + 1 minute + 41 seconds;2016-01-31 03:12:18.513A time span is specified with TimeSpanTimeInHospital = new TimeSpan(2, 4);2d04:00:00Time spans can be added to datesFirstDayHome = TwinBirth + TimeInHospital;
IntroductionPage 24 of 1142016-02-02 07:12:18.513Subtracting two dates gives a TimeSpanClassTimeDifference = #2016-1-31 6:10:37.5# - #2012-1-31#;1461dTimeSpanClass members can be used to extract real numeric values for various units of timeDifference = Block { "{0} Years"(TimeDifference.Years); "{0} Days"(TimeDifference.Days); "{0} Hours"(TimeDifference.Hours); "{0} Minutes"(TimeDifference.Minutes); "{0} Seconds"(TimeDifference.Seconds);};4.000704663852765 Years1461.2573784722222 Days35070.177083333336 Hours2104210.625 Minutes126252637.5 SecondsUnitsMeasurment units are handled nativelyDistance = 16";16 inchesYou can convert between compatible units using the operator tounitMetricDistance = Distance tounit centimeters;40.64 centimetersCommon 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 inches4.25" = 4.25 inches6' = 6 feet
The Nytril® Programming LanguagePage 25 of 1146'2 = 74 inches6'3" = 75 inches6'3.5 = 75.5 inches6'3.25" = 75.25 inches5g = 5 grams5kg = 5 kilograms5cg = 5 centigrams5mg = 5 milligrams5l = 5 liters5ml = 5 milliliters6.25m = 6.25 meters5km = 5 kilometers5mm = 5 millimeters5cm = 5 centimeters5ft = 5 feet5in = 5 inches5mi = 5 miles5pt = 5 pts5px = 5 pixelsValues with different, but compatible, units can be added togetherLongerDistance = 3" + 25.4cm + 1';25 inchesUnits can be multiplied together to form units of higher dimensionArea = Distance * 2 yards;Volume = Area * 14.0" tounit centimeters^3;264,291 centimeters3Common conversions of higher dimension units are handled in the same wayLiquidMeasure = Volume tounit gallons;69.8181818182 gallonsMultiplications factor out the correct unitsWaterDensity = 1 kilogram per liter;LiquidWeight = WaterDensity * Volume tounit pounds;583 poundsThe power of water flowing over Niagra fallsWaterFlow = 1 mile^3 per year; // from the book "Energy" by Richard RhodesFallsHeight = 170 feet;g = 9.8 meters per second^2;Power = (WaterFlow * WaterDensity * FallsHeight * g) tounit megawatts;67 megawatts
IntroductionPage 26 of 114CurrencyMonetary quantities are supported nativelyPocketChange = 47¢;TotalChange = PocketChange + 3 Cents + $0.05;55¢Compatible currency values can be added togetherWalletCash = $12;TotalMoney = (WalletCash + TotalChange) tounit Dollars;$12.55Simple accruals can be calculated with a user-defined functionCompound(amount, rate, times) { while (times > 0) { amount += amount * rate; --times; } return amount;}Payments = Block { TextGroup: true; Compound($200_000, 4.1%, 5);};$244,502.69ArraysAn 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];1A 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 LanguagePage 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)
IntroductionPage 28 of 114For 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 structuresreadonly 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, 5An array can contain data of all types, including variables and formulas[2, 13, π, x2 + y2a]An array can include other arrays[A simple sentence, 0, 1, 2, 3, x, y, A, B, C, π2, i, 2, 13, π, x2 + y2a]The contents of two arrays can be joined together to make a larger array using the operator +
The Nytril® Programming LanguagePage 29 of 114[0, 1, 2, 3, x, y, A, B, C, π2, i, 2, 13, π, x2 + y2a]You can create another array which contains the result of the operation performed on each item in the array using the operator each[3, 113, π + 1, x2 + y2a + 1]This works for all operators and can be daisy-chained to apply to more than one operation[4a2, 19a2, (πa)2, x2 + y2]Function arguments can also be expanded using the operator each[8, 127, π3, x2 + y2a3]RangesA range is an ordered, inclusive pair of values using the operator .. SmallRange = 1..5;1..5A range can also use variables for the min or max valuesMin = 1;Max = 5;MinMax = Min..Max;1..5An 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]
IntroductionPage 30 of 114Exclude 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 ObjectsClass 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 LanguagePage 31 of 114 p2; // ..};1, 21, 2A 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; }
IntroductionPage 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}; };};BaseBCompoundB2Group(B2)3
Page 33 of 114FormattingBoxesValues 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);};123Values 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);};123Separators can be used to add an item between each item in the revisionBoxesWithSeparators = Paragraph { HBoxSet { Separation: 10pt; Separator: "+"; LastSeparator: "="; }; Space; VBoxSet { Separation: 2pt; Separator: SolidBox(Colors.Blue); LastSeparator: SolidBox(Colors.Red); };};
FormattingPage 34 of 1141+2=3 123Margins can be added outside any box to put distance between it and ajacent figuresBoxesWithMargins = 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 contentsBoxesWithPadding = 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 SeparationAddChildren(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]); }};123Separation 0123Separation 5123Separation 10Rounded corners can be specified using the BorderRadius field.Chicklet(text) = HBox(null, null, new Edge(2, 0, Colors.Blue)) {
The Nytril® Programming LanguagePage 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 RightA 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 3Colors and FillsThe 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);};
FormattingPage 36 of 114The 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.50An even color gradient can be formed using the function:public static LinearGradient LinearGradient.FromColorArray(Color[] colors)For example:
The Nytril® Programming LanguagePage 37 of 114readonly 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")}
FormattingPage 38 of 114Sinusoidal Heat MapGet 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 LanguagePage 39 of 114ColorStop[] 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));};VerticalHorizontalDiagonalUse 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 LeftTop RightCenteredBottom LeftBottom RightShapesCreate a self-contained shape using:DocFormatter Shape(Fill fill=null, Stroke stroke=null, FillRules fillrule=null, width=null, height=null)For example:
FormattingPage 40 of 114ZigZag = 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);SolidDashedDottedDashDotDashDotDotUse the linejoin parmeter to change the way line segments join together.LineJoinTable = EnumTable(LineJoins, attribute DrawLineJoin);MiterRoundBevelUse the endcap parameter to change the end-cap of the line.LineCapTable = EnumTable(LineCaps, attribute DrawLineCap);FlatSquareRoundUse the miterlimit parameter to limit ratio of the extent of a miter to the stroke size (default: 4.0).LineMiterTable = MiterTable([10, 1]);Miter LimitEffect101Automatically complete the path with a line segment using the function:DocFormatter ClosedPath(x, y=null)For example:
The Nytril® Programming LanguagePage 41 of 114TwoLines(closed) = (closed ? ClosedPath(1) : OpenPath(1)) { LineTo(1, 20); LineTo(20, 20);};OpenClose = Paragraph { ShowClose(Colors.Red, false); Tab; ShowClose(Colors.Green, true);};Closed: falseClosed: trueAdding 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)) {
FormattingPage 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 LanguagePage 43 of 114Create 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);};345678910Bezier 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.
FormattingPage 44 of 114Elliptic 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. largefalseclockwisefalse-30 degrees0 degrees30 degreesclockwisetrue-30 degrees0 degrees30 degreeslargetrueclockwisefalse-30 degrees0 degrees30 degreesclockwisetrue-30 degrees0 degrees30 degreesIf 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 LanguagePage 45 of 114largefalseclockwisefalseclockwisetruelargetrueclockwisefalseclockwisetrueUse 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: DefaultImagine 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. →  ← NonZeroImagine 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.
FormattingPage 46 of 114BigMouth = 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))); };};TransformsAn affine 2D transform is represented by a sparse 3x3 matrix (3 of the elements are zero)m11m120m21m220xy0The matrix is commonly represented more compactly as:[m11 m12 m21 m22 x y]The following shows mirror transforms about the originMirror - 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 LanguagePage 47 of 114All angles are specified in radians. Convert from degrees to radians using the operator degrees.Angle = 90 degrees;1.5707963267948966Below 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]
FormattingPage 48 of 114public 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. StartTranslateRotateScale ScaleRotateTranslateSet 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 LanguagePage 49 of 114};NormalFitUse 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"};BackwardsUse 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 DownUse the ClipPath to set the clipping path of the canvas or frameClippedText = Canvas { var r = new Rect(new(15pt), new(210pt, 35pt)); Canvas { TextHeight: 50pt; "Clipped Text"; ClipPath: r; }; Shape(null) { RectanglePath(r) };};Clipped TextClipping paths can be set to be figures of arbitrary complexityTextArt = Canvas { TextFigure(new(1)); Frame(2.2") {
FormattingPage 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 ChartsA 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 LanguagePage 51 of 114Yearly RainfallMonthinchesJanFebMarAprMayJunJulAugSepOctNovDec02468101214161820A pie chart can be created by changing the chart typePieChart = Chart(5", 2.5") { TextDigits: 2; ChartType: ChartTypes.Pie; XAxis: RainAxis; Legend: ChartLegend { Direction: Directions.Vertical; Placement: Placements.Right }; ChartSeries { WedgeGap: 2; RainPoints; };};JanFebMarAprMayJunJulAugSepOctNovDecThe data used for a chart can come from an equation represented by a function
FormattingPage 52 of 114Quadratic(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 = x2 − 50-15-13-11-9-7-5-3-102468101214-50-30-10103050Use the X field of the datapoint to set a specific x coordinate for a scatter plotRandomNumber = 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 LanguagePage 53 of 114};Random PointsOneTwo012345678910012345678910More than one series can be specified in the same chartAngleRange = 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); }};
FormattingPage 54 of 114Trig FunctionsCos(x)Sin(x)016π13π12π23π56ππ116π113π112π123π156π2π-1.0-0.8-0.6-0.4-0.2-0.00.20.40.60.81.0Use a stacked chart to compare data from different seriesActivationChart(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 LanguagePage 55 of 114LinepcDNA4TWp65BothdWRd1940100200300400 AreapcDNA4TWp65BothdWRd1940100200300400ColumnpcDNA4TWp65BothdWRd1940100200300400 Bar0100200300400pcDNA4TWp65BothdWRd194
FormattingPage 56 of 114StackedColumnpcDNA4TWp65BothdWRd1940100200300400500600 StackedBar0100200300400500600pcDNA4TWp65BothdWRd194StackedColumn100pcDNA4TWp65BothdWRd1940102030405060708090100 StackedBar1000102030405060708090100pcDNA4TWp65BothdWRd194
The Nytril® Programming LanguagePage 57 of 114Doughnut% IL7% IL8TablesA 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)};RainfallMonthValueErrorJanuary12.0 inches-1.0 +1.0February13.2 inches-1.0 +1.0March14.6 inches-1.0 +1.2April18.5 inches-1.0 +1.0May12.6 inches-0.6 +0.4June7.2 inches-1.0 +1.0July4.0 inches-1.0 +1.0August4.7 inches-0.4 +1.2September5.0 inches-1.0 +1.0October6.0 inches-1.0 +1.0November12.6 inches-1.0 +1.0December15.1 inches-1.0 +1.0Table 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;
FormattingPage 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 FunctionsAngleSin(x)Cos(x)Tan(x)0010112π0.258819045102520740.96592582628906830.267949192431122716π12321314π1212113π32123512π0.96592582628906830.2588190451025213.732050807568873612π10TreesA 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 LanguagePage 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;};RootAA1A2BCSome 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;};AB123456CA tree's contents may be generated recursively.Attribute[] TreeMarkers = [attribute Markers.Circle, attribute Markers.Square, attribute Markers.TriangleUp, attribute Markers.Diamond];
FormattingPage 60 of 114TreeColors = [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);};A0B0C0D0D1D2D3C1D0D1D2D3C2D0D1D2D3B1C0D0D1D2D3C1D0D1D2D3C2D0D1D2D3The structure of a math expression may be shown using the function:public object.GetExpressionTreeFor 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 LanguagePage 61 of 114 };};Equation = xσ2 + 5AddPowerDivideMultiply-1xσ25Tree structures can be read directly from a data file.ShowTrees = Block { ShowTreeName(each TreeFile.Trees);};tree nametree0ABtree1ABCtree3ABCDtree4FABECDtree5tree6tree7ABCD
FormattingPage 62 of 114tree8FABECDtree9FABECDTree structures can be formatted in a variety of ways using Bevel and Curvature settingsFormattedTrees = Block { ShowNexusTree(TreeFile.FindTree("tree4")); ShowNexusTree(TreeFile.FindTree("tree5"));};tree4CurvatureBevel0%50%100%0FABECDFABECDFABECD50%FABECDFABECDFABECD100%FABECDFABECDFABECDtree5CurvatureBevel0%50%100%050%100%Creating a DocumentA document is made by creating a new class that inherits DocumentEntry. Overload the function GetDocument and add new content.
The Nytril® Programming LanguagePage 63 of 114class HelloDocClass: DocumentEntry { Constructor { super.Constructor(#ab6ec337-2885-4777-b223-855509822fa5#, "Hello"); } override GetDocument = Document { "Hello World"; };}Formatting PropertiesUse 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: LargeThe following text is: BoldThe following text is: ItalicThe following text is: Large, Bold, ItalicIf 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 {
FormattingPage 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 LanguagePage 65 of 114 "Monospaced Text"; };};Normal TextMonospaced TextUse 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 articlesUse 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 WavyDoubleUse 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 DoubleYou 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!"; }; }; }};
FormattingPage 66 of 114Nonehello Hello HELLO!AllUpperHELLO HELLO HELLO!AllLowerhello hello hello!WordUpperHello Hello Hello!FirstUpperHello Hello HELLO!FirstLowerhello Hello HELLO!SmallCapshello 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." }; }; }};1The quick brown fox jumped over the lazy dog.2The quick brown fox jumped over the lazy dog.3The quick brown fox jumped over the lazy dog.4The quick brown fox jumped over the lazy dog.5The 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 LanguagePage 67 of 114 1..5 step 1;};1, 2, 3, 4, 5Change the final separator in the revision with the LastSeparator property.ShowLastSeparator = Paragraph { Separator: ", "; LastSeparator: " and "; 1..5 step 1;};1, 2, 3, 4 and 5To 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};};11 and 21, 2, and 3Number FormattingUse 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;};42Functions 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);};
FormattingPage 68 of 114The output of X(5) is 28To format an integer in hexadecimal, change the TextRadix to 16. IntegerHexadecimal = Span { TextRadix: 16; 129579;};1fa2bTo have the hex digits shown in upper-case, change the TextCase property to AllUpper. IntegerHexadecimalUpper = Span { TextRadix: 16; TextCase: AllUpper; 671277;};A3E2DTo format a number in binary, use 2 as the TextRadix. IntegerBinary = Span { TextRadix: 2; 127;};1111111Use 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;};0004001b2fd5To 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 LanguagePage 69 of 114Use 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,67As with integers, to a format a number of type double, include it as an element in the revision. DoubleFormatting = Span { 4325.1245;};4325.1245Formatting a return value from a function works the same way. DoubleReturn = Span { Math.Sqrt(1 + 1);};1.4142135623730951Use the TextDigits property to fix the number of fractional digits in the number. DoubleDigits = Span { TextDigits: 3; Math.PI;};3.142Set 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;
FormattingPage 70 of 114};43305.420.000643122000000000.000000000120Format the number in scientific notation by setting TextScientific to true. ScientificNotation = Span { TextScientific: true; TextDigits: 2; 175_000;};1.75x105Notice 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.2x106You 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.2123.990.5544Use 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 LanguagePage 71 of 114181212341116Math FormattingCreate 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 32x raised to the power of y is xyThe independent variable 'y'Create several different types of common fractions with the Fraction formatter.FormatFraction = Fraction { x; y+1;};xy + 1Format the fraction with a diagonal slash by setting the diagonal argument to true. SlantedFraction = Fraction(true) { x; y ^ 2;};xy2Create a more compact fraction layout by setting the compact argument to true. ThreeQuarters = Fraction(false, true) {3; 4};
FormattingPage 72 of 114CompactFraction = Span { "Add "; ThreeQuarters; " of a cup of flour. ";};Add 34 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 12 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 113 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;x1Use 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 = mc2The speed of lightSquare-root symbols can be created with the Radical formatter. Solution = Paragraph { "The solution is: "; Tex.pm; Radical { x; Tex.Plus; 2;
The Nytril® Programming LanguagePage 73 of 114 };};The solution is:  ± x + 2Change the degree of the radical by setting the Degree propertyV = 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 V3The 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]Operatorpre-upperpre-lowerupperlowerSet 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};};1nsUse 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;
FormattingPage 74 of 114 Lower: x Tex.Equals 1; }; Fraction { 1; x^2; }; Tex.nbsp; Tex.derivative; x;};f(x) = x=11x2 dxPlace the superscripts and subscripts above and below the Operator by setting the TextStacked property to true. StackedNary = InverseSquareIntegral { TextStacked: true;};f(x) = x=11x2 dxUse 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");Th23290The 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; };};psps − 1If 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 LanguagePage 75 of 114LineEquation = Paragraph { TextEquation: true; TextStacked: true;};ZetaEquivalence = LineEquation { Tex.zeta; "("; s; ")"; Tex.Equals; ZetaSum; Tex.Equals; ZetaProduct;};ζ(s) = 1ns = psps − 1Here 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);ax5 + bx4 + cx3 + dx2 + ex + fUse 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;};ex = limn→∞1 + x1! + x22! + x33! +  + xnn!Choose from a wide variety of arrow and bracket styles.
FormattingPage 76 of 114VerticalBrackets = 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"};};OverUnderbar aboveflat curly belowround aboveEnclose 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 1Topic 2Topic 3Here 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 LanguagePage 77 of 114Use 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");};Th23290 α Ra22888 β Ac22889Matrices 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π2341x + 2y + 5811π2341x + 2y + 5811π2341x + 2y + 581Paragraph FormattingParagraphs 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
FormattingPage 78 of 114already 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 OneParagraph Two2.414213562373095A 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 1Line 2Line 3Default block formatOverridden formatA 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 JordanUse 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 LanguagePage 79 of 114Greatness = 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 NightAlignment of the text can be controlled with the ParAlignment property. SmallBlock = Block { Paragraph {ParAlignment: Left; "Left"}; Paragraph {ParAlignment: Center; "Center"}; Paragraph {ParAlignment: Right; "Right"};};LeftCenterRightThe 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 HandeyThe 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)
FormattingPage 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"; };};LeftCenter3.1415....................................................RightLeft AlignCenter Align527.10...............................................Right AlignA 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 textA 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 LanguagePage 81 of 114 ParAlignment: Center; Bold; "Header";};HeaderAdd extra space before the start of a paragraph using the SpaceBefore property. ParSpaceBefore = Block { Bold "Header"; Paragraph { "First line"; SpaceBefore: 200%; };};HeaderFirst lineSpace before the paragraphAdd extra space after the end of a paragraph using the SpaceAfter property. ParSpaceAfter = Block { Paragraph { SpaceAfter: 200%; TextHeight: 120%; Bold; "Title"; }; "Body text";};TitleBody textSpace after the paragraphSet 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 sidestop - bottom
FormattingPage 82 of 114left - rightParagraph borders can also have different colors and paddingColorBorder = Paragraph(new Edge(3pt, 5pt, Colors.Red)) { ParAlignment: Center; ParBackground: #FCFCF4#; LeftIndent: 16pt; RightIndent: 15pt; Bold; "Very Important Notice";};Very Important NoticeChange 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 POINTSStatement of Relevant FactsDouble-spaced linesUse 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 1IntroductionConsider 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 LanguagePage 83 of 114Emphasis = Span {Italic; TextColor: Colors.Red};Chapter2 = Block { Heading1 {"Chapter 2"}; Heading2 {"Introduction"}; Body {"I would like to "; Emphasis {"emphasize"}; " the following points. "};};Chapter 2IntroductionI 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 1IntroductionConsider the curious case of Dr. Jeckle. Chapter 2IntroductionI would like to emphasize the following points. Image FormattingImages 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%);};
FormattingPage 84 of 114Zombies 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 LanguagePage 85 of 114Set 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 proportionUse 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 LanguagePage 87 of 114readonly 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 folderHere 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 YouTubehttps://www.youtube.com/@Nytril
FormattingPage 88 of 114Hyperlinks and TipsUse 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.comUnderlined on mouse-overIf 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 webHidden URL, underlined text on mouse-overUse 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 answerThe answer is 42Use 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 onlinehttps://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 Editionhttps://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 114MathematicsUser defined symbolsSymbols are special values that can represent constants or variablesx = Symbol("x");xThe typeset representation of a symbol can differ from its variable namesigma = Symbol("σ");σYou can create symbols with subscripts and superscriptsSigmaNaught = sigma sub 0;XSquared = x sup 2;SymbolSum = XSquared + SigmaNaught;x2 + σ0AlgebraAddition is carried out using the operator +Number = 1 + 3;Sum = Number + x;4 + xSubtraction is carried out using the operator -Difference = 5 - 7;-2Multiplication is carried out using the operator *Product = 5 * 3;15Rational division is carried out using the operator overRatio = 3 over 5;35
MathematicsPage 92 of 114Floating point division is carried out using the operator /, the result is a floating point number.RealDivision = 3 / 5;0.6Integer division (even division without a remainder) is carried out using the operator divIntResult = 8 div 5;1The remainder after integer division can be found using the operator modRemainder = 8 mod 5;3A value can be raised to a power using the operator ^Power = 4^2;16Symbols obey the rules of algebra when combined with other symbols and numbersPolynomial = a x^2 + b x + c;ax2 + bx + cBasic algebra is performed automatically when symbols are multipled or addedAddX = 2 x + 5 x + 3;7x + 3Combined terms can be expanded using the function:public object.GetExpandedTermsFor example:CompareAll = [ CompareEquations(14), CompareEquations((3 x + y) * x * y), CompareEquations(2 * (6 + y) * y), CompareEquations((3 x + 1) * 1 * x),];14=> 14(3x + y)xy=> 3x2y + y2x2(6 + y)y=> 12y + 2y2(3x + 1)x=> 3x2 + x
The Nytril® Programming LanguagePage 93 of 114The operator between common types can be ommited in simple expressionsThreeX = 3 x;g = 9.8 meters per second^2;Palindrome = "was it " "a car " "or a cat I saw";3x9.8 meterssecond2was it a car or a cat I sawGet 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);-22.718281828459045Get 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);510xGet 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.6761611.69314718055994522.9999999999999996
MathematicsPage 94 of 1144Get 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, 720StatisticsStatistics 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 = xini=1where n is the length of the array and xi is the ith element. It can be computed using the function:double Sum(double[] values)For example:SumData = Math.Sum(NumberSet);32.5The product of an array is defined as:P = xini=1where n is the length of the array and xi is the ith element. It can be computed using the function:double Product(double[] values)For example:ProductData = Math.Product(NumberSet);19388.16The arithmetic mean of an array is defined as:x = xini=1nwhere n is the length of the array and xi is the ith element. It can be computed using the function:
The Nytril® Programming LanguagePage 95 of 114double Mean(double[] values)For example:MeanData = Math.Mean(NumberSet);5.416666666666667The harmonic mean of an array is defined as:H = n1xini=1where n is the length of the array and xi is the ith element. It can be computed using the function:double HarmonicMean(double[] values)For example:HarmonicMeanData = Math.HarmonicMean(NumberSet);4.976299376299376The geometric mean of an array is defined as:H = xini=1nwhere n is the length of the array and xi is the ith element. It can be computed using the function:double GeometricMean(double[] values)For example:GeometricMeanData = Math.GeometricMean(NumberSet);5.183098144673662The 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]);2The variance of an array is defined as:
MathematicsPage 96 of 114σ2 = (xi − x)2ni=1nwhere x is the mean.It can be computed using the function:double Variance(double[] values)For example:VarianceData = Math.Variance(NumberSet);2.771388888888889The standard deviation of an array is defined as:σ = (xi − x)2ni=1nIt can be computed using the function:double StandardDeviation(double[] values)For example:StdDevData = Math.StandardDeviation(NumberSet);1.6647488966474462The standard scores (Z-scores) for every element in an array can be calculatedZ = 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 = (Oi − Ei)2Eini=1
The Nytril® Programming LanguagePage 97 of 114Where Oi is the ith observed value and Ei is the ith 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.7083333333333333You can perform a simple regression analysis on two datasets using:sealed class Math.LinearRegressionFor 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 PreMath.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.86279259953732The Correlation Coefficient of two datasets is defined as:r = (xi − x)(yi − y)ni=1(xi − x)2ni=1(yi − y)2ni=1It can be computed using the function:public readonly double Math.LinearRegression.CorrelationFor example:Correlation = Regression.Correlation;0.8506559172499765Here is an example of how to add regression lines to a chartCricketChart = 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;
MathematicsPage 98 of 114 Label: "Temperature"; foreach (var x in Temperature) new DataPoint(x, ChirpsPerSec[each0]); }; }};Cricket Chirps vs. TemperatureTemperature (F)CricketChirps687072747678808284868890929402468101214161820VectorsVector 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 VectorI10 = new Vector(5, a);[a, a, a, a, a]Vectors of the same size can be added together using the operator +
The Nytril® Programming LanguagePage 99 of 114VAdd = 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);ac + bd22The 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]);[bz − cy, cx − az, ay − bx][-3, 6, -3]The norm of a vector is calculated using the function:public Vector.NormFor example:VNorm = V1.Norm;NNorm = N1.Norm;a2 + b24.47213595499958The normalize form of a vector is calculated using the function:public Vector.NormalizeFor example:VNormalize = V1.Normalize;NNormalize = N1.Normalize;[aa2 + b2, ba2 + b2][0.8944271909999159, 0.4472135954999579]MatricesMatrix objects represent a 2 dimensional array of numbers or symbols of a fixed size.
MathematicsPage 100 of 114x = 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]]);14317589abcdefghMatrices can be initialized with uniform contents and an optional diagonal element for square matricesI52 = new Matrix(4, 4, 0.0, 1.0);1000010000100001Matrices of the same size can be added together using the operator +VAdd = V1 + V2;NAdd = N1 + N2;a + eb + fc + gd + h891110Matrices of the same size can be subtracted using the operator -VSub = V1 - V2;NSub = N1 - N2;a − eb − fc − gd − h-6-1-5-8The determinant of a matrix is calculated using the function:public Matrix.DeterminantFor example:
The Nytril® Programming LanguagePage 101 of 114VDet = V1.Determinant;NDet = N1.Determinant;ad − bc-11The inverse of a matrix is calculated using the function:public Matrix<any> Matrix.InverseFor example:VInv = V1.Inverse;NInv = N1.Inverse;dad − bcbad − bccad − bcaad − bc-0.090909090909090910.363636363636363650.2727272727272727-0.09090909090909091The transposition of a matrix is calculated using the function:public Matrix<any> Matrix.TransposeFor example:VTran = V1.Transpose;NTran = N1.Transpose;acbd1341The normalize form of a matrix is calculated using the function:public Matrix<any> Matrix.NormalizeFor example:VNormalize = V1.Normalize;NNormalize = N1.Normalize;aad − bcbad − bccad − bcdad − bc-0.09090909090909091-0.36363636363636365-0.2727272727272727-0.09090909090909091The cofactor matrix of a given square matrix is calculated using the function:public Matrix<any> Matrix.CofactorMatrixFor example:VCofactor = V1.CofactorMatrix;NCofactor = N1.CofactorMatrix;TCofactor = Matrix.Convert([[1, 2, 3], [0, 4, 5], [1, 0, 6]]).CofactorMatrix;dcba1-3-41
MathematicsPage 102 of 114245-4-1232-2-54Automatic Equation TypesettingUnresolved square roots are automatically typesetx = Symbol("x");y = Symbol("y");SquareRoot = x^(1 over 2);xHigher roots are also typesetCubeRoot = x^(1 over 3);x3Equations of arbitray complexity will be typesetPart1 = (x / y)^(1 over 3);Part2 = Part1 + x/y + x^2/y + (x^3/y^5)^(1 over 3) + x;xy3 + xy + x2y + x3y53 + xExpressions can be combined to form larger formulasLargeEquation = Symbolic.Sqrt(Part1 / Part2);xy3xy3 + xy + x2y + x3y53 + x
Page 103 of 114Local ResourcesProcessesAn executable file can be run using ProcessConsole = 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 SentBytes 1872272320 1814403950Unicast packets 10115256 17189496Non-unicast packets 205008 13446Discards 0 0Errors 0 0Unknown protocols 0File SystemGet 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 ResourcesPage 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 NameCreatedSizeAngle Calculator.nytril02-16-20257624Body Mass Index.nytril09-24-20251873Chemistry.nytril09-24-20254316Color Picker.nytril09-20-20231662Data Tables.nytril09-24-20253885Doc With Sidebar.nytril11-29-2021849Embedded Data.nytril11-29-20211604Equations.nytril06-18-20259619Examples Home.nytril05-05-20262094Finance.nytril09-16-2025899Finger Binary.nytril05-10-20263313FizzBuzz.nytril02-08-2024650Font Families.nytril05-06-20261196Hello World.nytril10-06-2018247Input Form.nytril09-24-20256443International.nytril05-26-20263038Mad Lib.nytril09-24-20255050Matrix Calculations.nytril03-08-20221955Mortgage Calculator.nytril09-24-20256781Opacity Examples.nytril09-24-20253296Paragraph Examples.nytril11-03-20211277Party Signs.nytril09-24-20251827Random Walk.nytril09-24-20257265Read Text File.nytril10-01-2023308SieveOfEratosthenes.nytril02-09-20241213Simple Document.nytril09-24-2025807Source Reflection.nytril09-24-20251192Split The Bill.nytril11-29-20213913Sub Realm United States.nytril05-06-2026456Table Edges.nytril09-06-20204798Time Sheet.nytril09-24-20254021White Paper.nytril03-25-202612433Get a listing of folders using the function:
The Nytril® Programming LanguagePage 105 of 114FileEntry[] 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 NameCreatedCitations07-23-2021Database06-13-2024Documentation Workflow02-22-2026Family Tree08-07-2020History11-23-2021Import09-16-2025JSON04-22-2024Mail Merge07-14-2020Map08-09-2024Math Homework07-23-2021Phylo07-14-2020Quotations04-02-2025Recipes07-14-2020Resumes06-18-2020Scuba Watch06-03-2025Web04-29-2025XML09-25-2023
Page 107 of 114GeneticsBasesBases can be specified by using built-in symbols joined together with a + sign to form a sequenceBase1 = Dna.Cytosine + Dna.Guanine;CGBases can be combined into a base set using the binary or operator | Set1 = Dna.Thymine | Dna.Guanine;KLonger sequences can be input by using the correct string prefixDNA1 = dna"ACTG";RNA1 = rna"UGAC";Codons1 = codon"<MDI><AIHHPWIRR>";Protein1 = protein"MDIAIHHPWIRR";ACTGUGAC<MDI><AIHHPWIRR>MDIAIHHPWIRRUse string functions to generate several variations of a sequenceDNAFunc = dna"AC{0}TG";Call = DNAFunc(Dna.N);Iterate = DNAFunc(each [dna"-AA-", dna"-CC-", dna"-TT-", dna"-GG-"]);ACNTGAC-AA-TGAC-CC-TGAC-TT-TGAC-GG-TGSequences can be repeated by using using the operator * with an integerPromoter = 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 otherGene2 = Promoter 30 dna"CCTCCCAGG";TATAAA------------------------------CCTCCCAGG
GeneticsPage 108 of 114Common variants can be constucted without repeating or losing informationHighlight = {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; }; }};TypeVariantSubstitutionATTGGCCTTAACCCCCGATTATCAGGAT ⇒ ATTGGCCTTAACCCTCGATTATCAGGATInsertionATTGGCCTTAACCCCCGATTATCAGGAT ⇒ ATTGGCCTTAACCCC---CGATTATCAGGATDeletionATTGGCCTTAACCCCCGATTATCAGGAT ⇒ ATTGGCCTTAACCCCTTATCAGGATInversionATTGGCCTTAACCCCCGATTATCAGGAT ⇒ ATTGGCCTTGCCCCCAAATTATCAGGATCopy NumberATTGGCCTTAACCCCCGATTATCAGGAT ⇒ ATTGGCCTTAGGCCTTAACCCCCGATTATCAGGATSequences can also be read from files using the function:ReadDocument(path_or_blob, FileFormat fileformat=null)
The Nytril® Programming LanguagePage 109 of 114For 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 geneatgtctaaagctggaaccaaaattactttctttgaagacaaaaactttcaaggccgccactatgacagcgattgcgactgtgcagatttcRevisions are used to control sequence formattingGeneFormatted = Span { TextColumns: 30; TextDivision: 5; GeneSlice;};atgtc taaag ctgga accaa aatta ctttc tttga agaca aaaac tttca aggcc gccac tatga cagcg attgc gactg tgcag atttcSections 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);atgtctaaagctggaaccaaaattactttctttgaagacaaaaactttcaaggccgccactatgacagcgattgcgactgtgcagatttcRNA sequences are constructed in the same way using the operator rnaRNASequence = rna"ACUG" + Rna.Uracil + Rna.Adenine;ACUGUADNA can be transcribed into RNA using the operator rnaComputedRNA = rna GeneStained;AUGUCUAAAGCUGGAACCAAAAUUACUUUCUUUGAAGACAAAAACUUUCAAGGCCGCCACUAUGACAGCGAUUGCGACUGUGCAGAUUUCRNA can be converted into codons using the operator codon
GeneticsPage 110 of 114ComputedCodons = codon ComputedRNA;<SKAGTKITFFEDKNFQGRHYDSDCDCADFRNA or codons can be translated into a protein using the operator proteinComputedProtein = protein ComputedRNA;SKAGTKITFFEDKNFQGRHYDSDCDCADFProteins 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, GGC, GGA, GGG, CGU, CGC, CGA, AGA, CGG, AGG, CAU, CAC, UAU, UAC, GAU, GAC, UCU, AGU, UCC, AGC, UCA, UCG, GAU, GAC, UGU, UGC, GAU, GAC, UGU, UGC, GCU, GCC, GCA, GCG, GAU, GAC, UUU, UUC]ProteinsProteins can be input directly using using the operator proteinProtein1 = protein"AVG";AVGProteins can also be built up from smaller segments using the same rules as for dna and rnaProtein2 = Protein1 Amino.Phenylalanine Amino.Aspartate;AVGFDCodons can be computed from RNA sequencesAllRNATriplets = rnaGUGGCGGAGGG"GUGGCGGAGGG"GUGGCGGAGGG";RNACodons = codon AllRNATriplets;FFLLSSSSYY>>CC>WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGGIf 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 codonCodons = codon"<FTGN>";
The Nytril® Programming LanguagePage 111 of 114Protein3 = protein Codons;FTGNArrays of proteins can also be created from back-to-back sequences of codonsProteinArray= protein codon"--<FTGN>----<MQS>--";FTGNMQSA 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]MutationsLong sequences can be built up from short sequences using the operator +CompleteRegion = dna"TATAAA" + 20 + Gene2;TATAAA--------------------GCTGATTCSections can be inserted into existing sequences using the function:public [] Array.Insert(range, value)For example:InsertedRegion = CompleteRegion.Insert(10, dna"AACCTTGG");TATAAA----A----------------GCTGATTCSections can be removed from existing sequences using the function:public [] Array.Remove(range)For example:DeletedRegion = InsertedRegion.Remove(16..28);TATAAA----A-----TGATTCSections can be replaced using the function:public [] Array.Substitute(range, value)For example:Substitution = DeletedRegion.Substitute(12..17, dna"GGGGG");
GeneticsPage 112 of 114TATAAA----A-GGGGGGATTCRepetitive sequences like Alu elements can be encoded to highlight unique sectionsAluElement = dna"GCCGGGCGCGGTGGCGCGTGCCTGTAGTCCC{0}GTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTC"GTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTC";Stain = {TextColor: Colors.White; TextBackground: Colors.Red};AluExample = AluElement(Stain dna"AGCT") * 5;GCCGGGCGCGGTGGCGCGTGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCGCCGGGCGCGGTGGCGCGTGCCTGTAGTCCCAGCTACTCGGGAGGCTGAGGCTGGAGGATCGCTTGAGTCCAGGAGTTCTGGGCTGTAGTGCGCTATGCCGATCGGAATAGCCACTGCACTCCAGCCTGGGCAACATAGCGAGACCCCGTCTCSequences can be formatted to fit in regular columnsAluFormat = Span { TextColumns: 40; TextDivision: 5; TextHeight: 8pt; AluExample;};GCCGG GCGCG GTGGC GCGTG CCTGT AGTCC CAGCT 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 TCCCA GCTAC 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 CCAGC TACTC 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 AGCTA 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 CCCAG CTACT CGGGA GGCTG AGGCT GGAGG ATCGC TTGAG TCCAG GAGTT CTGGG CTGTA GTGCG CTATG CCGAT CGGAA TAGCC ACTGC ACTCC AGCCT GGGCA ACATA GCGAG ACCCC GTCTCStainingUse an array of proteins included from an external filereadonly PSequenceClass[] ProteinArray = [ new("Squac", Proteins.crab_squac), new("Bovin", Proteins.crab_bovin),
The Nytril® Programming LanguagePage 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);SquacMDIAIQHPWLRRPLFPSSIFPSRIFDQNFGEHFDPDLFPSFSSMLSPFYWRMGAPMARMPSWAQTGLSELRLDKDKFAIHLDVKBovinMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPASTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFHumanMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWFDTGLSEMRLEKDRFSVNLDVKHFRabbitMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFMouseMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFMesauMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHFRatMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHFAnaplMDITIHNPLIRRPLFSWLAPSRIFDQIFGEHLQESELLPASPSLSPFLMRSPIFRMPSWLETGLSEMRLEKDKFSVNLDVKHFSChickenMDITIHNPLVRRPLFSWLTPSRIFDQIFGEHLQESELLPTSPSLSPFLMRSPFFRMPSWLETGLSEMRLEKDKFSVNLDVKHFSSquacHFTPEELRVKILGDFIEVQAQHEERQDEHGYVSREFHRKYKVPAGVDPLVITCSLSADGVLTITGPRKVADVPERSVPISRDEKBovinSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPAHumanSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPARabbitSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQAPGPERTIPITREEKPAMouseSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPAMesauSPEELKVKVLGDVVEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPARatSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPAAnaplPEELKVKVLGDMVEIHGKHEERQDEHGFIAREFNRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAIChickenPEELKVKVLGDMIEIHGKHEERQDEHGFIAREFSRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAISquacPAVAGPQQKBovinVTAAPKKHumanVTAAPKKRabbitVTAAPKKMouseVAAAPKKMesauVTAAPKKRatVTAAPKKAnaplAGAQRKChickenAGSQRKSearch each item for a matching pattern, and highlight the resultsPSequenceClass 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);SquacMDIAIQHPWLRRPLFPSSIFPSRIFDQNFGEHFDPDLFPSFSSMLSPFYWRMGAPMARMPSWAQTGLSELRLDKDKFAIHLDVKBovinMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPASTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFHumanMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWFDTGLSEMRLEKDRFSVNLDVKHFRabbitMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFPTSTSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFMouseMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRLEKDRFSVNLDVKHFMesauMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHFRatMDIAIHHPWIRRPFFPFHSPSRLFDQFFGEHLLESDLFSTATSLSPFYLRPPSFLRAPSWIDTGLSEMRMEKDRFSVNLDVKHFAnaplMDITIHNPLIRRPLFSWLAPSRIFDQIFGEHLQESELLPASPSLSPFLMRSPIFRMPSWLETGLSEMRLEKDKFSVNLDVKHFSChickenMDITIHNPLVRRPLFSWLTPSRIFDQIFGEHLQESELLPTSPSLSPFLMRSPFFRMPSWLETGLSEMRLEKDKFSVNLDVKHFSSquacHFTPEELRVKILGDFIEVQAQHEERQDEHGYVSREFHRKYKVPAGVDPLVITCSLSADGVLTITGPRKVADVPERSVPISRDEKBovinSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPAHumanSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPARabbitSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQAPGPERTIPITREEKPAMouseSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLAITSSLSSDGVLTVNGPRKQVSGPERTIPITREEKPAMesauSPEELKVKVLGDVVEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPA
GeneticsPage 114 of 114RatSPEELKVKVLGDVIEVHGKHEERQDEHGFISREFHRKYRIPADVDPLTITSSLSSDGVLTVNGPRKQASGPERTIPITREEKPAAnaplPEELKVKVLGDMVEIHGKHEERQDEHGFIAREFNRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAIChickenPEELKVKVLGDMIEIHGKHEERQDEHGFIAREFSRKYRIPADVDPLTITSSLSLDGVLTVSAPRKQSDVPERSIPITREEKPAISquacPAVAGPQQKBovinVTAAPKKHumanVTAAPKKRabbitVTAAPKKMouseVAAAPKKMesauVTAAPKKRatVTAAPKKAnaplAGAQRKChickenAGSQRK