我有一个预先安装的应用程序,可以加载GraphML文件,其中节点具有“颜色”字符串属性。即。

<node id="1">
  <data key="Color">Green</data>
<node>


我想允许指定一系列预定义的颜色,并且我不想强制创建GraphML的程序使用所有颜色。

我以为这将是一个简单的任务(也许是吗?),但似乎每时每刻都在争吵。我提出了两个部分解决方案,但是它们都有问题。我的第一种方法是手动添加与“ Color”字符串相关的新Integer属性,如下所示:

// Add new property to Graph g
g.addColumn("ColorNumber", int.class);

// Add property to each node
Iterator<Node> it = g.nodes();
while(it.hasNext()) {
    Node n = it.next();
    String type = n.getString("Color");
    // Compare to an array of accepted types
    for(int i=0; i < colorMap.length; i++) {
        if(type.equalsIgnoreCase(colorMap[i])) {
            n.setInt("ColorNumber", i);
            break;
        }
    }
}


然后,您可以使用prefuse的默认颜色管理器将这些整数链接到数组索引。

draw.add(new DataColorAction("graph.nodes", "ColorNumber", Constants.NUMERICAL, VisualItem.FILLCOLOR, fillArray));


这种方法的最大问题(最重要的是,它不够雅致)是,当用户指定的唯一颜色少于三种时,它将失败。如果指定了两种颜色,则prefuse使用颜色数组的第一个和最后一个元素。如果一个,则第一。嗯

我的另一个解决方案是手动设置每个节点的颜色。

// Iterate over VisualItems in Visualization vis
Iterator<VisualItem> v_it = vis.items("graph.nodes");
while(v_it.hasNext()) {
    VisualItem item = v_it.next();
    String type = item.getString("Color");
    for(int i=0; i < typeMap.length; i++) {
        if(type.equalsIgnoreCase(typeMap[i])) {
            item.setFillColor(fill[i]);
            item.setEndFillColor(fill[i]);
            break;
        }
    }
}
vis.repaint();


这适用于任何数量的颜色,但会造成混乱。我认为prefuse在它们自己的线程上处理这些方法,由于某种原因,它们运行缓慢。对于较小的网络,我可以设置固定的等待时间(我尚未找到要使用的Thread.join()方法)。但是,对于大型网络,这很可笑(阅读:使我的计算机崩溃)。

所以你有它。不必要的大量时间投入,这应该是一件微不足道的任务。有人设法做到这一点吗?有没有简单的方法?请告诉我,我想得太多了。

最佳答案

我非常了解这种有关预灌输的经验:-/

第一种方法是正确的,但是指定了错误的数据类型。颜色是NOMINAL变量。

DataColorAction color = new DataColorAction("graph.nodes", "Color",
    Constants.NOMINAL, VisualItem.FILLCOLOR, fillArray);


ColorNumber字段不是必需的。

您对第二种方法的结论是正确的。 prefuse在单独的线程中运行其ActionList。因此,不应手动设置视觉属性。

如果需要更多细粒度的代码,则可以扩展DataColorAction

关于java - GraphML节点着色预涂,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10019329/

10-09 22:44