比较开源java图形绘制框架(JUNG和Prefuse)绘制网络拓扑

时间:2011-01-12 15:56:00

标签: java graph topology jung prefuse

哪个开源Java图形绘制框架用于具有以下要求的网络图?该图表的节点少于1000个。

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

我评估了JUNG和Prefuse。这是我为每个要求找到的。

1)当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都有多种布局算法。但是当我尝试在JUNG和Prefuse中使用FruchtermanReingoldLayout显示相同的数据集时,我会得到不同的显示。有什么想法吗?虽然Prefuse中的大多数布局算法都是基于JUNG实现的,Prefuse中的布局算法似乎显示出比JUNG更好的布局(渲染也更好)。 PreFuse布局(如ForceDirectedLayout / FruchtermanReingoldLayout和CircleLayout)直接映射到星形,圆形,网格拓扑。

除了这些要求之外,prefuse对表达式和查询语言有很好的支持,但看起来它并不像JUNG那样积极开发。哪一个有更好的可视化?关于哪一个适合以及如何克服缺点的任何建议?

我可以使用其他任何框架吗?

5 个答案:

答案 0 :(得分:5)

我是JUNG的创作者和维护者之一,所以请记住下面的回答。

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

以下是JUNG对这些问题的回答。其中几个((1),(2),(4)在PluggableRendererDemo

中进行了演示
  1. 支持(出于性能原因,您需要正确的数据模型,而不是所有支持并行边缘)
  2. 支持(再次,您需要正确的数据模型)
  3. 支持(请参阅ImageShaperDemo
  4. 支持(大多数演示)
  5. 支持(请参阅GraphEditorDemo
  6. 不直接支持,但您当然可以动态更改标签并使用HTML来呈现复杂标签。
  7. JUNG的布局算法更适用于一般网络(树木等少数例外)。但是,您当然可以构建自己的布局算法,并且许多人已经这样做了。
  8. 希望这有帮助。

答案 1 :(得分:3)

几年前(2007年?)我使用prefuse来显示呼叫数据记录。我考虑了prefuse,jung,jgraph和其他一些人,并选择了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的经验,我强烈推荐它,因为非常好(IMHO)深思熟虑的设计和组件之间的可靠性分离。杰弗里·希尔(prefuse作者)在那里做得很好。

如果你使用prefuse需要注意的事项(这些是我在使用prefuse时生动地记住的两个“痛苦的拇指”):

1)有一个错误,当缩小时,节点标签没有被适当地缩小,使得它溢出节点的边界框,当节点移动时会留下字体绘制工件,因为渲染器只清除并重绘内容节点的边界框。 IIRC这是由AWT字体指标本身的错误引起的。解决方法是在标签和节点边界框​​之间留出足够的边距。

2)扩展内置布局时,您可能会遇到一个或两个“范围问题”,其中您要访问的超类成员被赋予私有属性而不是受保护,因此解决方案是修改库本身或创建一个没有继承的新类(这可能有点痛苦!)。我想你可以对其他一些java库说同样的话。不是每个人都有后见之明的好处吗? :)

自从你在一个月前(在我写这篇文章时)提出这个问题以来,我想知道你的决定是什么,以及如果你继续实施它的结果。

答案 2 :(得分:2)

我知道你指定了jung和prefuse但是...... 我对TomSawyer和yFiles都有很好的经验。您提出的要求清单对于这两个要求非常基础 - 而且它们支持更多。

冉。

答案 3 :(得分:0)

我建议也评估JGraph

答案 4 :(得分:0)

我喜欢@ holygeek的回答。以下是我对2的解决方案(有向和无向边)的实现,对于Prefuse:

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);