比较开源的Java图形绘制框架(JUNG和Prefuse)用于绘制网络拓扑结构。

27

针对以下网络图的要求,您应该选择哪个开源Java图形绘制框架?该图形将拥有少于1000个节点:

1)具有平行边
2)在单个图形中有定向和无定向边
3)节点用图像表示
4)用户可以与节点和边进行交互
5)动态添加/删除节点和边
6)节点和边可以有多个标签,不同级别的标签可以由用户关闭/打开(例如在图层中绘制并关闭/打开图层)
7)不同的布局算法来显示星形、环形、网状拓扑结构

我评估了JUNG和Prefuse,以下是我对每个要求的发现:

1)Prefuse不能显示平行边,而JUNG支持它。能否通过更改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都有多种布局算法。但是当我尝试使用FruchtermanReingoldLayout在JUNG和Prefuse中显示相同的数据集时,我得到了不同的显示结果。有什么想法?尽管Prefuse中的大多数布局算法都基于JUNG实现,但某种程度上Prefuse中的布局算法似乎比JUNG展现出更好的布局(我认为呈现效果也更好)。Prefuse的布局,如ForceDirectedLayout/FruchtermanReingoldLayout和CircleLayout,直接映射到星形、圆形和网格拓扑。

除此之外,Prefuse对表达式和查询语言有很好的支持,但看起来不像JUNG那样积极开发。哪一个可视化效果更好?有没有关于哪一个更适合以及如何克服缺点的建议?

还有其他可以使用的框架吗?


7
我赞同这个观点。我喜欢你做了很多前期工作,评估了两种可能性并呈现了你的发现。这里有很多价值,不仅仅是回答你的问题,对其他人也非常有用。这可能是我在这里看到的最好的新用户“第一个问题”。如果可以的话,我会给更高的评分。 - duffymo
5个回答

5

我是JUNG的创建者和维护者之一,所以请在以下回答中记住这一点。

首先,我应该说Prefuse的作者是我的朋友的朋友(是的,我们见过面),他做得很好。我没有使用Prefuse的经验,但我看到了一些用它创建的美丽可视化。

以下是针对JUNG的这些问题的答案。其中一些问题((1)、(2)、(4))在 PluggableRendererDemo 中演示:

  1. 支持(您需要正确的数据模型,不是所有模型都支持并行边缘以提高性能)
  2. 支持(同样,您需要正确的数据模型)
  3. 支持(请参见 ImageShaperDemo
  4. 支持(大多数演示文稿)
  5. 支持(请参见 GraphEditorDemo
  6. 不直接支持,但您可以动态更改标签并使用HTML呈现复杂的标签。
  7. JUNG的布局算法更适用于一般网络(除了一些树等特殊情况)。但是,您肯定可以构建自己的布局算法,许多人已经这样做了。

希望这可以帮到您。


3
几年前(2007年?)我使用prefuse来可视化通话数据记录。我考虑了prefuse、jung、jgraph等几个选择,最终选择了prefuse。一开始理解prefuse有点困难,但一旦熟悉了它,它就非常容易(扩展)和有趣。我想JUNG也是一样的,但我从未尝试过。
1)在prefuse中,为绘制平行边添加自定义渲染器非常容易-您可以子类化默认EdgeRenderer并覆盖render()方法。不需要进行“基本数据级别更改”。如果您希望将其视为MVC内容,则所有这些都在视图部分中。
2)这实际上根本不是问题。有多种方法可以做到这一点:1)您可以有两个渲染器-一个用于绘制有向边,另一个用于绘制无向边,并且它们将正常工作,并适当地分组边缘。 2)添加一个标志(在prefuse语言中,在支持表元组中添加布尔列)以指示边是否定向,并根据该标志在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,请注意以下问题(这是我在使用prefuse时非常明显的两个问题):
1)有一个错误,在缩小视图时,节点标签无法适当地缩小以致于溢出节点的边界框,因此当节点移动时会留下字体绘制伪影。这是由于AWT字体度量本身存在错误引起的。解决方法是在标签和节点边界框之间留出充足的空白区域。
2)当扩展内置布局时,您可能会遇到一两个"作用域问题",其中超类的成员被赋予了私有属性而不是受保护的属性,因此解决方案是修改库本身或创建一个新类而不继承(这可能有点麻烦!)。我想对于其他一些Java库也可以这样说。并非每个人都拥有先见之明,对吧?:)
因为你大约一个月前(在我写这篇文章的时候)问了这个问题,所以我想知道你的决定是什么,如果你继续实现,它如何为你带来?

2

我知道你提到了jung和prefuse,但是我以前使用过TomSawyer和yFiles,它们都很好用。你提出的要求对于这两个工具来说非常基础,它们支持更多功能。

Ran。


0
我建议你也评估一下JGraph

0

我喜欢@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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接