mingrammer / diagrams

:art: Diagram as Code for prototyping cloud system architectures
https://diagrams.mingrammer.com
MIT License
39.2k stars 2.52k forks source link

Nested Cluster with neato layout #399

Closed bandoos closed 1 year ago

bandoos commented 3 years ago

Hi!

Thanks for the lib!

I'm encountering an issue with nested clusters while using the neato layout to manually specify position.

With default layout nesting works as charm:

from diagrams import Diagram, Cluster
from diagrams.onprem.container import Docker

with Diagram('Working cluster nesting'):
    with Cluster("A"):
        for b in range(3):
            with Cluster("B-"+str(b)):
                Docker('Docker-'+str(b))

working_cluster_nesting

When using neato:

from diagrams import Diagram, Cluster
from diagrams.onprem.container import Docker

graph_attr = {
    "layout":"neato",
    }

with Diagram('Borken cluster nesting 2',
             graph_attr=graph_attr):
    with Cluster("A"):
        Docker('Docker-A',pin="true",
               pos="0,-2")
        for b in range(3):
            with Cluster("B-"+str(b)):
                Docker('Docker-'+str(b),
                       pin="true",
                       pos="0,"+str(b*2))

borken_cluster_nesting_2

Am I doing something wrong or is it not possible to do such nesting with neato?

Thanks in advace!

clayms commented 3 years ago

You don't need to nest the clusters with neato, because you can force them to be drawn where ever you want by using the coordinates.

For more fine grained control over the size and position of each Cluster, use some blank "plaintext" Nodes to pin the opposite corners.

from diagrams import Diagram, Cluster, Node
from diagrams.onprem.container import Docker

graph_attr = {
    "layout":"neato",
    }

clusB_graph_attr = {
    "bgcolor": "azure",
}

with Diagram('Neato "nested" Clusters', show=False,
            graph_attr=graph_attr) as diag:
    with Cluster("A"):
        Node('', shape="plaintext", pin="true", pos="-1,-0.5")
        Node('', shape="plaintext", pin="true", pos="1,5")
        Docker('Docker-A',pin="true",
               pos="0,-2")
    for b in range(3):
        with Cluster("B-"+str(b), graph_attr=clusB_graph_attr, ):
            Docker('Docker-'+str(b),
                    pin="true",
                    pos="0,"+str(b*2))

diag

image

clayms commented 3 years ago

slight variation to use neato's node separation algorithms.

This can be faster, as you will not have to specify each coordinate. However, it can get more tricky to get the final plot laid out the way you want.

from diagrams import Diagram, Cluster, Node
from diagrams.onprem.container import Docker

graph_attr = {
    "layout": "neato",
    "mode": "major",
    "overlap": "voronoi",
    "sep": "0.0", 
    "splines": "spline",
}

clusB_graph_attr = {
    "bgcolor": "azure",
}

with Diagram('Neato "nested" Clusters',show=False,
            graph_attr=graph_attr) as diag:
    with Cluster("A"):
        Node('', shape="plaintext", width="0.0", height="0.0", pin="true", pos="0,0")
        Node('', shape="plaintext", width="0.0", height="0.0", pin="true", pos="0,5")
        A1 = Docker('Docker-A', )
    for b in range(3):
        with Cluster(f"B-{str(b)}", graph_attr=clusB_graph_attr, ):
            exec(f"B{str(b)} = Docker('Docker-{str(b)}', )")

    (
        A1 - Edge(penwidth="0.0") - 
        B0 - Edge(penwidth="0.0") - 
        B1 - Edge(penwidth="0.0") - 
        B2 
    )

diag

image