INDEX SEARCH

Configuration

The visual appearance of the tree is described in configuration files. This includes the shape, color and positioning of the nodes and connections, the font used to draw the text inside the nodes and more.

Configuration files are plain text files with a .twg extension. They do not contain any tree data, but only instructions on how to draw the trees. These instructions can then be applied to arbitrary tree data files.

Configurations have the following structure:

All names in a configuration are case sensitive. Extra blank lines and whitespace characters are not significant, although it’s a good idea to use some form of indentation and to separate sections with blank lines. Line comments can be included by using the -- marker (two dash characters).

The following is an example of a complete configuration file:

[layout]                                     -- layout section start marker
    style                 layout             -- layout style
    rootPadX              70                 -- property definition; constan

[node]                                       -- node section start marker
    style                 rect               -- node style
    textPadY              fontSize * 0.7     -- property definition; expression

[connection]                                 -- connection section start marker
  {default}                                  -- 'default' level start marker
    style                 curve              -- connection style
    nodeLineWidthStart    1.5
    nodeLineWidthEnd      1.5

  {root}                                     -- 'root' level start marker
    @copy                 default            -- copy directive
    levelDepthMax         0                  -- level selector
    nodeLineWidthEnd      3.5                -- override nodeLineWidthEnd

[color]                                      -- color section start marker
    @include              "mycolor.twg"      -- include directive

Sections

Sections group sets of property definitions together that control one particular visual aspect of a tree (e.g. how the nodes are drawn). There are four section types in total, all of which must appear exactly once in a configuration in any order. These are the following:

layout
Controls the positioning of the nodes.
node
Controls how the individual nodes are drawn.
connection
Controls how the shapes connecting the nodes are drawn.
color
Defines the colors used for all drawing operations.

The start of the sections are denoted by section start markers, which are written as the name of the section in square brackets (e.g. [node]). Section start markers must be in a separate line. Everything that appears below a section start marker belongs to the section it denotes, until another section start marker is encountered or the end of file is reached. For example:

[layout]                                     -- [layout] starts
    style                 layout             --   belongs to the layout section
    rootPadX              70                 --   belongs to the layout section

[node]                                       -- [layout] ends, [node] starts
    style                 rect               --   belongs to the node section
    textPadY              fontSize * 0.7     --   belongs to the node section
                                             -- end of file, [node] ends

Levels

By default, property definitions within a section apply to all elements the section controls. For example, the following configuration snippet results in all nodes being drawn as rectangles and the node text typeset with a 14-point font:

[node]
    style                 rect
    fontSize              14

Many times, however, it is desirable to style certain groups of elements differently. For example, one might want to distribute the nodes into three groups, root node, leaf nodes and remaining nodes, and apply three distinct visual styles to these groups. Or the grouping could be based on the depth a particular node can be found at in the tree, so all nodes at depth 1 would be drawn in a certain style, nodes at depth 2 in another style, and so forth.

By using level definitions within a section definition, it is possible to refine the visual appearance of the tree by applying properties to certain groups of elements only. Levels can appear in the node, connection and color sections with the following syntax:

[section]
  {levelname}
    level selectors
    ...
    property definitions
    ...

As seen above, a level definitions consists of three parts:

In the example below, the root node is drawn as an octagonal polygon, the leaf nodes as ovals, and the rest of the nodes as rectangles:

../../_images/levels-example.png

This configuration snippet illustrates the use of level definitions to achieve the above results (non-relevant properties are omitted):

[node]
  {default}                                 -- level start marker
    style                   rect

  {leaf}                                    -- level start marker
    levelNumChildrenMax     0               -- level selector
    style                   oval

  {root}                                    -- level start marker
    levelDepthMax           0               -- level selector
    style                   poly
    numSides                8

Note

The order in which the level definitions appear are important — generic level definitions should always precede more specific ones. For instance, if the order of the levels was root, leaf and default, all nodes would have been drawn using the default style.

Level selectors

Level selectors provide a way to control which group of elements a particular level definition applies to. Level selectors can appear in level definitions only. They can be specified using the same name-value pair syntax as property definitions.

A level definition applies to an element if all level selectors specified within the level definition select a given element. In other words, there is an and relation between the level selectors specified within a level definition. Note that because of the and relation, the following level definition will never select any nodes:

{fail}
  levelNumChildrenMin   1
  levelNumChildrenMax   0

Multiple level definitions are allowed to appear in the same section. Level definitions within a section are evaluated in the order they appear in. Level definitions are not cascaded if more than one definition selects the same element — only the last level definitions that selects a particular element will apply.

The following level selectors can be specified in level definitions:

levelDepthMin
Type
Number
Values
>0
Default
0

Minimum depth of the node in the tree to be selected.

levelDepthMax
Type
Number
Values
>0
Default
999999999

Maximum depth of the node in the tree to be selected.

levelNumChildrenMin
Type
Number
Values
>0
Default
0

Minimum number of child nodes the node must have to be selected.

levelNumChildrenMax
Type
Number
Values
>0
Default
999999999

Maximum number of child nodes the node can have to be selected.

Below are some common level selector examples:

Select root node only

{root}
  levelDepthMax         0

Select all leaf nodes

{leaf}
  levelNumChildrenMax   0

Select leaf nodes at depth 2 or greater

{leaf}
  levelDepthMin         2
  levelNumChildrenMax   0

Directives

Directives are special commands that can appear anywhere within section and level definitions, just like regular properties. Directive names are always prefixed by a @ character and usually have at least one parameter. For example:

@copy                   normal

Currently, the following two directives are supported:

@copy <levelname>

Copy all property definitions from another level into the current one within the same section. The <levelname> parameter has to be the name of the level without the curly brackets.

The directive is only allowed to appear in level definitions. The level <levelname> does not have to be defined in the same file where the @copy directive appears in; it can also come from another configuration file that was included previously (see @include ).

The purpose of the @copy directive is to avoid duplication of configuration content where mostly similar, but slightly different sets of property definitions need to be applied to two (or more) distinct sets of elements. For example, one could define a default style that applies to all nodes, then apply a very similar style to the leaf nodes with only a few property definitions changed. In this sense, the @copy directive achieves something similar to the concept of inheritance in object-oriented programming languages with the ability to override certain property definitoins.

Note that as the contents of the configuration files are evaluated line by line from top to bottom, it is possible to override the copied properties by redefining them after a @copy directive, as shown in the example below.

In this example, all nodes are drawn as rounded rectangles, except for the root node, which is drawn as a regular rectangle:

[node]
  {normal}
    style                   rect
    roundness               1.0

  {root}
    @copy                   normal
    levelDepthMax           0
    roundness               0.0
@include <configname>

Include the contents of another configuration file into the current configuration. The <configname> argument is the full path to the configuration file to be included as a double-quoted string.

The most natural way to think about this is that when the parser encounters a line containing an @include directive, it simply replaces that line with the contents of the included configuration file and continues the parsing from there. There is no nesting depth limit, but two configuration cannot include each other. If such circular references are encountered, an error is raised and the execution stops.

The search order for included configuration files is the following:

  • The current directory (the directory the main Python script was started in)
  • $TWYG_USER/configs
  • $TWYG_HOME/configs

If the configuration file cannot be found in either of these locations, an error is raised and the execution stops.

For example:

[connection]
    @include                "connections/style1.twg"
    cornerRadius            40
    junctionRadius          17

Properties

Property definitions are name-value pairs separated by at least one whitespace character. Each configuration section and style has a distinct set of predefined properties. For a detailed description of all available properties see the Properties reference.

Property values can be either simple literal values:

rootPadX        70
fontName        "Gill Sans"
nodeColor       #f80

or expressions of arbitrary complexity:

fontSize        max(10, round(21 / sqrt(depth + 1)))

Expressions can contain mathematical operators (+, -, *, /, ^) and parentheses. The ^ operator is the power operator (e.g. 2^3). Standard mathematical operator precedence rules apply.

The important thing to remember is that the property value starts at the first non-whitespace character after the property name and it cannot span multiple lines.

There is an exception to this rule; array property values are allowed to span multiple lines:

nodeColors      [#af8700, #d75f00, #d70000, #af005f,
                 #5f5faf, #0087ff, #00afaf, #5f8700]

Property value types

Every property value has a type associated with it. These are the following:

Number

A numeric value:

level     5
width     103.2
stuff     -3.1516
String

A string in double-quotes. Double-quote characters within a string have to be escaped with a \ (backslash) character:

fontName  "Source Sans Pro"
name      "double-quotes (\"\") within a string"
Boolean

Used for turning a specific feature on or off. Valid values are:

  • on, yes, true, numbers greater than or equal to 1
  • off, no, false, numbers less than or equal to 0

The following expressions all evaluate to true:

sameWidthSiblings       1000
sameWidthSiblings       10 / 5 - 2 + 3            -- evaluates to 3 => true
sameWidthSiblings       false + no + off + yes    -- evaluates to 1 => true
Color
See Colors definitions for more information.
Enum

Property specific list of predefined values. See the Properties reference for details.

The predefined values can be referred to by their ordinal number as well. The numbering always starts from 0. For example, the junctionSign enum property has three predefined values, none, plus and minus, which correspond to the numeric values 0, 1 and 2. The following expression evaluates to minus:

junctionSign            32 / 8 * .5               -- evaluates to 2 => minus
Array

An array of values in square brackets ([]), separated by commas (,). Array definitions are allowed to span multiple lines:

nodeColors      [#af8700, #d75f00, #d70000, #af005f,
                 #5f5faf, #0087ff, #00afaf, #5f8700]

Variables

The following variables are available in property definition expressions. These variables are effectively properties of the node that is currently being processed. In case of connection properties, the node in question is always the one on the parent side of the connection.

  • x
  • y
  • width
  • height
  • maxTextWidth
  • bboxWidth
  • bboxHeight
  • textWidth
  • textHeight
  • lineHeight
  • fontSize
  • fontColor
  • bgColor
  • baseColor
  • connectionColor
  • fillColor
  • strokeColor

All variables are of numeric type, except the ones ending with Color, which contain color definitions.

Note that usually only a subset of these variables are available in a particular property definition.

Mathematical functions

The following mathematical functions can be used in property expressions:

abs(x)

Return the absolute value of x.

ceil(x)

Return the smallest integer value greater than or equal to x.

floor(x)

Return the larger integer value less than or equal to x.

log(x)

Return the natural (base-e) logarithm of x.

log10(x)

Return the base-10 logarithm of x.

max(x, y)

Return the largest of two values.

min(x, y)

Return the smallest of two values.

pow(x, y)

Return x to the power of y.

round(x)

Round x to the nearest integer value.

sqrt(x)

Return the square root of x.

Colors definitions

Colors can be specified in either hexadecimal or functional CSS3 notation. Below are some examples of valid CSS3 color definitions:

#ff8
#00427a
rgb(100, 100, 255)
rgb(11%, 20%, 42%)
rgba(255, 0, 79, 0.4)
rgba(11%, 100%, 0%, 0.1)
hsl(130, 30%, 80%)
hsla(99, 12%, 74%, 0.33)

Colors can also be specified using SVG 1.0 color keyword names in color.<colorname> format:

color.yellow
color.azure
color.darkseagreen

For a comprehensive description of the CSS3 color notation refer to the CSS Color Module Level 3 specification.

Color functions

There are a number of functions that can be used to manipulate colors. These functions can be invoked using the <color>.<function> syntax. For example:

#ff8.lighten(0.5)
color.blue.darken(0.2)
rgb(11%, 20%, 42%).blend(#fff, 0.5)

The following color manipulation functions are available. The parameter factor should be between 0.0–1.0. Values outside this range are clamped to the interval 0.0–1.0.

darken(factor)

Darken the color by a given factor.

color.red.darken(0.5)
#48a70f.darken(0.3)
lighten(factor)

Darken the color by a given factor.

color.fuchsia.lighten(0.3)
hsla(88, 30%, 68%, 0.7).lighten(.7)
blend(destcolor, factor)

Blend the color (source color) with destcolor by a given factor. A factor of 1.0 will result in the destination color and 0.0 in the source color.

#118833.blend(#fff, 0.8)
#777.blend(color.red, 0.6)
baseColor.blend(bgColor, 0.2)

Tip

The brightness of a color can be changed in two ways:

The blending method result in less saturated shades which might be preferable in some situations. The following table illustrates the difference between the two methods:

../../_images/color-blending.png