You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
C4-PlantUML/LayoutOptions.md

25 KiB

Layout Options

PlantUML uses Graphviz for its graph visualization. Thus the rendering itself is done automatically for you - that it one of the biggest advantages of using PlantUML.

...and also sometimes one of the biggest disadvantages, if the rendering is not what the user intended.

For this reason, C4-PlantUML also comes with some layout options.

Layout Guidance and Practices

Overall Guidance

  1. Be minimal in the use of all directed relations - use the fewest possible to accomplish the desire results.
  2. With dynamic rendering tools (e.g. VS Code plugin) do NOT trust the first rendering as it is shifty when adding code because you do not know exactly when it grabs the current unsaved code. Wait for a bit or close and reopen preview panel.

Layout Practices

These are intended to correlate to the layout engines algorithm, but have (as of this writing) been determined by trial and error - not a code review.

  1. Create all components, containers and boundaries first - in order top to bottom or left to right.
  2. Create relationships next (Rel)
  3. Create Lay_ statements next.
  4. Use Rel (directionless) where possible.
  5. Use Rel_ to force shape layouts.
  6. Add Lay_ to force any layouts that Rel_ does not resolve.
  7. For both Rel_ and Lay_:
    1. Order inner objects first when it creates the desired result (enclosing objects tend to follow suit when child objects are ordered).
    2. Try NOT to apply order to both inner elements and elements that enclose them to force relationships that aren't working out.
    3. Make all orderings at the same nesting level whenever possible.
  8. Do NOT create duplicated, opposite direction "Lay_" commands in an attempt to force or ensure relationships as it does not affect the results. For instance if you have "Lay_R(entity1,entity2)" which is not working as desired and then add the opposing one as "Lay_L(entity2,entity1)" - it does not help with forcing layouts to be as you want them.
  9. Do not create an "All enclosing" boundary - the code for processing relationships seems to struggle with relationships inside this. Additionally, SHOW_FLOATING_LEGEND() will not display inside the All enclosing boundary.
  10. Legend statements must come after at least one usage of each of the elements you want the legend to contain.

LAYOUT_TOP_DOWN() or LAYOUT_LEFT_RIGHT() or LAYOUT_LANDSCAPE()

With the two macros LAYOUT_TOP_DOWN() and LAYOUT_LEFT_RIGHT() it is possible to easily change the flow visualization of the diagram. LAYOUT_TOP_DOWN() is the default.

@startuml LAYOUT_TOP_DOWN Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

/' Not needed because this is the default '/
LAYOUT_TOP_DOWN()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

LAYOUT_TOP_DOWN Sample

LAYOUT_LEFT_RIGHT() rotates the flow visualization to from Left to Right and directed relations like Rel_Left(), Rel_Right(), Rel_Up() and Rel_Down() are rotated too.

@startuml LAYOUT_LEFT_RIGHT Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

LAYOUT_LEFT_RIGHT()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

LAYOUT_LEFT_RIGHT Sample

LAYOUT_LANDSCAPE() rotates the default flow visualization to from Left to Right like LAYOUT_LEFT_RIGHT() additional directed relations like Rel_Left(), Rel_Right(), Rel_Up() and Rel_Down() are not rotated anymore.

@startuml LAYOUT_LANDSCAPE Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

LAYOUT_LANDSCAPE()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")

System(S,"S")
System(SU,"S Up")
System(SD,"S Down")
System(SL,"S Left")
System(SR,"S Right")

Rel_Up(S, SU, "Up")
Rel_Down(S, SD, "Down")
Rel_Left(S, SL, "Left")
Rel_Right(S, SR, "Right")

SHOW_LEGEND()

@enduml

LAYOUT_LANDSCAPE Sample

LAYOUT_WITH_LEGEND() or SHOW_LEGEND(?hideStereotype)

Colors can help to add additional information or simply to make the diagram more aesthetically pleasing. It can also help to save some space.

All of that is the reason, C4-PlantUML uses colors and prefer also to enable a layout without <<stereotypes>> and with a legend. This can be enabled with LAYOUT_WITH_LEGEND().

@startuml LAYOUT_WITH_LEGEND Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

LAYOUT_WITH_LEGEND()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

LAYOUT_WITH_LEGEND Sample

Instead of a static legend (activated with LAYOUT_WITH_LEGEND()) a calculated legend can be activated with SHOW_LEGEND(?hideStereotype).

The calculated legend has following differences:

  • only relevant elements are listed
  • custom tags/styles are supported
  • stereotypes can remain visible (with SHOW_LEGEND(false))
  • SHOW_LEGEND() has to be last call in the diagram
@startuml SHOW_LEGEND Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")

SHOW_LEGEND()
@enduml

SHOW_LEGEND Sample

SHOW_FLOATING_LEGEND(?alias, ?hideStereotype) and LEGEND()

LAYOUT_WITH_LEGEND() and SHOW_LEGEND(?hideStereotype)` adds the legend at the bottom right of the picture like below and additional whitespace is created.

@startuml Layout With Whitespace Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

Person(a, "Person A")
Container(b, "Container B", "techn")
System(c, "System C")
Container(d, "Container D", "techn")
Container_Ext(e, "Ext. Container E", "techn")

Rel_R(a, b, "calls")
Rel_D(b, c, "uses")
Rel_D(c, d, "uses")
Rel_R(d, e, "updates")

SHOW_LEGEND()
@enduml

Layout With Whitespace Sample

Therefore a floating legend can be added via SHOW_FLOATING_LEGEND(), positioned with Lay_Distance() and existing whitespace is reused like below.

  • `SHOW_FLOATING_LEGEND(?alias, ?hideStereotype): shows the legend in the drawing area
  • LEGEND(): is the default alias of the created floating legend and can be used in Lay_Distance() call
@startuml Compact Legend Layout Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

Person(a, "Person A")
Container(b, "Container B", "techn")
System(c, "System C")
Container(d, "Container D", "techn")
Container_Ext(e, "Ext. Container E", "techn")

Rel_R(a, b, "calls")
Rel_D(b, c, "uses")
Rel_D(c, d, "uses")
Rel_R(d, e, "updates")

SHOW_FLOATING_LEGEND()
Lay_Distance(LEGEND(), e, 1)
@enduml

Compact Legend Layout Sample

LAYOUT_AS_SKETCH() and SET_SKETCH_STYLE(?bgColor, ?fontColor, ?warningColor, ?fontName, ?footerWarning, ?footerText)

C4-PlantUML can be especially helpful during up-front design sessions. One thing which is often ignored is the fact, that these software architecture sketches are just sketches.

Without any proof

  • if they are technically possible
  • if they can fulfill all requirements
  • if they keep what they promise

More often these sketches are used by many people as facts and are manifested into their documentations. With LAYOUT_AS_SKETCH() you can make a difference.

@startuml LAYOUT_AS_SKETCH Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

LAYOUT_AS_SKETCH()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

LAYOUT_AS_SKETCH Sample

Additional styles and the footer text can be changed with SET_SKETCH_STYLE():

  • SET_SKETCH_STYLE(?bgColor, ?fontColor, ?warningColor, ?fontName, ?footerWarning, ?footerText): Enables the modification of differnt sketch styles and footer.

The possible font name(s) depend on the output format (e.g. PNG uses fonts which are installed on the server and SVG fonts have to be installed on the client). Additional is it possible to define comma separated fall back fonts (if the diagrams are exported as SVG. Atm PNG does not support fallback fonts based on a PlantUML bug, but this could be fixed in one of the following versions)

@startuml LAYOUT_AS_SKETCH Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

SET_SKETCH_STYLE($bgColor="lightblue", $fontColor="darkblue", $warningColor="darkred", $footerWarning="Sketch", $footerText="Created for discussion")

' PNG with font jlm_cmmi10 (typically another font is used)
' SET_SKETCH_STYLE($fontName="jlm_cmmi10")

' SVG with fallback fonts MS Gothic,Comic Sans MS, Comic Sans, Chalkboard SE, Comic Neue, cursive, sans-serif (typically without "MS Gothic")
SET_SKETCH_STYLE($fontName="MS Gothic,Comic Sans MS,Comic Sans,Chalkboard SE,Comic Neue,cursive,sans-serif")

LAYOUT_AS_SKETCH()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

PNG with font jlm_cmmi10

LAYOUT_AS_SKETCH with custom style png Sample

SVG with fallback fonts MS Gothic,Comic Sans MS,Comic Sans,Chalkboard SE,Comic Neue,cursive,sans-serif

LAYOUT_AS_SKETCH with custom style svg Sample

All available (PNG) fonts can be displayed with

@startuml
listfonts
@enduml

HIDE_STEREOTYPE()

To enable a layout without <<stereotypes>> and legend. This can be enabled with HIDE_STEREOTYPE().

@startuml HIDE_STEREOTYPE Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

HIDE_STEREOTYPE()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

HIDE_STEREOTYPE Sample

HIDE_PERSON_SPRITE(), SHOW_PERSON_SPRITE(?sprite), SHOW_PERSON_PORTRAIT() and SHOW_PERSON_OUTLINE()

With the macros HIDE_PERSON_SPRITE(), SHOW_PERSON_SPRITE() and SHOW_PERSON_PORTRAIT() it is possible to change the person related default sprite or person layout itself. SHOW_PERSON_SPRITE() is the default.

  • HIDE_PERSON_SPRITE(): deactivates the default sprite
  • SHOW_PERSON_SPRITE(): activates the default sprite "person"
  • SHOW_PERSON_SPRITE($sprite): activates a specific sprite as default sprite
  • SHOW_PERSON_PORTRAIT(): activates portrait instead of a rectangle
  • SHOW_PERSON_OUTLINE(): activates person outline instead of a rectangle

"person" and "person2" are predefined sprites which can be used as default sprite too.

@startuml predefined sprites Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

Person(userA, "User A", "with predefined sprite person", "person")
Person(userB, "User B", "with predefined sprite person2", "person2")
@enduml

Predefined sprites Sample

Using HIDE_PERSON_SPRITE()

@startuml HIDE_PERSON_SPRITE Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

HIDE_PERSON_SPRITE()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

HIDE_PERSON_SPRITE Sample

Using SHOW_PERSON_SPRITE()

@startuml SHOW_PERSON_SPRITE Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

/' Not needed because this is the default with sprite "person" '/
SHOW_PERSON_SPRITE()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

SHOW_PERSON_SPRITE Sample

Using SHOW_PERSON_SPRITE(sprite)

@startuml SHOW_PERSON_SPRITE(sprite) Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!define osaPuml https://raw.githubusercontent.com/Crashedmind/PlantUML-opensecurityarchitecture2-icons/master
!include osaPuml/Common.puml
!include osaPuml/User/all.puml

SHOW_PERSON_SPRITE("osa_user_green_architect")

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

SHOW_PERSON_SPRITE(sprite) Sample

Using SHOW_PERSON_PORTRAIT()

@startuml SHOW_PERSON_PORTRAIT() Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

SHOW_PERSON_PORTRAIT()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

' if a person is combined with a sprite then the rectangle layout is used again
Person(person, "Person with sprite", $sprite="person2")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

SHOW_PERSON_PORTRAIT() Sample

Using SHOW_PERSON_OUTLINE()

This call requires PlantUML version >= v1.2021.4!

@startuml SHOW_PERSON_OUTLINE() Sample
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

SHOW_PERSON_OUTLINE()

Person(admin, "Administrator")
System_Boundary(c1, 'Sample') {
    Container(web_app, "Web Application", "C#, ASP.NET Core 2.1 MVC", "Allows users to compare multiple Twitter timelines")
}
System(twitter, "Twitter")

' if a person is combined with a sprite then the rectangle layout is used again
Person(person, "Person with sprite", $sprite="person2")

Rel(admin, web_app, "Uses", "HTTPS")
Rel(web_app, twitter, "Gets tweets from", "HTTPS")
@enduml

SHOW_PERSON_OUTLINE() Sample