Align packages vertically in PlantUML - plantuml

I have a class structure of something like this:
#startuml
package "A" {
ABase <|-- A1
ABase <|-- A2
ABase <|-- A3
}
package "B" {
BBase <|-- B1
BBase <|-- B2
BBase <|-- B3
}
package "C" {
CBase <|-- C1
CBase <|-- C2
CBase <|-- C3
}
#enduml
PlantUML renders the packages next to each other. This can get way too wide if class names are longer, or there are more subclasses, as the subclasses are always put next to each other. Is there any way to make the packages be aligned vertically?
I tried using left to right direction, which is an improvement, but has its own problems. I'd want a top to bottom direction for each package, but the packages should be below each other.

Many vertically challenged diagrams and what feels like hours of horizontal scrolling have made me ask the same question as you. Alas, the only admittedly unsustainable workaround that I have found so far is to create vertical helper links between the classes. That is fine for small diagrams but as I said, I would not call it sustainable as your diagram grows.
#startuml
package "A" {
ABase <|-- A1
ABase <|-- A2
ABase <|-- A3
}
package "B" {
BBase <|-- B1
BBase <|-- B2
BBase <|-- B3
}
package "C" {
CBase <|-- C1
CBase <|-- C2
CBase <|-- C3
}
A2 -[hidden]down- BBase
B2 -[hidden]down- CBase
#enduml

I tested with this code and maybe what you want to achieve.
#startuml
package Main{
}
package A{
}
Main -- A /'Main above A in vertical'/
A -- Main /'A above Main in vertical '/
Main - A /'same as position of code'/
A - Main /'same as position of code'/
#enduml

Probably not the solution you want, but newpage after each package will make them appear on separate pages (you'd need a GUI that supports multipage diagrams such as PlantUML for VSCode). Could be useful if you're combining the images in a single document.
#startuml
package "A" {
ABase <|-- A1
ABase <|-- A2
ABase <|-- A3
}
newpage
package "B" {
BBase <|-- B1
BBase <|-- B2
BBase <|-- B3
}
newpage
package "C" {
CBase <|-- C1
CBase <|-- C2
CBase <|-- C3
}
#enduml

Related

How to "forward" an object property from a pair of individuals to another?

Supposing I have:
some individuals a1 and a2 from class A, b1 and b2 from class B
an object property "myProperty" from A to A or B to B.
an object property "otherProperty" from A to B
a1 :myProperty a2
a1 :otherProperty b1 and a2 :otherProperty b2
Is there a simple way to infer b1 :myProperty b2?
I am using Protégé with OWL, and I haven't found in the documentation (https://protegeproject.github.io/protege/views/object-property-characteristics) any way to do it.

Plantuml: Why does adding an element cause major diagram repositioning? (deployment, class)

Another try at a semi-complicated deployment diagram (content is deployment:ish).
Background: I add components one by one, it works (see on plantuml server here)
until I get to "aabb9" (i e a9)...
Problem: When I add aabb9 to be the target of an "up" arrow from aabb5, I expect aabb9 to be placed above aabb5, where there is space. Like this:
Instead, the diagram layout is almost completely redone by the engine, and seemingly, the previously defined relationships are no longer "respected". So the (bad) result becomes:
Notice how the first nodes now come rightmost, and my relationships specified to be going to the right from those two (aabb1 & aabb2), are no longer "respected"/drawn as entered. Here is that same drawing with the line uncommented, and the "bad"/undesired result.
So, below here is the code that works, but if you uncomment the last line, it goes bananas and "relayouts" the whole thing.
Any clues to this? It would be cool to be able to create these simple diagrams with text...
Thanks! /mawi
#startuml
skinparam ranksep 5
skinparam nodesep 5
rectangle "aabb1" {
node aabb1 as a1
node aabb2 as a2
}
a1 --[hidden]> a2
control "aabb3" as a3
database "aabb4" as a4
queue "aabb5" as a5
control "aabb6" as a6
control "aabb7" as a7
database "aabb8" as a8
control "aabb9" as a9
a1 -right-> a3: Range
a2 -right-> a3: 3D Models
a3 -down-> a4: Range & Models
a3 -> a5: product.\nupsert
a5 -down-> a6: product.\nupsert
a6 -> a5: product.\nprocessed
a5 -> a7: product.processed
a7 -> a8: Data
a7 -> a5: product.\nstored
'a5 -up-> a9: product.stored
#enduml
Ok, so I figured I'd continued experimenting a bit before giving up, and I found what works for this case, and a hypothesis, but no root cause...
What works?
So, if I add a relationship/flow from the new "free" node (i e "aabb9") and not to it, it works. So, if I do e g a9 -down-> a5: product.stored, it works as expected.
And once that is done, I can add the flow from the rest of the diagram to the new node, i e uncomment the last line.
So the key is that I need to do the down arrow first: To link from the new node to the rest of the diagram, before the up arrow line that was commented.
Then the engine will layout aabb9 correctly.
To achieve the exact result I was after, I can just reverse the arrowhead of that flow, so I get a9 <-down- a5: product.stored.
But it almost seems like a bug. :-)
Comments and thoughts welcome, hope this helps some poor plantuml explorer. :)
Edit: here's the code:
#startuml
skinparam ranksep 5
skinparam nodesep 5
rectangle "aabb1" {
node aabb1 as a1
node aabb2 as a2
}
a1 --[hidden]> a2
control "aabb3" as a3
database "aabb4" as a4
queue "aabb5" as a5
control "aabb6" as a6
control "aabb7" as a7
database "aabb8" as a8
control "aabb9" as a9
a1 -right-> a3: Range
a2 -right-> a3: 3D Models
a3 -down-> a4: Range & Models
a3 -> a5: product.\nupsert
a5 -down-> a6: product.\nupsert
a6 -> a5: product.\nprocessed
a5 -> a7: product.processed
a7 -> a8: Data
a7 -> a5: product.\nstored
a9 -down-> a5: product.stored
a5 -up-> a9: product.stored
#enduml

Django ORM to get a nested tree of models from DB with minimal SQL queries

I have some nested models with foreign key relationships going 4 levels deep.
A <- B <- C <- D
A has a set of B models, which each have a set of C models, which each have a set of D models.
I'm iterating of the each model (4 layers of looping from A down to B). This is producing lots of DB hits.
I don't need to do any filtering at the DB fetch level, as I need all the data from all the DB tables, so I ideally I'd like to get all the data with ONE SQL query that hits the DB (if that's possible) and then somehow have the data organized/filtered into their correct sets for each model. i.e. it's all pre-fetched and structured ready for using the data (e.g. in a web dashboard).
There seems to be a lot of django related pre-fetch helpers and packages, but none of them seem to work the way I expect. e.g. django-auto-prefetch (which seems ideal).
Is this a common use case (I thought it would be)?
How can I construct the ORM to get all the data in one hit and then just use the bits I need.
NOTE: target system is raspberry pi class device (1GHz Arm processor) with eMMC storage (similar to SD card), and using SQLite as the DB backend.
NOTE: I'm also using this with django-polymorphic, which may or may not make a difference?
Thanks, Brendan.
Using one query would result in a huge amount of bandwidth, since the values for the columns of the A model will be repeated per B model per C model per D model.
Indeed, the response would look like:
a_col1 | a_col2 | b_col1 | b_col2 | c_col1 | d_col1
A1 A1 B1 B1 C1 D1
A1 A1 B1 B1 C1 D2
A1 A1 B1 B1 C1 D3
A1 A1 B1 B1 C2 D4
A1 A1 B1 B1 C2 D5
A1 A1 B1 B1 C2 D6
A1 A1 B2 B2 C3 D7
A1 A1 B2 B2 C3 D8
A1 A1 B2 B2 C3 D9
A1 A1 B2 B2 C4 D10
A1 A1 B2 B2 C4 D11
A1 A1 B2 B2 C4 D12
A2 A2 B3 B3 C5 D13
A2 A2 B3 B3 C5 D14
A2 A2 B3 B3 C5 D15
A2 A2 B3 B3 C5 D16
We thus would repeat the values for the a_columns, b_columns, etc. a large number of times resulting in a large amount of bandwidth going from the database to the Python/Django layer. This would not only result in large amounts of data being transferred, but also large amounts of memory being used by Django to deserialize this response.
Therefore .prefetch_related makes one (or two depending on the type of relation) extra queries per level at most, so three to seven queries in total, which will minimize the bandwidth.
You thus can fetch all objects in memory with:
for a in A.objects.prefetch_related('b_set', 'b_set__c_set', , 'b_set__c_set__d_set'):
print(a)
for b in a.b_set.all():
print(b)
for c in b.c_set.all():
print(c)
for d in c.d_set.all():
print(d)

How to generate all possible rankings of a document set when each document can take one of 2 types?

I need to generate possible ranking of all possible ranking of n documents. I understand that the permutations of an array {1, 2,..., n} will give me the set of all possible rankings.
My problem is a bit more complex as each document could take one of 2 possible types. Therefore, in all there are n!*2n possible rankings.
For instance, let us say I have 3 documents a, b, and c. Then possible rankings are the following:
a1 b1 c1
a1 b1 c2
a1 b2 c1
a1 b2 c2
a2 b1 c1
a2 b1 c2
a2 b2 c1
a2 b2 c2
a1 c1 b1
a1 c1 b2
a1 c2 b1
a1 c2 b2
a2 c1 b1
a2 c1 b2
a2 c2 b1
a2 c2 b2
b1 a1 c1
b1 a1 c2
b1 a2 c1
b1 a2 c2
b2 a1 c1
b2 a1 c2
...
What would be an elegant way to generate such rankings?
It's a kind of cross product between the permutations of B={a,b, ...} and the k-combinations of T{1,2} where k is the the number of elements in B. Say we take a p from Perm(B), e.g. p=(b,c,a) and a c from 3-Comb(T), e.g. c=(2,1,1) then we would merge p and c into (b2,c1,a1).
I don't really know if it's elegant but I would choose an algorithm to generate sequentially the permutations of B (cf TAOCP Volume 4 fascicle 2b) and for each permutation apply the above "product" with all the k-combinations generated sequentially (or stored in an array if k is small) (cf TAOCP Volume 4 fascicle 3a).
B={a,b,c, ... }
T={1,2}
k=length(B)
reset_perm(B)
do
p = next_perm(B)
reset_comb(T,k)
do
c = next_kcomb(T,k)
output product(p,c)
while not last_kcomb(T,k)
while not last_perm(B)

Parallel iteration over lists in makefile or CMake file

Is there a way to loop over multiple lists in parallel in a makefile or CMake file?
I would like to do something like the following in CMake, except AFAICT this syntax isn't supported:
set(a_values a0 a1 a2)
set(b_values b0 b1 b2)
foreach(a in a_values b in b_values)
do_something_with(a b)
endforeach(a b)
This would execute:
do_something_with(a0 b0)
do_something_with(a1 b1)
do_something_with(a2 b2)
I would accept an answer in either CMake or Make, though CMake would be preferred. Thanks!
Here you go:
set(list1 1 2 3 4 5)
set(list2 6 7 8 9 0)
list(LENGTH list1 len1)
math(EXPR len2 "${len1} - 1")
foreach(val RANGE ${len2})
list(GET list1 ${val} val1)
list(GET list2 ${val} val2)
message(STATUS "${val1} ${val2}")
endforeach()
As of CMake 3.17, the foreach() loop supports a ZIP_LISTS option to iterate through two (or more) lists simultaneously:
set(a_values a0 a1 a2)
set(b_values b0 b1 b2)
foreach(a b IN ZIP_LISTS a_values b_values)
message("${a} ${b}")
endforeach()
This prints:
a0 b0
a1 b1
a2 b2
In make you can use the GNUmake table toolkit to achieve this by handling the two lists as 1-column tables:
include gmtt/gmtt.mk
# declare the lists as tables with one column
list_a := 1 a0 a1 a2 a3 a4 a5
list_b := 1 b0 b1 b2
# note: list_b is shorter and will be filled up with a default value
joined_list := $(call join-tbl,$(list_a),$(list_b), /*nil*/)
$(info $(joined_list))
# Apply a function (simply output "<tuple(,)>") on each table row, i.e. tuple
$(info $(call map-tbl,$(joined_list),<tuple($$1,$$2)>))
Output:
2 a0 b0 a1 b1 a2 b2 a3 /*nil*/ a4 /*nil*/ a5 /*nil*/
<tuple(a0,b0)><tuple(a1,b1)><tuple(a2,b2)><tuple(a3,/*nil*/)><tuple(a4,/*nil*/)><tuple(a5,/*nil*/)>

Resources