The GUESS .gdf format
The file structure for the .gdf files is very simple. We will basically define the nodes with their properties followed by the edges with theirs.
The node definition section starts with the line: “nodedef> name”
The nodedef line will tell GUESS what the format is of the following lines that actually describe nodes. In the simple case we are just going to have one column on each line, the node name. Nodes are required to have unique names (identifiers). You will want to avoid using anything that is not a valid Python variable name here if you want to access the nodes by this name (so setting names to just a number is probably a bad idea... try v44 or n44 instead of just "44"). When GUESS starts up, it will automatically create variables for you for each node. So if you have a node called foobarbaz, you’ll be able to talk about foobarbaz.color.
The simplest file looks something like this:
nodedef> name foobar
which tells GUESS that we want a node called foobar. All other aspects of the node (color, visibility, style) will be extracted from defaults. After name (the only required column), you may use pre-defined columns and new columns to set and control extra node properties. Pre-defined columns are:
x – a double representing the node’s x location (default: random)
y – a double representing the node’s y location (default: random)
visible – a boolean indicating if the node should be displayed (default: true)
color – a string, the default color of the node (default: “cornflowerblue”). We have a long list of color names that we know about, but if you didn’t want to use one of those you could quote an rgb triplet (e.g. “124,234,222”)
strokecolor – a string, the color of the small line around most nodes (default: cadetblue)
fixed – boolean, can the node be moved? (default: false)
style – an int indicating which style of node to use (default: 1). Currently GUESS maps: rectangle = 1, ellipse = 2, rounded rectangle = 3, text inside a rectangle = 4, text inside an ellipse = 5, text inside a rounded rectangle = 6, and an image = 7
width – double, node width (default: 4)
height – double, node height (default: 4)
label – string, a label for the node in the visualization (default is the name)
labelvisible – boolean, should we show the label? (default: false)
labelcolor – string, the color of the label (default: same color as node)
image – string, a filename of the image to use if the node style = 7
These properties can also be controlled and accessed once GUESS is actually running. You can type “foobar.x” to get the x coordinate for foobar and “foobar.height = 20” to set foobar’s height.
These pre-defined attributes can be overridden by simply adding them to the list in the nodedef line. For example:
nodedef> name,x,y,color foo,0,0,blue bar,100,100,red
This will tell GUESS that you want two nodes: a blue one called foo at (0,0) and a red one called bar at (100,100). Notice that you don’t have to quote things explicitly (strings versus numbers). The system should figure that out for you (unless your string has a comma in which case you’ll want to put it in quotes).
This pre-defined list is simply our choice on node properties that have a specific meaning to the visualization. We may add more in the future (font sizes, colors, complex shape definitions, etc.), but this is the set for now. Usually you will want to add extra attributes to the node definitions. For example, you may want to have a department property or maybe a salary. Unlike the pre-defined nodes you will need to tell GUESS what kind of property this is (string, integer, etc.). We use standard SQL to define these aspects. For example:
nodedef> name,style,dept VARCHAR(32),salary INT default 40000 foo,1,dept1,50000 bar,2,dept2,52000
This file tells GUESS that you want to have two user defined columns, dept (the department) and salary. Notice that we can define a default salary so that any new nodes added after the load will take on the default value. After running GUESS on this .gdf file you will have two nodes and be able to access these properties in the same way as the pre-defined ones. For example, typing “foo.style” will return 1 and “foo.salary” will return 50000.
Edges are defined in a very similar way, the only required columns for edges are “node1” and “node2” which are the names of the two nodes you are connecting. A simple example is something like:
nodedef> name a b c d edgedef> node1,node2 a,b a,c a,d
Which defines a star network centered on node a. It will look something like:
Edges, like nodes, can contain pre-defined and user-defined attributes in the definition lines. Valid pre-defined edge properties are:
visible – a boolean indicating if the edge should be displayed (default: true)
color – a string, the default color of the node (default: “dandelion”).
weight – a double indicating the edge weight (default: 1, but not currently used for calculations)
width – double, node width (default: .3)
directed – boolean, indicating edge directionality (default: false, undirected/bidirected). If true, this will assume node1 is the source and node2 is the destination.
label – string, a label for the node in the visualization (default is the edge weight)
labelvisible – boolean, should we show the label? (default: false)
labelcolor – string, the color of the label (default: same as edge color)
One critical thing to note is that duplicated edges are not supported by default (GUESS will complain unless you explicitly use the –m option when starting GUESS). That is you can not create more than one edge of the same direction between two nodes. At most you can have 3 edges between two nodes (a->b, b->a, and a-b). Recall that a-b and a<->b are considered to be the same thing. GUESS will try to remove duplicate edges (e.g. a->b and b<-a) for you (when loading the file), but sometimes this will fail and you will get an exception. You can simulate this behavior by adding extra fields.
Again, just as in the case of nodes, any user-defined edge attributes can be added by putting them on the edgedef line. Extending our previous example:
nodedef> name,style,dept VARCHAR(32),salary INT default 40000 bob,1,dept1,50000 john,1,dept1,49000 alice,2,dept2,52000 edgedef> node1,node2,directed,relationship VARCHAR(32) bob,alice,true,reports to john,alice,true,reports to bob,john,false,colleague of
Using something like this you will be able to say “(bob-john).relationship” in GUESS and get back “colleague of.”
Arrows: If your graph contains directed edges, GUESS will, by default, create an arrow at the appropriate end. You can turn this on or off for ANY graph by using the command setDirected(true) or setDirected(false) (undirected arrows are assumed to be bidirected and an arrow will appear on both ends). You can play with appearance of arrows by using the command overrideArrowLength(length) or overrideArrowWidth(width).
As we described above there are a number of predefined nodes styles. The following image shows these styles:
Node style 7 has its “image” field set to hplogo.jpg (a local file). It is also possible to “push” an image (a java object) to an image style node. This allows you to create new images dynamically. For example, CustomNodes.py in the scripts directory will generate an “aqua” style button for each node when convertAllToAqua() is called. The result would look something like:
Finally, it is now possible to define your own polygon shapes for nodes. By generating a style id (an integer > 100) and associating it with a Shape object in the shapeDB you will be able to create your own shapes. For example, we can create diamond, triangle, or star shapes using the following code (also in shapetest.py):
from java.awt.geom import GeneralPath from java.awt import Polygon import jarray xpoints = jarray.array((10,5,0,5),'i') ypoints = jarray.array((5,10,5,0),'i') diamond = Polygon(xpoints,ypoints,4); shapeDB.addShape(104,diamond) xpoints = jarray.array((55, 67, 109, 73, 83, 55, 27, 37, 1, 43),'i') ypoints = jarray.array((0, 36, 36, 54, 96, 72, 96, 54, 36, 36),'i') star = Polygon(xpoints,ypoints,10) shapeDB.addShape(105,star) triangle = GeneralPath() triangle.moveTo(5,0) triangle.lineTo(10,5) triangle.lineTo(0,5) triangle.lineTo(5,0) shapeDB.addShape(106,triangle)
Running this script and applying the commands v0.style = 104, v1.style = 105, and v2.style = 106 results in the following picture: