plantuml / plantuml

Generate diagrams from textual description
https://plantuml.com
Other
9.73k stars 881 forks source link

Support for table-like objects #307

Open hallvard opened 4 years ago

hallvard commented 4 years ago

Most OO languages support table-like data structures, that although they're encapsulated in objects, are better rendered as tables. E.g. a Collection is a single-row table, a List is a two row table with indices 0..size-1 in the header row and values in the other, a Map is a two row table with the keys in the first row and values in the second.

To get an effect similar to this, we currently can do something like this:

@startuml object "map: Map<Integer, String>" as map { |= 1 |= 2 |= 3 | | Hi | There | ! | } @enduml

Map instance

Although the table isn't rendered correctly here, you get the idea. However, table cells cannot contain be the source of references (links), so in practice this limits us to simple values. So if syntax was added for naming a table cell and that name could be use in relation syntax and it would be rendered as a dot from which the link is drawn, then we're pretty close.

E.g. @startuml object "map: Map<Integer, Object>" as map { |= 1 |= 2 | | as cell1 | as cell2 | } object target1 object target2 cell1 --> target1 cell2 --> target2 @enduml

arnaudroques commented 4 years ago

Very interesting idea... Although you are enlarging our TODO list :-)

First, I think we really need a dedicated syntax here. What about using a new keyword TABLE and using => separator.

This way, you could have:

table CapitalCity {
 UK => London
 USA => Washington
 Germany => Berlin
 Italy => Rome
}

table "map: Map<Integer, String>" as users {
 1 => Alice
 2 => Bob
 3 => Charlie
}

Note that the rendering of the Table would be verticaly (rather than horizontaly in your example). Something like (but with a better result)

http://www.plantuml.com/plantuml/uml/Iyv9B2vMS4uio2n9p77EBAbKgEQgKGZrLgXHyCdFIydFKwW1yOCTWGBXYSKPcNdf9L11zzIYtCIyIg24KsfHJYP4q1De34WeA3yt4IXGomK0

Then, we could use connector in the following way : CapitalCity::UK --> foo

To get something like: http://www.plantuml.com/plantuml/uml/SoWkIImgAStDuKhEIImkLYWjJYrIgERAJE7AIynDvQhbWeed9YVdb-QL0ANoIdD1mY25LbQPAGgwkdOmMIiha2INGsfU2j140000

Does it make sense to you ?

hallvard commented 4 years ago

I think it is a good idea to have a dedicated syntax and the suggested one seems OK. But note that the content of a cell can be a reference, rendered as some kind of line originating from the cell itself (or a dot inside the cell). In that case there will not be any text on the cell. Since the cell cannot be a target of a link, you could include the reference into the syntax:

table "name2person: Map<String, Person>" as name2person { "hal" => --> hallvard "plantuml" => --> arnaud } object "hallvard: Person" as hallvard object "arnaud: Person" as arnaud

This would render as two objects, and a table with two columns where the second column is cells from which there are lines to the two objects, respectively. Note that both sides of the mapping can be a reference, like a Map<Object, Object>.

arnaudroques commented 4 years ago

Ok, I better understand your point now. I need some time to think about it, it's an interesting challenge... I'll post a message here when some beta will be ready :-)

hallvard commented 4 years ago

If you can implement cell-with-reference rendering, you could consider supporting it in attributes, since it will look a bit like how Java objects are illustrated in text books. Of course, this removes the abstraction that UML provides (of OO languages), but is helpful for students. E.g.

object "hallvard: Person" as hallvard { spouse = --> marit }

object "marit: Person" as marit { spouse = --> hallvard }

This could render as a "spouse" label with a link to the other object starting at a dot just to the right of the label. This shouldn't affect the layout that much, e.g. you could assume for layout purposes that the link is attached to the edge. And even support hints like -right->

arnaudroques commented 4 years ago

We've started something with last beta http://beta.plantuml.net/plantuml.jar

It's still under work, but we can talk about it.

With this beta, you can now have :

@startuml
map CapitalCity {
 UK => London
 USA => Washington
 Germany => Berlin
}
@enduml

We choose map as keyword because it's more appropriate than table that we might use in the future. You can also have:

@startuml
object London

map CapitalCity {
 UK *-> London
 USA => Washington
 Germany => Berlin
}
@enduml

It's not completely finished yet : we have to draw a link between the big dot and London object. This is really the tricky part : I'm not 100% sure that we are going to success.

What do you think about the syntax ? Any idea/feedback is welcome :-)

hallvard commented 4 years ago

I haven't had a chance to look at the beta, but I would like to comment on the syntax. It does look nice, I like the "shortcut" with a general relation replaces the double array. Compared to may proposal, it omits the => arrow, i.e. "Hallvard" => -> hallvard becomes "Hallvard" -> hallvard if I understand your proposal correctly.

But you need also to support the general case where one object maps to another. If you first check if either side is a reference, this would work:

object hallvard
object marit

map Wife {
   hallvard => marit
}

This would render as two cells with a dot and ordinary arrows. But you won't be able to customise the link to both at the same time, with this syntax. e.g. if both links are supposed to be stippled. In my proposal, each side could be a link on its own:

map Wife {
   ..> hallvard => ..> marit 
}

or even

map Wife {
   hallvard <.. => ..> marit 
}

I'd say allow this syntax, combined with the shortcut where you can omit the => when there's already a link in between them.

arnaudroques commented 4 years ago

We have published a new official release with some new features. This is still experimental.

We are getting close to GraphViz limit here : I think there is no way to impose to GraphViz to use both left and right side of a map.

Example of what you can have:

http://www.plantuml.com/plantuml/uml/SoWkIImgAStDuUBAJyfAJIvHyCdFIydFW_724uipClFIIn0YJgb5EPbmdbzgUMH-KJONLsvYWO9pOa5cIMAESsP9fK8rbqAejuAMhXtKG20ts1781meWcQdWdbgKcvXN2PG0oi3ChkNYWfgh01H5DjRA2cWAbqDgNWhGoG00

The real issue is that on complex example, you can end up with very strange result:

http://www.plantuml.com/plantuml/uml/SoWkIImgAStDuSfFoafDBb78ICp9AKiiIe7nSnEBCajWdABytDHy62UhD2SpjOIBYoitiK0XF3CjLQ6Q2wvTGK5BLzSEgXkY3oW2589fg-NYGgW5YeDDiBA2Mm_HeekGWTZja9gN0dGj0000

Note that the syntax is not final yet. Once again, it's not the syntax which is an issue here.

I let you play with last version : tell us if you succeed in having something ok.

hallvard commented 4 years ago

This isn't quite what I thought of... The map needs to show both the key and value and must handle several cases, that are visualised below:

Screenshot 2020-04-06 at 23 54 08

I don't think it makes sense to point to to the entry/row, since you don't navigate that way. The link(s) must come from the key and/or value slot.

danielzgtg commented 3 years ago

I am struggling to do the following:

  1. Create bare rows. I want to simultaneously turn off the vertical line and the arrow going out
  2. Label the arrows going out

Basically, I would like the following code to work:

object Foo
map Bar {
  abc
  def
}
object Baz

Bar::abc --> Baz : Label one
Foo --> Bar::def : Label two
The-Lum commented 2 years ago

Hello @danielzgtg,

A possible workaround is to add =>:

@startuml
object Foo
map Bar {
  abc=>
  def=>
}
object Baz

Bar::abc --> Baz : Label one
Foo --> Bar::def : Label two
@enduml

If that can help, Regards.

schindld commented 2 years ago

Is this able to handle map keys with spaces in them, or icons next to them? For example:

@startuml
!define PK <size:12><&key></size><b>
!define FK <size:12><&link-intact></size><i>
map A {
  PK id => [string]
  FK parent_id => [string]
  foo => [string]
  bar => [int]
}
'A::"FK parent_id" -> A::"PK id"
A::parent_id -> A::id
@enduml

Is there a way to get the arrow to point from parent_id to id instead of from A to A?

The-Lum commented 2 years ago

Hello @schindld,

For:

Is there a way to get the arrow to point from parent_id to id instead of from A to A?

See also a pseudo-similar request here:

Regards.

schindld commented 2 years ago

Thanks @The-Lum , that's definitely part of it.

For key/field names with spaces (maybe using the "as id" syntax?) part, should I open another issue?