2012-04-04 61 views
1

我有一个prefuse应用程序,用于加载GraphML文件,其中节点具有“Color”字符串属性。即。GraphML节点着色Prefuse

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

我想允许指定一系列预定义的颜色,我不希望强制创建该GraphML使用所有的颜色方案。

我认为这将是一个简单的任务(也许它是?),但prefuse似乎在任何时候都打我。我已经提出了两个部分解决方案,但他们都有他们的问题。我的第一种方法是手动添加到“颜色”的字符串相关的新的整数属性,就像这样:

// 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()方法)。但是,对于大型网络来说,这会失败(阅读:崩溃我的电脑)。

所以,你有它。不必要的大量时间承担这项微不足道的任务。有人设法完成这个?有没有简单的方法?请告诉我,我正在推翻这一点。

回答

1

我知道prefuse这样的经历非常好: -/

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

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

ColorNumber字段是没有必要的。

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

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

+0

扩展DataColorAction是我最终选择的解决方案。另外,我需要更好地了解StackOverflow问题。 – PattimusPrime 2012-04-27 22:49:52