比较用于绘制网络拓扑的开源 Java 图形绘制框架(JUNG 和 Prefuse)
Posted
技术标签:
【中文标题】比较用于绘制网络拓扑的开源 Java 图形绘制框架(JUNG 和 Prefuse)【英文标题】:comparing open source java graph drawing frameworks(JUNG and Prefuse) for drawing network topology 【发布时间】:2011-06-07 22:28:42 【问题描述】:哪些开源 Java 图形绘制框架可用于具有以下要求的网络图?该图将包含少于 1000 个节点。
1) 有平行边 2) 单个图中的有向和无向边 3) 图像表示的节点 4) 用户与节点和边的交互 5) 动态添加/删除节点和边 6) 节点和边上的多个标签,用户可以关闭/打开不同级别的标签。 (例如在图层中绘制并关闭/打开图层) 7) 不同的布局算法来显示星形、环形、网状拓扑
我评估了 JUNG 和 Prefuse。这是我发现的每个要求。
1) 当 JUNG 支持时,Prefuse 无法显示平行边。可以操纵 prefuse 代码以显示平行边缘吗?由于这涉及基本的数据级别更改,我相信这将比通常的自定义渲染更改更加困难。
2) 我在 prefuse 和 JUNG 中都没有找到对组合图(有向和无向边)的任何引用。有谁知道吗?
3) 使用 Prefuse 和 JUNG 似乎很容易
4) 同样,prefuse 和 JUNG 都支持用户交互。
5) prefuse 和 JUNG 都支持它。每个框架在重绘图形时如何执行?我在另一篇文章中看到 prefuse 在动态更新方面表现不佳(Prefuse Toolkit: dynamically adding nodes and edges)
6) 这归结为修改图形并重新绘制它。所以问题就变成了 5)
7) JUNG 和 prefuse 都有多种布局算法。但是当我尝试在 JUNG 和 Prefuse 中使用 FruchtermanReingoldLayout 显示相同的数据集时,我得到了不同的显示。任何想法为什么?不知何故,Prefuse 中的布局算法似乎比 JUNG 显示了更好的布局(我认为渲染也更好),尽管 Prefuse 中的大多数布局算法都是基于 JUNG 实现的。 ForceDirectedLayout/FruchtermanReingoldLayout 和 CircleLayout 等 Prefuse 布局直接映射到星形、圆形、网状拓扑。
除了这些要求之外,prefuse 对表达式和查询语言有很好的支持,但看起来不像 JUNG 那样积极开发。哪一个有更好的可视化?关于哪一个合适以及如何克服缺点的任何建议?
还有其他我可以使用的框架吗?
【问题讨论】:
为此 +1。我喜欢你已经做了很多前期工作来评估两种可能性并展示了你的发现。除了您的问题之外,对于其他人来说,这里有很多价值。这可能是我两年来在这里见过的新用户最好的“第一个问题”。如果可以的话,我会付出更多。 【参考方案1】:我知道你指定了 jung 和 prefuse 但是... 我对 TomSawyer 和 yFiles 都有很好的经验。您提出的要求列表对这两个非常基本 - 它们支持更多。
跑。
【讨论】:
【参考方案2】:我建议也评估JGraph。
【讨论】:
【参考方案3】:几年前(2007 年?)我使用 prefuse 来可视化通话数据记录。我考虑了 prefuse、jung、jgraph 和其他几个,然后选择了 prefuse。起初,我有点难以理解 prefuse,但一旦我熟悉了它,它就真的很容易(扩展)并且使用起来很有趣。我想 JUNG 也可以这样说,但我从未尝试过。
1) 在 prefuse 中添加您自己的自定义渲染器来绘制平行边缘非常容易——您可以继承默认的 EdgeRenderer 并覆盖 render() 方法。不需要“基本数据级别更改”。如果您想将其视为 MVC 的东西,这一切都在视图部分。
2) 这根本不是问题。有不止一种方法可以做到这一点:1)您可以有两个渲染器 - 一个用于绘制有向边,一个用于绘制无向边,它们可以正常工作,并对边进行适当的分组。 2)放置一个标志(在prefuse speak的后备表元组中添加一个布尔列)指示边缘是否有向,并根据该标志在EdgeRender中相应地跳过箭头绘制部分。
3) 这超级简单
4) 同上
5) 最后一个 prefuse 版本是“prefuse beta release 2007.10.21”。我在此之前使用过一个,它在动态添加或删除节点时可能存在竞争条件——我猜它缺少一些同步关键字。我通过确保在添加或删除节点时停止所有动画和动作(颜色、大小、布局)来解决这个问题——也不要忘记更新你的 lucene 索引(如果你确实使用它的内置 lucene 搜索引擎)。最新的应该可以解决这个种族问题,但我从来没有机会尝试过。
6) 既然您提到了“多重标签”,我认为这不是“修改图形并重新绘制它”的问题 - 这只是自定义标签/边缘渲染器以仅绘制相关标签的问题,所以这不是真的一个大问题。另外我认为这根本与 5 无关。
7) prefuse 和 JUNG 对 FruchtermanReingoldLayout 的渲染不同,我并不感到惊讶 - 有几个因素可能会影响其中一个,每个实现都开始计算的起始节点,所以我不会太担心这个问题。在 prefuse 中尝试不同的内置图形布局算法非常容易,因此您可以继续检查哪个最接近您想要的。查看星形布局的 RadialLayout 和 BalloonTreeLayout。 ForceDirectedLayout 需要多次迭代才能使节点的放置“稳定”。请注意,这些迭代不是必须显示的,因此您可以在后台运行它并呈现最终结果。
我没用过JUNG,所以不能评论太多。
根据我在 prefuse 方面的经验,我强烈推荐它,因为它经过深思熟虑(恕我直言)的设计和组件之间的责任分离。 Jeffrey Heer(前言作者)确实做得很好。
使用 prefuse 时需要注意的事项(这是我在使用 prefuse 时清晰记得的两个“大拇指”):
1) 有一个错误,当缩小时,节点标签没有适当缩小,以至于它溢出节点的边界框,当节点移动时会留下字体绘制伪影,因为渲染器只清除和重绘里面的东西节点的边界框。 IIRC 这是由 AWT 字体度量本身的错误引起的。解决方法是在标签和节点边界框之间留出足够的边距。
2) 在扩展内置布局时,您可能会遇到一两个“范围问题”,其中您希望访问的超类成员被赋予私有属性而不是受保护,因此解决方案是要么修改库本身,要么创建一个不继承的新类(这可能有点痛苦!)。我想你可以对其他一些 java 库说同样的话。不是每个人都有事后诸葛亮的好处,不是吗? :)
自从您大约一个月前(在我撰写本文时)提出这个问题以来,我想知道您的决定是什么,以及如果您继续实施,结果如何。
【讨论】:
【参考方案4】:我是 JUNG 的创建者和维护者之一,因此请记住以下回复。
不过,首先,我应该说 Prefuse 的作者是朋友的朋友(是的,我们见过面),他做得很好。我没有使用 Prefuse 的经验,但我看到了一些用它创建的漂亮的可视化效果。
以下是 JUNG 对这些问题的答案。其中几个((1),(2),(4)在PluggableRendererDemo
中演示:
-
支持(您需要正确的数据模型,出于性能原因,并非所有模型都支持并行边)
支持(同样,您需要正确的数据模型)
支持(见
ImageShaperDemo
)
支持(大多数演示)
支持(见GraphEditorDemo
)
不直接支持,尽管您当然可以动态更改标签并使用 html 呈现复杂标签。
JUNG 的布局算法更适用于一般网络(树等少数例外)。不过,您当然可以构建自己的布局算法,而且很多人已经这样做了。
希望这会有所帮助。
【讨论】:
【参考方案5】:我喜欢@holygeek 的回答。这是我对 Prefuse 的 2(有向和无向边)解决方案的实现:
public class MyRenderFactory implements RendererFactory
private NodeRenderer nodeRenderer = new NodeRenderer();
private EdgeRenderer defaultEdgeRenderer = new EdgeRenderer();
private EdgeRenderer undirectedEdgeRenderer = new EdgeRenderer(EdgeRenderer.EdgeType.LINE, EdgeRenderer.EdgeArrowType.NONE);
public static String directedness = "myEdgeDirectedness";
public enum EdgeDirected
directed, undirected;
public static EdgeDirected fromIsDirected(boolean isDirected)
if (isDirected)
return directed;
return undirected;
@Override
public Renderer getRenderer(VisualItem<?> visualItem)
if (visualItem instanceof EdgeItem)
if (visualItem.get(directedness).equals(PrefuseGraphConverter.EdgeDirected.undirected))
return undirectedEdgeRenderer;
return defaultEdgeRenderer;
return nodeRenderer;
...其他地方,创建图表的地方...
MyRenderFactory.EdgeDirected directedness =
MyRenderFactory.EdgeDirected.fromIsDirected(myEdge.isDirected());
prefuseEdge.set(MyRenderFactory.directedness, directedness);
【讨论】:
以上是关于比较用于绘制网络拓扑的开源 Java 图形绘制框架(JUNG 和 Prefuse)的主要内容,如果未能解决你的问题,请参考以下文章