Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Panel
titleProject Information

Responsible:

The KGraph Text (KGT) project provides a textual syntax and editor for specifying KGraphs. While editing the KGraph in the textual editor, we provide a visualization of the graph in a KLighD view. This project was started with two use cases in mind:

...

Table of Contents

Quick Start Tutorial

This short tutorial will walk you through writing your first KGT file. Grab a cup of tea and a few biscuits and work your way through itTo quickly get you up to speed on how to write basic KGT files, we have a full-blown tutorial available for you learning pleasure. Once you've completed that, the rest of this page will provide a more comprehensive description of the KGT syntax.

The KGraph Text Format

In this section, we will take a closer look at the KGT syntax. We will start with the basic syntax. We will then take a look at the different kinds of objects available in KGT and at specifying parameters and properties of these objects.

Start by adding a few nodes. Enter the following text into the editor:

...

Info
titlePrerequisites

Before starting the tutorial, make sure that you have an Eclipse installation with the KIELER KGraph Editing and Visualization feature installed.

...

Shortcut

If you prefer reading Xtext grammars, you will find it over here.

Basic Syntax

In KGT, the KGraph is specified by listing the nodes in the graph, their ports, edges, and labels. The specification of each type of object follows the same basic syntax:

Code Block
type [id] <details>

An ID is only necessary if an object needs to be referenced later. For example, if you define a port that you want to connect an edge to, the port better have an ID or you won't be able to specify which port the edge should connect to. The details field doesn't always contain information. In fact, it is only necessary for the text of labels and for the source and target points of edges (see the next section for more details).

With this basic syntax, the following text specifies a complete KGraph with three nodes with the IDs n1n2, and n3:

Code Block
titleExample
linenumberstrue
knode n1
knode n2
knode n3

The KGraph itself is simply a list of objects. Some objects can be (and are sometimes expected to be) nested in other objects. For instance, a port must always belong to a node. To be able to add objects to other objects, we extend the basic syntax a little:

Code Block
type [id] <details> {
    <declarations>
}

If nodes n2 and n3 should be nested inside n1, the previous example must be changed a little:

Code Block
titleExample
linenumberstrue
knode 

...

n1 {
    

...

The KLighD view should update itself and show a rectangle that represents the node. Add two other nodes, node2 and node3, to the graph.

Let's add connection points to the nodes. Add two ports to node1 by adding the following text under the size specification of the node:

...

titleNodes with ports
linenumberstrue

...

knode n2
    knode n3
} 

Types of Objects in the KGraph

Now that we know the basic way of specifying objects, it's time to see what types of objects there are, which other objects they can appear in, and whether they require any details.

TypeKeywordDetailsTo appear inRemarks
NodeknodeEmptyTop level, nodes 
PortkportEmptyNodes 
LabelklabelString (label text):
"My gigantically useful label text"
Nodes, ports, edges 
EdgekedgeSource and target:
(:sourcePortId -> targetNodeId:targetPortId)
NodesEdges must always be defined in their source node. That is why the source node is not defined in the details.

When specifying edges, each port ID and the colon preceding it is optional. After all, edges don't have to connect ports, but can also connect nodes directly.

Object Parameters

So far, we have learned how the objects in a KGraph can be specified in the KGT format. However, this doesn't help us much since we don't know yet how to add basic parameters to the objects. This includes, for instance, the size of nodes.

Parameters are the first thing inside a block (the curly braces) of an object. There are three basic parameters that can be attached to a nodes, ports, and labels:

Code Block
pos: x=<xPosition> y=<yPosition>
size: width=<width> height=<height>
insets: top=<top> bottom=<bottom> left=<left> right=<right>

A node with a predefined size could be written like this:

Code Block
titleExampe
linenumberstrue
knode n1 {
    size: width=

...

100 height=

...

50
}

Edges are somewhat different. Position, size, and insets aren't meaningful to edges, so edges have a different parameter that defines their list of bend points:

Code Block
points: <source>;<bend>*;<target>

Each of the points is defined by their x and y coordinate as such:

Code Block
<x>,<y>

Object Properties

If you have already used a layout algorithm through KIML, you will know that layout algorithms are configured through properties attached to the different graph objects. In KGT, this is done through the properties section that follows the parameters:

Code Block
properties:
    

...

<propertyId> 

...

=

...

 <propertyValue>

The properties section can of course contain an arbitrary number of lines, each specifying the value of one property. For example, if we want to add ports and a label to a node, we will often have to set certain properties on it as well to tell the layout algorithm what to do:

Code Block
title

...

Example
linenumberstrue
knode n1 {
    properties:
        de.cau.cs.kieler.

...

Info
titleHint

The KGT editor has auto completion that you can trigger by pressing Ctrl+Space. The list that pops up shows you everything that can be added at the current cursor position. This is especially handy when it comes to property IDs and possible property values.

...

It's now time to connect the nodes. Add two edges to the graph that originate at node1 by adding the following lines under the port definitions of node1:

Code Block
titleEdges
linenumberstrue
kedge (:port1_2 -> node2:port2_1)
kedge (:port1_1 -> node3:port3_1) 

Edges can start and end at a node or at a port. The source node does not need to be explicitly specified since it is clear from the context (the edges are defined in the body of the source node, after all). The target needs the node to be specified, with an optional target port. Add another edge that starts at port2_2 and ends at port3_1. By now, the KLighD view should show something like this:
Image Removed

One of the problems here is that it is not immediately clear from the drawing which rectangle belongs to which node. This can easily be remedied by adding labels. Start by adding a label to the first node:

Code Block
titleLabels
linenumberstrue
klabel "Node 1"

In the same way, add labels to the other nodes. You will notice that the placement of the labels is not very good. Add the following line to the properties section of each node:

...

titleLabel placement
linenumberstrue
sizeConstraint="PORTS NODE_LABELS"
        de.cau.cs.kieler.nodeLabelPlacement="INSIDE V_TOP H_CENTER"
        de.cau.cs.kieler.portConstraints=FIXED_SIDE
    
    klabel "Node 1"
    
    kport p1 {
        size: width=5 height=5
        properties:
            de.cau.cs.kieler.portSide=WEST
        klabel "West port 1"
    }
    
    kport p2 {
        size: width=5 height=5
        properties:
            de.cau.cs.kieler.portSide=WEST
        klabel "West port 2"
    }
    
    kport p3 {
        size: width=5 height=5
        properties:
            de.cau.cs.kieler.portSide=EAST
        klabel "East port 1"
    }
}

Often enough, we also have to set properties on the graph itself (for instance, which layout algorithm to use). In that case, simply include a properties section at the top of the file:

Code Block
titleExample
linenumberstrue
properties:
    de.cau.cs.kieler.algorithm="de.cau.cs.kieler.klay.tree"
 
knode n1 {
    size: width=50 height=50
    
    kedge (-> n2)
    kedge (-> n3)
}
knode n2 {
    size: width=50 height=50
}
knode n3 {
    size: width=50 height=50
}

A More Complex Example

We finish with a more complex example that highlights some of the features of the KIELER graph layout technology and how to use it through the KGT format.

Section
Column
Code Block
titleExample
linenumberstrue
properties:
    de.cau.cs.kieler.edgeRouting=ORTHOGONAL
    de.cau.cs.kieler.direction=DOWN
    de.cau.cs.kieler.separateConnComp=FALSE

// The node label of N1 is placed outside. Edges connect directly to
// the node, without any ports in between
knode N1 {
    properties:
        de.cau.cs.kieler.nodeLabelPlacement="

...

OUTSIDE H_LEFT V_TOP"

...

This will place the labels at the top left corner inside each node. Of course, there are other possible placements you can experiment with. Note that while the value of the port constraints option above could be simply written as FREE, the value of this option needs to be put in quotation marks. This is because this option's value is actually a set of values.

Info
titleSomething to Try

Labels can also be added to ports and are then properly placed by the layout algorithm as well...

...

Let's add a final touch to the graph. Currently, the edges are routed as polylines with slanted edge segments. If we want to change that, we need to tell the layout algorithm to use another edge routing algorithm. Add a new properties section to the beginning of the file:

Code Block
titleEdge Routing
linenumberstrue
properties:
    de.cau.cs.kieler.edgeRouting=ORTHOGONAL

Your result could look something like this:

Image Removed

So much for a first glance at how KGT editing works. The rest of this page is devoted to a more detailed explanation of the syntax of the format.

The KGraph Text Format

In this section, we will take a closer look at the KGT syntax.

Info
If you prefer reading Xtext grammars, you will find it over here.

        de.cau.cs.kieler.sizeConstraint="NODE_LABELS PORTS"
    klabel "N1"
    
    kedge (-> N2)
}

// Compared to N1, this node will be slightly higher because the size
// constraints also take a default minimum size into account
knode N2 {
    properties:
        de.cau.cs.kieler.nodeLabelPlacement="OUTSIDE H_LEFT V_TOP"
        de.cau.cs.kieler.sizeConstraint="MINIMUM_SIZE NODE_LABELS PORTS"
        de.cau.cs.kieler.sizeOptions=DEFAULT_MINIMUM_SIZE
    klabel "N2"
    
    kedge (-> N3:N3Port)
    kedge (-> N4:N4Port)
}

// N3 is a compound node with three nodes nested inside. The layout
// algorithm uses the default node placement algorithm
knode N3 {
    properties:
        de.cau.cs.kieler.edgeRouting=ORTHOGONAL
        de.cau.cs.kieler.direction=DOWN
        de.cau.cs.kieler.nodeLabelPlacement="OUTSIDE H_CENTER V_BOTTOM"
    klabel "N3"
    
    kport N3Port {
        size: width=5 height=5
        pos: x=10 y=-5
    }
    kedge (:N3Port -> N31)
    
    knode N31 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N31"
        
        kedge (-> N32)
        kedge (-> N33)
    }
    
    knode N32 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N32"
    }
    
    knode N33 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N33"
    }
}

// Another a compound node with three nodes nested inside. The layout
// algorithm uses the linear segments algorithm for node placement
knode N4 {
    properties:
        de.cau.cs.kieler.edgeRouting=ORTHOGONAL
        de.cau.cs.kieler.direction=DOWN
        de.cau.cs.kieler.klay.layered.nodePlace=LINEAR_SEGMENTS
        de.cau.cs.kieler.nodeLabelPlacement="OUTSIDE H_CENTER V_BOTTOM"
    klabel "N4"
    
    kport N4Port {
        size: width=5 height=5
    }
    kedge (:N4Port -> N41)
    
    knode N41 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N41"
        
        kedge (-> N42)
        kedge (-> N43)
    }
    
    knode N42 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N42"
    }
    
    knode N43 {
        size: width=80 height=30
        properties:
            de.cau.cs.kieler.nodeLabelPlacement="INSIDE H_CENTER V_CENTER"
        klabel "N43"
    }
} 
Column

Image Added