Page History

PlantUML GraphViz Layout

Mark George edited this page on 8 Aug 2023

Clone this wiki locally

Many of the PlantUML diagrams have their layout handed of to GraphViz. Basically, any node and arc style diagram like class and use case diagrams. While is is convenient to not have to lay out the diagrams yourself, it can sometimes produce diagrams that look a bit nasty if you aren't careful.

Controlling Layout

Layout is determined dymanically, so can be tricky if you are trying to get a specific layout, but you can usually beat it into submission with a combination of the following:

' force class diagram mode
class c1
 
' horizontal placement
c1 -> c2
 
' vertical placement
c2 --> c3
 
' left placement
c4 -left-> c4

You can use left, right, up, and down to control placement direction.

If adding a link screws up the class placement you can use [norank] to exclude the link from the layout process:

' link will not affect class placement
c4 -[norank]-> c2

You can also use [hidden] to create invisible links solely for the purpose of influencing the layout. Repeating them will increase the likelihood that the classes will be placed closer and even be aligned with each other:

' place c2 and c4 closer together
c2 -[hidden]-> c4
 
' repeated again to place c2 and c4 even closer
c2 -[hidden]-> c4

Note that although the links are hidden they still affecting the drawing of links on the same path. If you temporarily remove the [hidden] option you can see what is going on.

You can fiddle with the ordering and direction to ensure the one that is being drawn is in the place that you want it (usually in the middle). The trick is to use identical links with the same class ordering and direction. If you want the link drawn in the opposite direction you can't flip the order of the classes - you need to swap the placement of the arrow:

' place c2 and c4 closer
c2 -[hidden]- c4
       
' draw the actual link between the hidden links
c2 <-[norank]- c4
    
' place c2 and c4 even closer
c2 -[hidden]- c4

You can combine hidden, and norank with directions:

c1 -[hidden]left- c2
c3 -[norank]up- c4

General Layout Tips

Understanding how the layout engine works (GraphVis) makes it easier to get what you want. The previous example with the [hidden] and [norank] links got weird because we were giving the layout engine conflicting information.

The layout is determined by the order that classes occur. Classes are drawn at the top of the document have higher ranking than those below.

The rank is determined by:

  • The order in which classes are added to the diagram
  • The layout hints (horizontal, vertical, left, right, up, down)
  • The direction in which the links are defined. The class on the left has higher rank than the one on the right: higher -> lower

Link direction can have a dramatic impact. If we add a c4 --> c2 link we confuse the engine by having c4 on the left which gives it a higher ranking than c2 and causes the diagram to flip upside down:

class c1 
c1 -> c2
c2 --> c3
c3 -left-> c4
 
' whoops, this flips the diagram on its head
c4 --> c2

Drawing links from the top down prevents this re-ranking problem, and means you don't have to use [norank] as often. Since the arrow direction has no effect on the layout we can just flip the end that the arrow is drawn at to account for the link being in a different order:

' ranking maintained, so layout isn't dramatically affected
' arrow drawn at opposite end to account for reverse order
c2 <-- c4

We could have also used the up layout hint to prevent the re-ranking:

c4 -up-> c2

Layout Direction

You can change the ranking direction from vertical to horizontal using left to right direction:

left to right direction
class c1
c1 -> c2
c2 --> c3
c3 -left-> c4
c2 <-- c4

This also changes the meaning of the layout hints. Horizontal hints become vertical, etc.

Spacing

You can control the spacing between class using the NodeSep and RankSep skinparams.

SkinParam {
    NodeSep 45 ' horizontal spacing
    RankSep 45 ' vertical spacing
}

Grouping

You can influence the layout to ensure classes are grouped together:

together {
  class c1
  class c2
}

c1 -- c2

Row based layout

On of the many undocumented features is the ability to add row breaks via layout_new_line:

@startuml
class c1
class c2

layout_new_line

class c3
class c4
@enduml

This seem partially implemented though. Relationships are currently not drawn when using this mode (as at August 2023).

Line style

Polylines will occasionally be used. For some line decorations (crows feet for ERD for example) look like crap when wonky angles are used.

' straight lines only
skinparam linetype ortho

' allow polylines
skinparam linetype polyline

Notes to members

@startuml
class A {
  a
  b
--
  c(some, stuff)
}

note left of A::a
  This the 'a' field
end note

note right of A::"c(some, stuff)"
  This is the 'c' method
end note
@enduml

Other stuff

Collection of mainly undocumented features that might be useful. Complete list found at:

https://github.com/plantuml/plantuml/issues/261

' minimum class width
skinparam minClassWidth 50

' same class width (useful for enforcing a column-aligned layout)
skinparam sameClassWidth true

' aligned line-breaks (using \l and \r instead of \n)
c1 "left\laligned" -- "right\raligned" c2

` text wrapping
skinparam wrapWidth 100
skinparam maxMessageSize 100

' debugging diagrams by generating a dot file that can be inspected
!pragma svek_trace on

' maybe fix some of the "PlantUML seems reluctant to generate sane horizontal lines in some cases" problems
' This might help avoid the need for "left to right mode" in some cases.
' Apparently there are some buggy GraphViz versions that cause problems, so they disabled horizontal lines in problematic cases - this enables them again
!pragma horizontalLineBetweenDifferentPackageAllowed

` hide nodes that are not linked to any other nodes
hide unlinked

` line continuation via "\"
a -> b : this is a long line that will \
be treated as a single line by PlantUML

' the above can be combined with "\n" to make the code and the diagram match
a -> b : this is a long line that will \n\
be treated as a single line by PlantUML

' class diagram relationship styling
a -[#blue]-> b
a -[#red,bold]-> c
a-[bold] -> d