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:动态添加节点和边

6)这归结为修改图形并重新绘制它。所以问题变得与5相同)

7) JUNG 和 prefuse 都有多种布局算法。但是当我尝试在 JUNG 和 Prefuse 中使用 FruchtermanReingoldLayout 显示相同的数据集时,我得到了不同的显示。任何想法为什么?尽管 Prefuse 中的大多数布局算法都基于 JUNG 实现,但 Prefuse 中的布局算法似乎显示出比 JUNG 更好的布局(我认为渲染也更好)。Prefuse 布局,例如 ForceDirectedLayout/FruchtermanReingoldLayout 和 CircleLayout 直接映射到星形、圆形、网状拓扑。

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

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

4

5 回答 5

5

我是 JUNG 的创建者和维护者之一,因此请记住以下回复。

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

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

  1. 支持(您需要正确的数据模型,出于性能原因,并非所有模型都支持并行边)
  2. 支持(同样,您需要正确的数据模型)
  3. 支持(见ImageShaperDemo
  4. 支持(大多数演示)
  5. 支持(见GraphEditorDemo
  6. 不直接支持,尽管您当然可以动态更改标签并使用 HTML 呈现复杂标签。
  7. JUNG 的布局算法更适用于一般网络(树等少数例外)。但是,您当然可以构建自己的布局算法,而且很多人已经这样做了。

希望这可以帮助。

于 2011-03-18T18:16:24.603 回答
3

几年前(2007 年?)我使用 prefuse 来可视化呼叫数据记录。我考虑了 prefuse、jung、jgraph 和其他几个,然后选择了 prefuse。起初,我有点难以理解 prefuse,但一旦我熟悉了它,它就真的很容易(扩展)并且使用起来很有趣。我想荣格也可以这样说,但我从未尝试过。

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 author) 确实做得很好。

如果你使用 prefuse 需要注意的事情(这是我在使用 prefuse 时清楚地记得的两个“大拇指”):

1)有一个错误,当缩小时,节点标签没有适当缩小,以至于它溢出节点的边界框,当节点移动时会留下字体绘制伪影,因为渲染器只清除和重绘节点边界内的东西盒子。IIRC 这是由 AWT 字体度量本身的错误引起的。解决方法是在标签和节点边界框​​之间留出足够的边距。

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

大约一个月前(在我写这篇文章的时候)你问了这个问题,我想知道你的决定是什么,如果你继续实施,结果如何。

于 2011-02-10T04:32:19.973 回答
2

我知道您指定了 jung 和 prefuse,但是……我对 TomSawyer 和 yFiles 都有很好的经验。您提出的要求列表对这两个非常基本 - 它们支持更多。

冉。

于 2011-01-12T16:07:11.730 回答
0

我建议也评估JGraph

于 2011-01-13T06:57:29.587 回答
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);
于 2017-03-22T01:07:21.937 回答