3

I'm currently having issues with designing UML-like diagrams on graphiz. The reason for the problem is that they are not exactly UML diagrams. The main difference is that I make use of indentations to add an hierarchy to an object's properties. Implementing these idiosyncrasies is a little difficult for me. What I'm trying to achieve is this:

diagram 1

I normally use a node shape called record to design these diagrams. The problem arises when I have to link two of these UML-like diagrams just like relationships in UML i.e. aggregation, association, composition, etc.

When I have the diagrams, I can't make the relationship with the arrows because the arrows only go from a random part of one node to another random part of the other node. The way I have the UML-like diagrams is good, but the relationship arrow causes it not to be what I want as I want the arrows to go from a specific point of one node to another specific point of another node.

diagram 2

The DOT code I used to create this graph is like this:

digraph G {

    fontname = "Bitstream Vera Sans"
    fontsize = 8

    node [
        fontname = "Bitstream Vera Sans"
        fontsize = 8
        shape = "record"
    ]

    edge [
        fontname = "Bitstream Vera Sans"
        fontsize = 8    
    ]

    Person [
        label = "{Person \l\l \ age : int\l \ livesIn : City \l \  \ \ sinceYear : int}"
    ] // \l -new line, \ -indentation

    City [
        label = "{City \l \ \ name : string}"
    ]

    Person -> City
}

I tried getting around this problem by using horizontal line divisions within the nodes even though I didn't want the lines. The horizontal line divisions make it possible for me to make this specific relationship possible by using ports, but they create a new problem of their own. The problem they create is that they get rid of the indentations I want and had in the previous graph. The way I tried to get around the arrow problems works, but new problems are created - the indentation disappears and the horizontal line divisions can't be made invisible

diagram 3.

The code I used to create this graph is:

digraph G {

    fontname = "Bitstream Vera Sans"
    fontsize = 8

    node [
        fontname = "Bitstream Vera Sans"
        fontsize = 8
        shape = "record"
        penwidth = 0.5 
    ]

    edge [
        fontname = "Bitstream Vera Sans"
        fontsize = 8    
    ]

    Person [
        label = "{<g0> Person | <g1> age : int | <g2> livesIn : City | <g3> sinceYear : int}"
    ] // \l -new line, \ -indentation

    City [
        label = "{<f0> City | <f1> name : string}"
    ]

    Person:<g2> -> City:<f1> [arrowhead = "empty", headlabel = "*"]
}

These indentations are a big part of the relationship, so I'm wondering if anyone knows what I can do to have these indentations back in the diagrams as well what I can do to make the horizontal line divisions invisible?

I'll appreciate if someone has a better way/idea that's also totally different from what I have done in diagrams 2 & 3, that will help me achieve diagram 1.

Potherca
  • 13,207
  • 5
  • 76
  • 94
Seyig
  • 31
  • 2
  • Since your reputation is now >10 you should add the images and also provide your graphviz input (or at least the relevant parts). – dgw Feb 12 '12 at 23:23
  • I took the liberty of posting the images from the duplicate question the original poster created in this question. That should make things a **lot** clearer. – Potherca Oct 25 '13 at 13:21

1 Answers1

2

Your original attempt wasn't bad. I would say using ports is definitely the way to go. If you place the node in a cluster you can use the cluster's border and hide the border of the record node, getting rid of those divider lines.

As you noted, using a backslash \ no longer works to escape a space. The workaround is to either use &#92; instead, this will escape the whitespace. As an alternative you could also replace each space with an &nnbsp;. Either one will achieve the required effect.

I made some minor changes to make things more readable, like put Graph properties in a graph block instead of in the root of the graph and rename the port-names to something more sensible. I also removed any ports not in use.

The final result I came up with was this:

enter image description here

...and this is the DOT code I used:

digraph G {

    graph [
        compound = true     // To clip the head at the cluster border
        penwidth = 2        // Make the cluster's borders a bit thicker
        rankdir = "LR"      // Make the arrow and nodes go from Left to Right
        ranksep = 1         // Add a bit more space inbetween nodes
    ]

    node [
        color = none        // Hide the node's border
        fontname = "Bitstream Vera Sans"
        height = 0          // Make the node as small as possible (it will grow if it needs more space)
        margin = 0          // Remove unneeded whitespace
        shape = "record"    // So we can use ports
    ]

    edge [
        arrowhead = "open"
        labelangle = -5     // Place the asteriks closer to the line
        labeldistance = 2.5 // Place the asteriks further away from the arrow head
        penwidth = 2        // Make the line a bit thicker
    ]

    /* @NOTE: escaping spaces in the label using '\' doesn't work so use '&nbsp' or '&#92' instead. */
    subgraph cluster_Person {
        Person [
            label = "\N\l | &#92; &#92; &#92;  age : int\l | <livesIn> &#92; &#92; &#92;  livesIn : City\l | &#92; &#92; &#92; &#92; &#92; &#92;  sinceYear : int\l"
        ]
    }

    subgraph cluster_City {
        City [
            label = "<city> \N\l | &#92; &#92; &#92;  name : string\l"
        ]
    }

    Person:livesIn -> City:city [headlabel = "*", lhead = "cluster_City"] // lhead allows us to point to the cluster's border instead of the node, as long as we add `compound = true` to the graph
}
Potherca
  • 13,207
  • 5
  • 76
  • 94