Проблемы с проектированием UML - подобных диаграмм в графвизе

В настоящее время у меня проблемы с проектированием 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
}

Я попытался обойти эту проблему, используя горизонтальные линейные деления внутри узлов, хотя я не хотел, чтобы линии. Горизонтальные деления линий позволяют мне сделать это возможным благодаря использованию портов, но они сами создают новую проблему. Проблема, которую они создают, состоит в том, что они избавляются от отступов, которые я хочу и имел в предыдущем графике. Способ, которым я пытался обойти проблемы со стрелками, работает, но создаются новые проблемы - отступы исчезают, а деления горизонтальных линий нельзя сделать невидимыми

диаграмма 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.

1 ответ

Ваша первоначальная попытка не была плохой. Я бы сказал, что использование портов, безусловно, путь. Если вы поместите узел в кластер, вы можете использовать границу кластера и скрыть границу узла записи, избавившись от этих разделительных линий.

Как вы заметили, используя обратную косую черту \ больше не работает, чтобы убежать из космоса. Обходной путь должен либо использовать &#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
}
Другие вопросы по тегам