How can I tag classes then show only classes bearing given tags in a class diagram?

+1 vote
asked Mar 1, 2018 in Closed feature request by matthewadams12 (240 points)

I'm using the following strategy for my domain model.

  • One file per class, interface, enum, or annotation.  Each class in a file only contains basic attributes (string, datetime, integer, decimal, etc).
  • One file storing all relations, including inheritance, interface implementation, association, aggregation, and composition.
  • Separate class diagram files (each representing a bounded context, AKA a subset of the larger domain model) with @startuml & @enduml directives that !include class/interface/enum/annotation files and the relations file.

The result of this strategy is that I have a high number of hide statements in all class diagram files so that only the classes that I intend to show on the diagram are visible.  This gets tedious.  Worse, if I add a new relation to the relations file, I have to go check all of the other class diagram files to ensure that I didn't just inadvertently add artifacts to the other class diagram files that include the same relations file.

In what way can I add one or more tags to classes/interfaces/enums/annotations, then, in the class diagram file, say something like show only myFirstTag myOtherTag to only show those classes with tags myFirstTag or myOtherTag so that I don't have to have so many hide statements?

This would be a really useful feature.

1 Answer

0 votes
answered Mar 2, 2018 by plantuml (294,960 points)
selected Mar 21, 2018 by Anthony-Gaudino
 
Best answer

We could extends the syntax of the hide/show syntax to hide by default all created classes/interface/enum/annotations.

This is not implemented yet, but imagine a new "hide everything" feature that would by default hide every classes/interface/enum/annotations created.
You would have to declare classes you want to show (in your !include file of each classes).

So something like:

@startuml
hide everything
class foo1
show foo1
class foo2
show foo2
' foo3 and foo4 are not explicitely shown, so they would be hidden.
foo3 --> foo4
@enduml

would only show foo1 and foo2.

Would this suit your needs ?

commented Mar 2, 2018 by matthewadams12 (240 points)
While your solution would suit my needs, I wouldn't mind seeing behavior similar to the current ability to hide by stereotype (hide <<bar>><<snafu>>).

However, I'd still prefer the ability to add tags to classes/interfaces/enums/annotations.  That would be a more effective means of hiding & showing, as well as being able to provide authors arbitrary means of categorizing c/i/e/a's.  For example, I like Eric Evans bounded contexts to break up my domain model into digestible pieces (https://martinfowler.com/bliki/BoundedContext.html).  Tags would allow me to do so.  I'm sure there are many other ways of categorizing c/i/e/a's out there, which tags would enable support for.

'Proposed sample syntax to tag things: use "#" to indicate a tag
class Account #bc:transactions #bc:performance {
  '...
}
class Transaction #bc:transactions
class Performance #bc:performance
Foo #bc:snafu "1" *-- "0..* Bar 'tagging sample in a relation

'Transactions class diagram
@startuml
hide everything
show #bc:transactions 'this one line shows everything tagged with "bc:transactions"
!include Account.puml
'...
!include relations.puml
@enduml

Instead of "hide everything", a more concise (and powerful) syntax could be:
hide * '(glob expression supporting * and ?)
hide /.*/ '(regex matching c/i/e/a name)
hide <<moment*>> 'glob matching stereotypes
hide <</^moment.*$/>> 'regex matching stereotypes
hide #moment* 'glob matching tags
hide #/^moment.*/$ 'regex matching tags
hide 'with no argument is same as "hide *"

I would also like for the "show" directive to support the same as above.

Further, it would be nice if the default hide/show behavior defaulted depending on which hide/show directive were encountered first.  If the first hide/show directive encountered were "show", then PlantUML should default to hiding everything and only showing what's been requested, and if no directive were encountered or the first directive encountered where "hide", then PlantUML should default to its current behavior of showing.

In the event of conflicting hide/show directives, the behavior could be to err, have hides win, have shows win, or last one wins.

Capice?  :)
commented Mar 2, 2018 by matthewadams12 (240 points)
I tried to shoehorn the feature that lets me hide by stereotype to achieve a "show by stereotype" by hiding all stereotypes that I don't want.  That won't work for me because I can't add a stereotype to a class name used in a relation statement (AFAICT).

I really need the ability to tag c/i/e/a's and hide by tag, but more importantly, show by tag.  This is becoming a show-stopper for me, which sucks.  I really love PlantUML.
commented Mar 2, 2018 by plantuml (294,960 points)
I think I've got the point about your tag suggestion.
A first concern is that we cannot use # to denotate tags : right now, this is already used for color. http://www.plantuml.com/plantuml/uml/Iyv9B2vMIClFLr0kIaq10000
Maybe we could use {{ }} to denotate tag ?

'Proposed sample syntax to tag things: use "#" to indicate a tag
class Account {{bc:transactions}} {{bc:performance}} {
  '...

What do you think about it ?
}
class Transaction {{bc:transactions}}
class Performance {{bc:performance}}
commented Mar 2, 2018 by matthewadams12 (240 points)
{{ & }} would work.  How about %?  Like
class Transaction %bc:transactions

I'm really lazy and would rather only type a single character.  :)
commented Mar 3, 2018 by plantuml (294,960 points)
Finally, let's give a try with the $ character.
We've built a new beta http://beta.plantuml.net/plantuml.jar

With this beta, you can have:

@startuml
class foo1 $tag1 {
}
class foo2 << This is My Stereo >> $tag1 $tag2 {
}
class foo3 $tag1  $tag2  $tag3  {
}
class foo4
class foo5 << Other >> $tag1 $tag2 {
}
hide2 $tag*
show2 << *My* >>
show2 foo3
@enduml

We use temporary the keywords hide2/show2.
Rather than using regex, we prefer the simple * character : I think it's easier for end user.
If this sounds good to you, we will rename them to hide/show

You can play with this last beta, and tell us what you think about it!
commented Mar 5, 2018 by matthewadams12 (240 points)
edited Mar 5, 2018 by matthewadams12
Thanks!  I'll play with this & report back.  Question:  I know that I can "hide ...", but does this beta have the show-only behavior that I described earlier (at the end of the comment at http://forum.plantuml.net/7337/classes-then-show-only-classes-bearing-given-class-diagram?show=7347#c7347 )?
commented Mar 5, 2018 by plantuml (294,960 points)
I think it does.
You can start with "hide2 *" (which hides everything) then use "show2 ..." to show only what you want. Is this your need ?
commented Mar 5, 2018 by matthewadams12 (240 points)
Looks like everything works, except there are two small bugs:

Bug 1:  the expression "class Foo {}" (class with body but no tag) causes a NullPointerException

Bug 2:  the expression "class Bar $tag1" (class with tag but no body) causes a "Syntax Error" rendering

Thanks!  :)

PS: if you were doing this work in a git branch, I could've taken a look to see if I could've fixed these bugs myself, but I didn't see any remote git branches pushed to https://github.com/plantuml/plantuml.
commented Mar 6, 2018 by matthewadams12 (240 points)
One more small bug.

Bug 3:  the expression "class Snafu $snafu {}' (class with tag & body but nothing between curly braces) causes a "Syntax Error" rendering.
commented Mar 6, 2018 by matthewadams12 (240 points)
Loving this feature as I'm using it!  However, I found another small bug/edge case.

Bug 4:  the expression "hide2 $*" doesn't appear to have any effect.  That statement should hide all c/i/e/a's that have one or more tags.  I'm following it with the expression "show2 $txn" to then show all c/i/e/a's that have tag "$txn".  If I use the expression "hide2 *" followed by "show2 $txn", I get all c/i/e/a's with tag "$txn", but zero notes are rendered, which isn't my intention.
commented Mar 6, 2018 by plantuml (294,960 points)
We've built a new beta http://beta.plantuml.net/plantuml.jar that should solve most of the bugs you've found. Note that now you have to use hide/show (and not hide2/show2 anymore)
Not sure to understand bug 4. The following example is working for us:
@startuml
class foo1 $tag1
class foo2 $txn {
}
class foo3
hide $*
show $txn
@enduml

If you find issues, do not hesitate to post snipset that shows them.
Tag should work for packages now, but we're still interested in feedback : we're bad in testing :-)
commented Mar 6, 2018 by matthewadams12 (240 points)
RE Bug 4, I've been able to distill it to a simple example.  Given four separate files, Foo.puml, Bar.puml, Goo.puml & diagram.puml with the following content:

'file Foo.puml
class Foo $a
Foo -- Goo

'file Bar.puml
class Bar $z

'file Goo.puml
class Goo

'file diagram.puml
@startuml
!include Foo.puml
!include Bar.puml
hide $*
show $z
@enduml

With your latest beta, since Bar is the only class tagged with $z, I expect only to see class Bar in the diagram, but PlantUML renders both Bar & Goo.
commented Mar 6, 2018 by plantuml (294,960 points)
edited Mar 6, 2018 by plantuml
Ok, I've merged your example in :
@startuml
class Foo $a
Foo -- Goo
class Bar $z
hide $*
show $z
@enduml

However, since Goo does not have any tags it's not hidden by "hide $*"
So everything looks fine to me.
Did I miss something ?
EDIT:
> Further, it would be nice if the default hide/show behavior defaulted
> depending on which hide/show directive were encountered first
Ok, here is what I've missed : no, this has not been implemented in the beta
commented Mar 6, 2018 by plantuml (294,960 points)
So if you want to default behavior to hide by default, just use "hide *" as first.
I think you'll get the behaviour that your are expecting. Am I right ?
commented Mar 6, 2018 by matthewadams12 (240 points)
Unfortunately, no.  If I change the hide statement to just "hide *", PlantUML hides Goo, like it should, but it also hides notes, too.  How can I say "show notes", then?

@startuml
class Foo $a
Foo -- Goo
class Bar $z
note "A note" as N1
N1 .. Bar
hide *
show $z
@enduml
commented Mar 6, 2018 by plantuml (294,960 points)
Good question...
We could exclude notes from all this show/hide mechanism..
Probably the best solution is to allow tags on note.
So yet another beta http://beta.plantuml.net/plantuml.jar (version 1.2018.02beta20) that supports:
@startuml
class Foo $a
Foo -- Goo
class Bar $z
note "A note" as N1 $z
N1 .. Bar
hide *
show $z
@enduml
What do you think about it ? Does it sound logical to you ?
commented Mar 7, 2018 by matthewadams12 (240 points)
I like that.  It allows me to put notes anywhere.  I'm ok with it, provided that I can add tags to every form of the note syntax (there are many).  From what I can tell, it looks like tags could be appended to the "as" clause in most forms.  Please ensure that _all_ forms of notes can be tagged in the syntax change.

While you're at it, are there any other primitives that could tagged and later hidden/shown?  I've only made these suggestions in the context of class diagrams.  I'd welcome input regarding tags on other artifact types that are in other kinds of diagrams, too!  :)

Great work!

PS: I would find it helpful if y'all were doing this work on a remote branch in a public git repo rather than privately in subversion.  I could've seen the changes you've been making, more easily learned your codebase, played around with things, tried different things out, and, most importantly, saved you some work!  :)
commented Mar 7, 2018 by matthewadams12 (240 points)
edited Mar 7, 2018 by matthewadams12
I just noticed one more thing about hiding elements.  It appears, although I'm not 100% sure, that the hidden elements still take up screen space.  I think it would be preferable, when hiding something, for it to never be included in the diagram at all, so that it never has the ability to take up any space.
commented Mar 7, 2018 by plantuml (294,960 points)
> Please ensure that _all_ forms of notes can be tagged in the syntax change.
> While you're at it, are there any other primitives that could tagged and later hidden/shown?
> I've only made these suggestions in the context of class diagrams.
> I'd welcome input regarding tags on other artifact types that are in other kinds of diagrams, too!  :)
>
Yes, we also would like to extends those tags to every diagrams.
Because of the way we parse texts, it's difficult to garantee that _all_ forms of notes are supported.
It should sound very strange to you, but the quickest way for us to proceed is to wait for users to report bugs...

About hide/show, you're 100% right. This is not something we can change because it has been implemented that way for some users.
The good news is that we've added remove/restore in last beta http://beta.plantuml.net/plantuml.jar that really remove elements. You'll see that it can be an issue, because the layout may be highly impacted by element removals.

So you can have:
@startuml
class Foo $a
Foo -- Goo
class Bar $z
note "A note" as N1 $z
N1 .. Bar
remove *
restore $z
@enduml

About code change, I am aware that using a private subversion is not very open, and that a public git repo would be far better. All this will be released in the incoming days/weeks so that you will be able to see how it works.

Thanks for your tests-to-be about remove/restore :-)
commented Nov 20, 2023 by The-Lu (63,920 points)

Hi PlantUML team,

It seems that the last example is broken...

@startuml
class Foo $a
Foo -- Goo
class Bar $z
note "A note" as N1 $z
N1 .. Bar
remove *
restore $z
@enduml

  • Could you have a look?

See also, same remark here:

Regards,
Th.

...