mingrammer / diagrams

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

diagram alignment is inconsistent and label location is off. #579

Closed felixgao closed 3 years ago

felixgao commented 3 years ago

I have my diagram defined as following, using 0.20.0 version of the software

from diagrams import Diagram, Cluster, Edge
from diagrams.custom import Custom
from diagrams.k8s.clusterconfig import HorizontalPodAutoscaler
from diagrams.k8s.compute import Pod, ReplicaSet, Deployment
from diagrams.k8s.network import Ingress, Service

from diagrams.gcp.ml import VisionAPI

from diagrams.aws.storage import SimpleStorageServiceS3Bucket
from diagrams.aws.ml import Sagemaker

from diagrams.onprem.gitops import Argocd
from diagrams.onprem.network import Nginx
from diagrams.onprem.queue import Kafka
from diagrams.onprem.vcs import Github
from diagrams.onprem.security import Vault

from diagrams.generic.network import Switch

graph_attr={"bgcolor": "transparent"}

with Diagram("Synchronous Workflow", direction="LR", show=False, graph_attr={}):
    with Cluster("Services", direction="LR"):            
        with Cluster("Security"):
            vault = Vault("vault")

        with Cluster("3rd Party"):
            google_vision = VisionAPI("OCR")

        with Cluster("MXS"):
            mxs = Sagemaker("model")

        with Cluster(""):
            event_bus = Kafka("Event Bus")
            s3 = SimpleStorageServiceS3Bucket("Data Lake")
            event_bus >> s3

    with Cluster("CI/CD"):
        github = Github("Repo")
        ibp = Custom("Build", "my_resources/jenkins.jpeg")
        argo = Argocd("Deploy")
        github >> ibp >> argo

    with Cluster("K8s", direction="LR"):
        with Cluster("Namespace"):
            k8s_ingress = Ingress("")
            k8s_svc = Service("Apps")
            k8s_metrics_svc = Service("metrics")
            k8s_rs = ReplicaSet("replica set")
            k8s_hpa = HorizontalPodAutoscaler("hpa")
            k8s_deployment = Deployment("deploy")
            nginx = Nginx("sidecar")
            with Cluster("Deployment"):             
                k8s_pod = Pod("app")

            k8s_ingress >> [k8s_svc, k8s_metrics_svc] >> nginx >> k8s_pod << k8s_rs << k8s_deployment << k8s_hpa           

    switch = Switch("Gateway")

    switch >> k8s_ingress
    k8s_pod >> Edge(label="get secret",  labelloc="b") >> vault
    k8s_pod >> Edge(label="get ocr output",  labelloc="b") >> google_vision
    k8s_pod >> Edge(label="extract data",  labelloc="b") >> mxs
    k8s_pod >> Edge(label="emit events", style="dotted",  labelloc="b") >> event_bus
    argo >> k8s_deployment

The image generate looked like synchronous_workflow

notice the label for extract data is suppose to be on the line going to a model but ended up on the line pointing to OCR

Another problem is all the other diagrams seems to be honoring the direction of LR but the Services seems to be doing a TB instead. I am not sure if there is a way to organize the position of each diagram within Services it doesn't seems to follow the order of the definition or the order of the link within the code.

clayms commented 3 years ago

@felixgao

Thanks for posting your code.

Try using xlabel instead of label Edge attributes.

See: https://graphviz.org/docs/attrs/xlabel/

Without Edges between the Nodes in the Services Cluster, the Nodes just get stacked vertically. Add Edges between those Nodes and set the penwidth to 0 so you don't have to see them.

with Diagram("Synchronous Workflow", direction="LR", show=False, graph_attr={}) :
    with Cluster("Services", direction="LR"):            
        with Cluster("Security"):
            vault = Vault("vault")

        with Cluster("3rd Party"):
            google_vision = VisionAPI("OCR")

        with Cluster("MXS"):
            mxs = Sagemaker("model")

        with Cluster(""):
            event_bus = Kafka("Event Bus")
            s3 = SimpleStorageServiceS3Bucket("Data Lake")
            event_bus >> s3

    with Cluster("CI/CD"):
        github = Github("Repo")
        ibp = Custom("Build", "my_resources/jenkins.jpeg")
        argo = Argocd("Deploy")
        github >> ibp >> argo

    with Cluster("K8s", direction="LR"):
        with Cluster("Namespace"):
            k8s_ingress = Ingress("")
            k8s_svc = Service("Apps")
            k8s_metrics_svc = Service("metrics")
            k8s_rs = ReplicaSet("replica set")
            k8s_hpa = HorizontalPodAutoscaler("hpa")
            k8s_deployment = Deployment("deploy")
            nginx = Nginx("sidecar")
            with Cluster("Deployment"):             
                k8s_pod = Pod("app")

            k8s_ingress >> [k8s_svc, k8s_metrics_svc] >> nginx >> k8s_pod << k8s_rs << k8s_deployment << k8s_hpa           

    switch = Switch("Gateway")

    (
        vault - Edge(penwidth="0") -
        google_vision - Edge(penwidth="0") -
        mxs - Edge(penwidth="0") -
        event_bus
    )

    switch >> k8s_ingress
    k8s_pod >> Edge(xlabel="get secret",  labelloc="b") >> vault
    k8s_pod >> Edge(xlabel="get ocr output",  labelloc="b") >> google_vision
    k8s_pod >> Edge(xlabel="extract data",  labelloc="b") >> mxs
    k8s_pod >> Edge(xlabel="emit events", style="dotted",  labelloc="b") >> event_bus
    argo >> k8s_deployment

image

felixgao commented 3 years ago

thanks for the reply @clayms and that works out really good. I have a follow up question, is there a way to move the Services cluster to align to the middle of the K8s cluster?

clayms commented 3 years ago

You'll have to play around with the Edge attributes minlen and/or constraint.

https://graphviz.org/docs/attrs/minlen/ https://graphviz.org/docs/attrs/constraint/

See the following. I also changed the splines from ortho (default in this library) to spline and made the label a headlabel so I could have more fine control over the placement with labelangle and labeldistance.

https://graphviz.org/docs/attrs/splines/ https://graphviz.org/docs/attrs/headlabel/ https://graphviz.org/docs/attrs/labelangle/ https://graphviz.org/docs/attrs/labeldistance/

from diagrams.onprem.ci import Jenkins

graph_attr={
    "splines": "spline"
    }

with Diagram("Synchronous Workflow", direction="LR", show=False, graph_attr=graph_attr):
    with Cluster("Services", direction="LR"):            
        with Cluster("Security"):
            vault = Vault("vault")

        with Cluster("3rd Party"):
            google_vision = VisionAPI("OCR")

        with Cluster("MXS"):
            mxs = Sagemaker("model")

        with Cluster(""):
            event_bus = Kafka("Event Bus")
            s3 = SimpleStorageServiceS3Bucket("Data Lake")
            event_bus >> s3

    with Cluster("CI/CD"):
        github = Github("Repo")
        ibp = Jenkins("Build")
        argo = Argocd("Deploy")
        github >> ibp >> argo

    with Cluster("K8s", direction="LR"):
        with Cluster("Namespace"):
            k8s_ingress = Ingress("")
            k8s_svc = Service("Apps")
            k8s_metrics_svc = Service("metrics")
            k8s_rs = ReplicaSet("replica set")
            k8s_hpa = HorizontalPodAutoscaler("hpa")
            k8s_deployment = Deployment("deploy")
            nginx = Nginx("sidecar")
            with Cluster("Deployment"):             
                k8s_pod = Pod("app")

            k8s_ingress >> [k8s_svc, k8s_metrics_svc] >> nginx >> k8s_pod << k8s_rs << k8s_deployment << k8s_hpa           

    switch = Switch("Gateway")

    (
        vault - Edge(penwidth="0") -
        google_vision - Edge(penwidth="0") -
        mxs - Edge(penwidth="0") -
        event_bus
    )

    switch >> k8s_ingress
    switch - Edge(minlen="2", penwidth="0") - vault
    switch - Edge(minlen="1", penwidth="0") - github

    k8s_pod >> Edge(headlabel="get\nsecret", labelangle="0", labeldistance="14", constraint="False") >> vault
    k8s_pod >> Edge(headlabel="get ocr\noutput",  labelangle="0", labeldistance="12", constraint="False") >> google_vision
    k8s_pod >> Edge(headlabel="extract\ndata",  labelangle="0", labeldistance="15", constraint="False") >> mxs
    k8s_pod >> Edge(headlabel="emit\nevents", labelangle="0", labeldistance="12", constraint="False", style="dotted") >> event_bus

    argo >> k8s_deployment

image