我正在创建一个用于将Python项目显示为UML图的工具(+使用GUI显示一些代码错误检测)
我使用Pyreverse扫描一些项目,我拥有绘制UML图所需的所有数据。 问题是在画布上定位类框
首先,我决定使用已经实现的基于力的算法来决定类的位置,它的效果非常好这里的结果 https://github.com/jvorcak/gpylint/blob/master/screenshots/gpylint.png 这里是code(Python,但即使非Python程序员也很容易理解)
有一个问题,它非常适合显示图形,但如果我想显示UML,我想要一些增强功能,例如,如果2个类扩展了一个超类,我希望它们处于同一级别在graphs generated by dot program
中的图表中你能告诉我一个算法怎么做?或者至少给我一些想法?
答案 0 :(得分:8)
您似乎缺少的主要增强功能是将图表转换为layered graph.这是不容易的任务,但它可行。 (结果的质量可能会因为过程中投入的时间和精力而有所不同)。
主要思想是在图表上做某种topological sorting将其拆分为图层,在其中进行一些排列然后绘制图形。 (你可以找到python代码在线进行真正的拓扑排序(example),但真正的TS只会产生一个类似于长线的图,我们想要一些不同的东西)
因此,我将尝试描述一种算法,将给定的图形转换为分层图形:
拓扑排序不适用于具有周期的图形,因此如果输入图形不是没有周期的有向图形,则必须找到一组可以删除的边缘(或者可能是反转的) )创建一个循环图(稍后你会将它们添加到分层图中,但这会制动分层并使图不那么漂亮:)。由于找到可以移除的最小边缘集是NP完全(非常难) - 我认为你必须在这里做一些快捷方式,并且不一定找到最小边集,但是在合理的时间内完成。 / p>
将图形制作成图层,可以在此处进行许多优化,但我建议您保持简单。迭代所有图形的顶点,每次收集所有顶点,没有到图层的入边。在某些简单的情况下,这可能会产生类似线条的图形,但在UML图形的情况下它非常适合。
一个好的图是具有最小边数crossing each other的图,它听起来并不重要,但这个事实对图的整体外观有很大影响。决定交叉数的原因是每一层中边缘的排列顺序。但是,找到最小交叉数或找到最大无交叉边集是NP完全的:(“所以再次这是典型的采用启发式方法,例如将每个顶点放置在一个位置,该位置通过查找前一级别上邻居位置的平均值或中位数确定,然后交换相邻对,只要这样可以改善交叉次数。“
< / LI>算法第一步中删除(或反转)的边缘将返回其原始位置。
你有它!一个很好的UML分层图。
希望我的评论在任何方面都有所帮助。
重要更新: 既然你说你是“寻找可靠和/或官方来源的答案。” 我附上 This 来自graphviz(dot算法)的正式文档“描述了用于绘制有向图的四遍算法。第一遍使用网络单纯形算法找到最佳秩分配。第二遍通过迭代启发式设置秩内的顶点顺序结合新颖的权重函数和局部变换来减少交叉。第三遍通过构造和排列辅助图来找到节点的最佳坐标。第四遍使样条绘制边缘。算法绘制好图纸并快速运行。 http://www.graphviz.org/Documentation/TSE93.pdf
答案 1 :(得分:3)
连接组件的约束布局是一个非常重要的问题,您可能最好使用现有工具来解决。你提到Graphviz,但我认为你找不到一个简单的算法来移植到Python。更好的解决方案可能是使用pydot与Graphviz连接并让它处理布局。
流程看起来像:
Graphviz处理布局,但所有显示仍然在Python中,以允许您想要支持的任何自定义行为。
答案 2 :(得分:2)
提供我自己的答案building on blahdiblah's,您确实可以使用建议的工作流程来成功生成UML图表。
但是,这似乎需要你的解决方案的花园路径,这似乎不适合你的应用程序的设计。具体来说,我们希望reduce the number of theoretical moving parts required能够实现这一目标。
我建议不要使用pyreverse来查看the alternatives mentioned in this thread。具体而言,诸如Epydoc之类的工具可以更好地满足您的需求,既可以减少依赖性,又可以减少其(MIT)许可结构。
无论您选择哪条路径,都应运气好。
答案 3 :(得分:0)
我不是一个python程序员,但在功能上我可以建议你。
您必须拥有每个班级的行数
保持班级的等级编号,以帮助您根据等级编号组织班级。
答案 4 :(得分:0)
如果你想以有序的方式展示课程(父母的上层,孩子们的底部),你应该跟踪&#34;体重&#34;每节课。我的体重是指父母的数量&#34;。
例如,如果B继承自A,B.weight = 1和A.weight = 0.并且如果C继承自B,则C.weight = 2.如果将此表示为一行,则将打印A类在第0行,B在第1行,C在第2行。一般来说,所有类别的相同&#34;权重&#34;将打印在同一条虚线上。
当然,这只是基本思想,如果你想要tu支持复杂的对象(多重遗产等),定位元素将比这更难。
答案 5 :(得分:0)
你不太可能从没有开发UML优先的真实项目中获得好的结果。这是我们10年前使用第一个java-uml往返工具(TogetherJ)学到的一课。在文本模式下,很容易摆脱不可能很好地绘制的代码。与UML工具当前提供的相比,smalltalk系统的动态基于浏览器的视图作为一种深入了解代码的方式更加有效。
对于布局,只需看看CAD中用于电子产品的所有工作,尤其是印刷电路板(PCB)。那里有很好的布局和布线算法。我没有看到自动UML工具正确做的事情之一就是处理很多子类,你希望布局从父类下面的一行类改为双行,低节点移动半个节点。