图表可视化

3

我有一个简单的程序,模拟分布式环境。我想使用GraphStream库来可视化处理器的行为。每个处理器都是一个线程,它们进行一些计算,但并不总是这样,只有在我设置switch变量时才会进行。

while(running){
  if(switch)
    computate();
}

我编写了一个类,它接收处理器列表并准备图形可视化。这个类有一个专门用于此任务的函数。

  public void adjustBFSGraph2(){
    for(Edge e: this.g.getEdgeSet())
    {
        e.clearAttributes();
    }
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for(Processor p : processorList)
    {
        p.getNode().setAttribute("ui.label", "Pid" +" " + p.getPID() +" "+"Dist: " + p.getFieldValue("bfs") + " " + "Parent" + " " + p.getFieldValue("parent"));
        if(!p.getFieldValue("parent").equals("-1"))
        {
            Edge e = p.getNode().getEdgeBetween(p.getFieldValue("parent"));
            if(e != null)
            {
                e.setAttribute("ui.color", p.getColor());
                e.setAttribute("ui.label", "added" + p.getPID());

            }
        }
    }
}

我的问题是,我只在眨眼的瞬间看到边缘上的颜色,然后颜色就消失了。看起来它在同一个循环中添加属性“ui.color”并将其删除,但这可能吗?

更新:我已经编辑了我的代码,现在我可以在第一次循环之后按thread.sleep()指定的时间看到边缘,但是我不明白为什么在清除所有属性之后我实际上可以看到它们。

这里是我调用函数的方式:

    while(true)
            {   i++;
//if any processor is not runing
                boolean aux = false;
                while(!aux) {
                    for (Processor proc : s.processorList) {
                        aux = aux || proc.isEnabled();
                    }
                    aux = !aux;
                }
                s.gp.adjustBFSGraph();
                Thread.sleep(5000);
                for(Processor proc: s.processorList)
                {
                    proc.enable();
                }
            }

当adjust函数内的Thread.sleep()时间小于100毫秒时,屏幕将重新开始闪烁。
因为我的操作可能有点不太清楚,所以我创建了一个较小的示例。
这相当于我的处理器类。
    public class SomeObjectWithNode {
    public Node n;
    public Color c;
    public SomeObjectWithNode(Node n)
    {
        Random rand = new Random();
        float r = rand.nextFloat();
        float g = rand.nextFloat();
        float b = rand.nextFloat();
        Color randomColor = new Color(r, g, b);
        c = randomColor;
        this.n = n;
    }

}

这是一个能够改变图形样式/绘制的类。
    public class TestDraw {
    Vector<SomeObjectWithNode> n;
    Graph g;
    public TestDraw(Vector<SomeObjectWithNode> k, Graph g)
    {
        this.g= g;
        this.n = k;
    }
    public void adjust()
    {
        Random rand = new Random();
        for(Edge e: g.getEdgeSet())
        {
            e.clearAttributes();
        }
        for(SomeObjectWithNode k: n)
        {
            k.n.addAttribute("ui.color", k.c);
            for(Edge e: k.n.getEdgeSet())
            {
                float r = rand.nextFloat();
                float g = rand.nextFloat();
                float b = rand.nextFloat();
                Color randomColor = new Color(r, g, b);
                e.addAttribute("ui.color", randomColor);
            }
        }
    }
}

这里是主类

public class TestGs {

        public static void main(String[] args) {
            Node lastNode;
            TestDraw t;
            Vector<SomeObjectWithNode> a = new Vector<SomeObjectWithNode>();
            System.setProperty("gs.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
            Graph g = new SingleGraph("test1");
            g.display();
            g.addAttribute("ui.stylesheet", "node { fill-mode: dyn-plain; size: 10px;} edge { fill-mode: dyn-plain; size: 2px;}");
            a.add(new SomeObjectWithNode(g.addNode(Integer.toString(0))));
            lastNode = g.getNode("0");
            for(int i = 1; i < 10; i++)
            {
                a.add(new SomeObjectWithNode(g.addNode(Integer.toString(i))));
                g.addEdge(Integer.toString(i-1).concat(Integer.toString(i)), a.get(i).n, lastNode);
                lastNode = a.get(i).n;
            }
            t = new TestDraw(a,g);
            while(true)
            {
                t.adjust();
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }

    }

当我运行示例时,我们可以看到图形仅在眨眼间显示颜色,而不是在Thread.sleep()中显示它的时间。

你有什么意见吗? - Vladislav Kysliy
我已经更正了我的回答,希望这就是你想要的。 - Vladislav Kysliy
1个回答

1
主要问题在于adjust()方法中的e.clearAttributes();。您不仅删除了所有属性,而是只能使用e.setAttribute("ui.color", randomColor);来替代e.addAttribute("ui.color", randomColor);,并且完全删除带有e.clearAttributes()的块(请参见原始example第2个)。

我已根据我的评论修改了您的代码,并在gist.github上共享了它。现在它每2秒更改一次颜色。

PS:现在关于闪烁的原因。我对GraphStream源代码进行了简短的调查(很多Java代码,抱歉)。AbstractElement.java(仅有趣的方法):
    public void clearAttributes() {
            if (attributes != null) {
                for (Map.Entry<String, Object> entry : attributes.entrySet())
                    attributeChanged(AttributeChangeEvent.REMOVE, entry.getKey(),
                            entry.getValue(), null);

                attributes.clear();
            }
        }
...
    public void setAttribute(String attribute, Object... values) {
        addAttribute(attribute, values);
    }
...
    public void addAttribute(String attribute, Object... values) {
        if (attributes == null)
            attributes = new HashMap<String, Object>(1);

        Object oldValue;
        Object value;
        if (values.length == 0)
            value = true;
        else if (values.length == 1)
            value = values[0];
        else
            value = values;

        AttributeChangeEvent event = AttributeChangeEvent.ADD;
        if (attributes.containsKey(attribute)) // In case the value is null,
            event = AttributeChangeEvent.CHANGE; // but the attribute exists.

        oldValue = attributes.put(attribute, value);
        attributeChanged(event, attribute, oldValue, value);
    }
...

正如您所看到的,setAttribute和addAttribute非常相似。现在在GraphicElement.java中实现attributeChanged()函数:
@Override
    protected void attributeChanged(AttributeChangeEvent event,
            String attribute, Object oldValue, Object newValue) {
        if (event == AttributeChangeEvent.ADD
                || event == AttributeChangeEvent.CHANGE) {
            if (attribute.charAt(0) == 'u' && attribute.charAt(1) == 'i') {
                if (attribute.equals("ui.class")) {
                    mygraph.styleGroups.checkElementStyleGroup(this);
                    // mygraph.styleGroups.removeElement( tis );
                    // mygraph.styleGroups.addElement( this );
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.label")) {
                    label = StyleConstants.convertLabel(newValue);
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.style")) {
                    // Cascade the new style in the style sheet.

                    if (newValue instanceof String) {
                        try {
                            mygraph.styleSheet.parseStyleFromString(
                                    new Selector(getSelectorType(), getId(),
                                            null), (String) newValue);
                        } catch (Exception e) {
                            logger.log(Level.WARNING, String.format("Error while parsing style for %S '%s' :", getSelectorType(), getId()), e);
                        }
                        mygraph.graphChanged = true;
                    } else {
                        logger.warning("Unknown value for style [" + newValue + "].");
                    }
                } else if (attribute.equals("ui.hide")) {
                    hidden = true;
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.clicked")) {
                    style.pushEventFor(this, "clicked");
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.selected")) {
                    style.pushEventFor(this, "selected");
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.color")) {
                    style.pushElementAsDynamic(this);
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.size")) {
                    style.pushElementAsDynamic(this);
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.icon")) {
                    mygraph.graphChanged = true;
                }
                // else if( attribute.equals( "ui.state" ) )
                // {
                // if( newValue == null )
                // state = null;
                // else if( newValue instanceof String )
                // state = (String) newValue;
                // }
            } else if (attribute.equals("label")) {
                label = StyleConstants.convertLabel(newValue);
                mygraph.graphChanged = true;
            }
        } else // REMOVE
        {
            if (attribute.charAt(0) == 'u' && attribute.charAt(1) == 'i') {
                if (attribute.equals("ui.class")) {
                    Object o = attributes.remove("ui.class"); // Not yet removed
                                                                // at
                                                                // this point !
                    mygraph.styleGroups.checkElementStyleGroup(this);
                    attributes.put("ui.class", o);
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.label")) {
                    label = "";
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.hide")) {
                    hidden = false;
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.clicked")) {
                    style.popEventFor(this, "clicked");
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.selected")) {
                    style.popEventFor(this, "selected");
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.color")) {
                    style.popElementAsDynamic(this);
                    mygraph.graphChanged = true;
                } else if (attribute.equals("ui.size")) {
                    style.popElementAsDynamic(this);
                    mygraph.graphChanged = true;
                }
            } else if (attribute.equals("label")) {
                label = "";
                mygraph.graphChanged = true;
            }
        }
    }

注意: 当您清除属性时,动态样式将通过popElementAsDynamic/pushElementAsDynamic方法添加/删除。在StyleGroup.java中实现这些方法:

     /**
     * Indicate the element has dynamic values and thus cannot be drawn in bulk
     * operations. Called by the GraphicElement.
     * 
     * @param element
     *            The element.
     */
    protected void pushElementAsDynamic(Element element) {
        if (dynamicOnes == null)
            dynamicOnes = new HashSet<Element>();

        dynamicOnes.add(element);
    }

    /**
     * Indicate the element has no more dynamic values and can be drawn in bulk
     * operations. Called by the GraphicElement.
     * 
     * @param element
     *            The element.
     */
    protected void popElementAsDynamic(Element element) {
        dynamicOnes.remove(element);

        if (dynamicOnes.isEmpty())
            dynamicOnes = null;
    }

当我们使用add/setAttribute时,我们只向现有的哈希映射中添加新元素。当我们使用clearAttributes时,我们为dynamicOnes创建了新的HashMap实例。可能在这种情况下,我们存在同步问题,这就是闪烁的原因。


我接受这个事实,但并不清楚为何先移除属性再添加会导致闪烁效果。 - whd
@whd 添加了 PS 部分,请检查。 - Vladislav Kysliy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接