简体   繁体   English

GraphML 节点着色前缀

[英]GraphML Node Coloring Prefuse

I have a prefuse application that loads GraphML files where the nodes have a "Color" string property.我有一个 prefuse 应用程序,它加载节点具有“Color”字符串属性的 GraphML 文件。 ie. IE。

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

I want to allow a range of predefined colors to be specified, and I don't want to force the program that creates the GraphML to use all of the colors.我想允许指定一系列预定义的 colors,我不想强制创建 GraphML 的程序使用所有 colors。

I thought this would be a simple task (and maybe it is?), but prefuse seems to fight me at every turn.我认为这将是一项简单的任务(也许它是?),但预示似乎无时无刻不在与我作对。 I've come up with two partial solutions, but they both have their issues.我提出了两个部分解决方案,但它们都有各自的问题。 My first approach was to manually add a new Integer property that correlated to the "Color" strings, like so:我的第一种方法是手动添加一个与“颜色”字符串相关的新属性 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;
        }
    }
}

Then, you can use prefuse's default color manager to link these integers to array indices.然后,您可以使用 prefuse 的默认颜色管理器将这些整数链接到数组索引。

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

The biggest issue with this approach (on top of it being inelegant), is that it fails when less than three unique colors are specified by the user.这种方法的最大问题(最重要的是它不够优雅)是当用户指定的唯一 colors 少于三个时它会失败。 If two colors are specified, prefuse uses the first and last elements of the color array.如果指定了两个 colors,则 prefuse 使用颜色数组的第一个和最后一个元素。 If one, the first.如果一个,第一个。 Meh.嗯。

My other solution is to manually set each node's color.我的另一个解决方案是手动设置每个节点的颜色。

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

This works for any number of colors, but randomly messes up.这适用于任意数量的 colors,但会随机出现混乱。 I think that prefuse handles these methods on their own thread, which, for some reason, runs slowly.我认为 prefuse 在它们自己的线程上处理这些方法,由于某种原因,它运行缓慢。 For smaller.networks, I can set a fixed wait time (I haven't found a Thread.join() method to use).对于 smaller.networks,我可以设置一个固定的等待时间(我还没有找到可以使用的 Thread.join() 方法)。 But, this fails hilariously (read: crashes my computer) for large.networks.但是,这对于 large.networks 来说非常失败(阅读:让我的电脑崩溃)。

So, there you have it.所以你有它。 An unnecessarily large time commitment for what should be a trivial task.为本应是微不足道的任务付出不必要的大量时间。 Has someone managed to accomplish this?有人设法做到这一点吗? Is there an easy way?有简单的方法吗? Please tell me I'm overthinking this.请告诉我我想多了。

I know such experiences about prefuse very well:-/我非常了解这种关于 prefuse 的经历:-/

The first approach is on the right way, but specified the wrong data type.第一种方法是正确的方法,但指定了错误的数据类型。 Color is a NOMINAL variable.颜色是NOMINAL变量。

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

The ColorNumber field is not necessary. ColorNumber字段不是必需的。

Your conclusions about the second approach are correct.您对第二种方法的结论是正确的。 prefuse runs its ActionList in a separate thread. prefuse 在一个单独的线程中运行它的ActionList Therefore one should not set visual properties manually.因此,不应手动设置视觉属性。

If more fine-grained code is desired, you can extend DataColorAction .如果需要更细粒度的代码,您可以扩展DataColorAction

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM