从 Graphviz 中的点图中删除不必要的负空间

Posted

技术标签:

【中文标题】从 Graphviz 中的点图中删除不必要的负空间【英文标题】:Removing Unnecessary Negative Space from Dot Graph in Graphviz 【发布时间】:2021-12-21 18:12:44 【问题描述】:

我正在尝试使用 Graphviz 使用点绘制 ER 图。我有以下内容:

digraph ERD 
graph [ rankdir = "LR" ];
ranksep=1;
"DEPARTMENT" [ label="<DEPARTMENT> DEPARTMENT|<PK_DEPARTMENT>deptcode \l | <F_DEPARTMENT> self* \ldeptcode \ldeptname \l " shape = "record", style = "rounded" ];
"COURSE" [ label="<COURSE> COURSE|<PK_COURSE>cnum \l | <F_COURSE> self* \lcnum \lcname \ldepartment* \l " shape = "record", style = "rounded" ];
"PROFESSOR" [ label="<PROFESSOR> PROFESSOR|<PK_PROFESSOR>pnum \l | <F_PROFESSOR> self* \lpnum \lpname \loffice \ldepartment \l " shape = "record", style = "rounded" ];
"CLASS" [ label="<CLASS> CLASS|<PK_CLASS>term \l | <F_CLASS> self* \lcourse* \lterm \lsection \lprofessor* \l " shape = "record", style = "rounded" ];
"ENROLLMENT" [ label="<ENROLLMENT> ENROLLMENT|<PK_ENROLLMENT> | <F_ENROLLMENT> self* \lstudent* \lclass* \l " shape = "record", style = "rounded" ];
"SCHEDULE" [ label="<SCHEDULE> SCHEDULE|<PK_SCHEDULE>time \l | <F_SCHEDULE> self* \lclass* \lday \ltime \lroom \l " shape = "record", style = "rounded" ];
"MARK" [ label="<MARK> MARK|<PK_MARK>grade \l | <F_MARK> self* \lenrollment* \lgrade \l " shape = "record", style = "rounded" ];
"STUDENT" [ label="<STUDENT> STUDENT|<PK_STUDENT>snum \l | <F_STUDENT> self* \lsnum \lsname \lyear \l " shape = "record", style = "rounded" ];

"COURSE":"F_COURSE"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"PROFESSOR":"F_PROFESSOR"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"CLASS":"F_CLASS"->"COURSE":"PK_COURSE" [arrowhead = normal] [label="generic label"];
"ENROLLMENT":"F_ENROLLMENT"->"CLASS":"PK_CLASS" [arrowhead = normal] [label="generic label"];
"SCHEDULE":"F_SCHEDULE"->"CLASS":"PK_CLASS" [arrowhead = normal] [label="generic label"];
"MARK":"F_MARK"->"ENROLLMENT":"PK_ENROLLMENT" [arrowhead = normal] [label="generic label"];

但是,点引擎放置节点时会导致图中出现过多的负数/空白。它最终看起来像这样:

例如,PROFESSOR 表可以很容易地放在 COURSE 表上方以节省空间。可以对 SCHEDULE 表进行类似的优化。此外,DEPARTMENT 表可以放在 COURSE 和 PROFESSOR 的左侧,而不是右侧。

通过在互联网上阅读有关此内容,我发现可能设置了 rankdir。但是,我认为我需要它是 LR,因为否则节点本身是横向的......

有什么方法可以让箭头双向(不仅仅是从左到右,反之亦然?)以节省空间?或者我可以指定一些其他属性来最小化我的图表中不必要的负/空白的数量?不过我不想让节点、字体或箭头的长度变小。

谢谢!

【问题讨论】:

【参考方案1】:

也许你应该为rank=same 点赞

digraph ERD 
graph [ rankdir = "LR" ];
ranksep=1;
"DEPARTMENT" [ label="<DEPARTMENT> DEPARTMENT|<PK_DEPARTMENT>deptcode \l | <F_DEPARTMENT> self* \ldeptcode \ldeptname \l " shape = "record", style = "rounded" ];
"COURSE" [ label="<COURSE> COURSE|<PK_COURSE>cnum \l | <F_COURSE> self* \lcnum \lcname \ldepartment* \l " shape = "record", style = "rounded" ];
"PROFESSOR" [ label="<PROFESSOR> PROFESSOR|<PK_PROFESSOR>pnum \l | <F_PROFESSOR> self* \lpnum \lpname \loffice \ldepartment \l " shape = "record", style = "rounded" ];
"CLASS" [ label="<CLASS> CLASS|<PK_CLASS>term \l | <F_CLASS> self* \lcourse* \lterm \lsection \lprofessor* \l " shape = "record", style = "rounded" ];
"ENROLLMENT" [ label="<ENROLLMENT> ENROLLMENT|<PK_ENROLLMENT> | <F_ENROLLMENT> self* \lstudent* \lclass* \l " shape = "record", style = "rounded" ];
"SCHEDULE" [ label="<SCHEDULE> SCHEDULE|<PK_SCHEDULE>time \l | <F_SCHEDULE> self* \lclass* \lday \ltime \lroom \l " shape = "record", style = "rounded" ];
"MARK" [ label="<MARK> MARK|<PK_MARK>grade \l | <F_MARK> self* \lenrollment* \lgrade \l " shape = "record", style = "rounded" ];
"STUDENT" [ label="<STUDENT> STUDENT|<PK_STUDENT>snum \l | <F_STUDENT> self* \lsnum \lsname \lyear \l " shape = "record", style = "rounded" ];

"COURSE":"F_COURSE"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"PROFESSOR":"F_PROFESSOR"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"CLASS":"F_CLASS"->"COURSE":"PK_COURSE" [arrowhead = normal] [label="generic label"];
"ENROLLMENT":"F_ENROLLMENT"->"CLASS":"PK_CLASS" [arrowhead = normal] [label="generic label"];
"SCHEDULE":"F_SCHEDULE"->"CLASS":"PK_CLASS" [arrowhead = normal] [label="generic label"];
"MARK":"F_MARK"->"ENROLLMENT":"PK_ENROLLMENT" [arrowhead = normal] [label="generic label"];

rank=same STUDENT PROFESSOR SCHEDULE MARK

导致:

【讨论】:

感谢您的提示。我不认为这个图真的像 ER 图,因为节点不是均匀分布的,而且 DEPARTMENT 节点还有很多空白。是否可以让箭头也从右向左移动?那么也许 DEPARTMENT 节点可以放在 ENROLLMENT 节点下以节省空间... 您是否尝试过使用 rank=same 的类似技巧(看起来它开箱即用)【参考方案2】:

如果您不介意一些调整,您可以添加一些不可见的边缘和重量说明。注释代码:

digraph ERD 
graph [ rankdir = "LR" ];
ranksep=1;
"DEPARTMENT" [ label="<DEPARTMENT> DEPARTMENT|<PK_DEPARTMENT>deptcode \l | <F_DEPARTMENT> self*    \ldeptcode \ldeptname \l " shape = "record", style = "rounded" ];
"COURSE" [ label="<COURSE> COURSE|<PK_COURSE>cnum \l | <F_COURSE> self* \lcnum \lcname \ldepartment* \l " shape = "record", style = "rounded" ];
"PROFESSOR" [ label="<PROFESSOR> PROFESSOR|<PK_PROFESSOR>pnum \l | <F_PROFESSOR> self* \lpnum \lpname \loffice \ldepartment \l " shape = "record", style = "rounded" ];
"CLASS" [ label="<CLASS> CLASS|<PK_CLASS>term \l | <F_CLASS> self* \lcourse* \lterm \lsection \lprofessor* \l " shape = "record", style = "rounded" ];
"ENROLLMENT" [ label="<ENROLLMENT> ENROLLMENT|<PK_ENROLLMENT> | <F_ENROLLMENT> self* \lstudent* \lclass* \l " shape = "record", style = "rounded" ];
"SCHEDULE" [ label="<SCHEDULE> SCHEDULE|<PK_SCHEDULE>time \l | <F_SCHEDULE> self* \lclass* \lday \ltime \lroom \l " shape = "record", style = "rounded" ];
"MARK" [ label="<MARK> MARK|<PK_MARK>grade \l | <F_MARK> self* \lenrollment* \lgrade \l " shape = "record", style = "rounded" ];
"STUDENT" [ label="<STUDENT> STUDENT|<PK_STUDENT>snum \l | <F_STUDENT> self* \lsnum \lsname \lyear \l " shape = "record", style = "rounded" ];

// added 
// ---
 rank = same; STUDENT -> MARK[ style = invis ] 
STUDENT -> ENROLLMENT[ weight = 10, style = invis ]
 rank = same; ENROLLMENT -> SCHEDULE[ style = invis ]  
ENROLLMENT -> COURSE[ weight = 10, style = invis ]
// ---
"COURSE":"F_COURSE"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"PROFESSOR":"F_PROFESSOR"->"DEPARTMENT":"PK_DEPARTMENT" [arrowhead = normal] [label="generic label"];
"CLASS":"F_CLASS"->"COURSE":"PK_COURSE" [arrowhead = normal] [label="generic label"];
//extra weight in the line below
"ENROLLMENT":"F_ENROLLMENT"->"CLASS":"PK_CLASS" [arrowhead = normal, label="generic label", weight = 10 ];
//                                                                                          ^^^^^^^^^^^
"SCHEDULE":"F_SCHEDULE"->"CLASS":"PK_CLASS" [arrowhead = normal] [xlabel="generic label"]; // xlabel for better label placement
"MARK":"F_MARK"->"ENROLLMENT":"PK_ENROLLMENT" [arrowhead = normal] [label="generic label"];

这给了你

【讨论】:

嗨!感谢您的回答 - 这张图看起来很棒。但是,我正在使用另一个程序自动生成上述点代码,并且在将 rank=same 添加到特定节点之前无法真正查看图形的呈现。有没有更自动的方法来实现这种外观?也许您根据外键声明选择了对哪些节点进行相同排名并添加不可见边? 如果不了解更多有关如何生成代码的信息,就无法回答,但总的来说,我不会过于乐观。调整往往需要一些试验和错误,这在您的上下文中似乎是没有选择的。您可以生成 rank = same 指令,但还需要额外的不可见边缘,最重要的是,重量,这使得它更复杂。

以上是关于从 Graphviz 中的点图中删除不必要的负空间的主要内容,如果未能解决你的问题,请参考以下文章

ggplot2:从图中删除未使用的因子水平组合的方面(facet_grid)

如何删除人口金字塔中的负 X 轴标签?

从深度图中提取物体边界

图的拓扑排序

Confluence 6 删除一个空间

从 Python 中的绘图饼图中删除“0%”标签