3

我目前在 graphiz 上设计类似 UML 的图表时遇到问题。问题的原因是它们不完全是 UML 图。主要区别在于我使用缩进将层次结构添加到对象的属性中。实现这些特质对我来说有点困难。我想要实现的是:

图1

我通常使用称为record设计这些图表的节点形状。当我必须像 UML 中的关系(即聚合、关联、组合等)一样链接这些类似 UML 的图表中的两个时,就会出现问题。

当我有图表时,我无法与箭头建立关系,因为箭头只从一个节点的随机部分到另一个节点的另一个随机部分。我拥有类似 UML 的图表的方式很好,但是关系箭头导致它不是我想要的,因为我希望箭头从一个节点的特定点到另一个节点的另一个特定点。

图2

我用来创建这个图表的 DOT 代码是这样的:

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
}

我尝试通过在节点内使用水平线划分来解决这个问题,即使我不想要这些线。水平线的划分使我可以通过使用ports来使这种特定的关系成为可能,但是它们自己产生了一个新问题。他们创造的问题是他们摆脱了我想要的并且在上图中有的缩进。我试图解决箭头问题的方法有效,但产生了新问题 - 缩进消失并且水平线分割不能隐藏

图 3.

我用来创建此图的代码是:

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 = "*"]
}

这些缩进是关系的重要组成部分,所以我想知道是否有人知道我可以做些什么来让这些缩进回到图表中,以及我可以做些什么来使水平线分割不可见?

如果有人有更好的方法/想法,这也与我在图 2 和图 3 中所做的完全不同,我将不胜感激,这将帮助我实现图 1。

4

1 回答 1

2

你最初的尝试还不错。我会说使用端口绝对是要走的路。如果您将节点放在集群中,您可以使用集群的边界并隐藏记录节点的边界,从而摆脱那些分隔线。

正如您所指出的,使用反斜杠\不再适用于转义空格。解决方法是&#92;改用,这将转义空格。作为替代方案,您也可以将每个空格替换为&nnbsp;. 任何一个都将达到所需的效果。

我做了一些小改动以使内容更具可读性,例如将 Graph 属性放在graph块中而不是图的根中,并将端口名称重命名为更合理的名称。我还删除了所有未使用的端口。

我想出的最终结果是这样的:

在此处输入图像描述

...这是我使用的 DOT 代码:

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
}
于 2013-10-24T11:23:31.110 回答