JUNG: adding children to DelegateTree after drawing it

I am developing a Java application and I am using the JUNG library. In my application, I first create DelegateTree

and draw it on the screen:

public static GraphZoomScrollPane generateTree(Tree tree,
    GraphicalUserInterface gui) {

    /* Create a new tree */
    edu.uci.ics.jung.graph.Tree<Node, Edge> graphTree = new DelegateTree<Node, Edge>();

    /* Add all nodes and vertices to the tree */
    graphTree.addVertex(tree.getRoot());
    addChildren(tree.getRoot(), graphTree);

    /* Create the visualization */
    TreeLayout<Node, Edge> treeLayout = new TreeLayout<Node, Edge>(graphTree);
    VisualizationViewer<Node, Edge> vv = new VisualizationViewer<Node, Edge>(treeLayout);
    vv.setBackground(Color.WHITE);
    vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>());
    vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<Node, Edge>());
    vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
    vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S);

    vv.addGraphMouseListener(new ClickNode(gui, vv));
    final DefaultModalGraphMouse<Node, Edge> graphMouse = new DefaultModalGraphMouse<Node, Edge>();
    graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
    vv.setGraphMouse(graphMouse);

    return new GraphZoomScrollPane(vv);
}

      

After that, the user can add new children to the leaves of my tree. But when I just do

graphTree.addEdge(edge, parent, child);

      

and then redraw VisualizationViewer

, the visualization has lost its "Tree" structure. It just adds the child somewhere above the parent and all the other children of that new child right on top of it.

Is there a better way to dynamically add children to the leaves of my tree? Or do I need to use something else to redraw instead of just vv.repaint()

?

Any help would be really appreciated.

An example of what's going on:

http://www.dylankiss.be/JUNGExample.PNG

Starting from just the root (OUTLOOK), after adding three children (Leaf, Leaf, Leaf) with different edges (sunny, cloudy, rainy), they just appear on top of each other.

EDIT . This is the method addChildren()

.

private static void addChildren(Node node, edu.uci.ics.jung.graph.Tree<Node, Edge> tree) {
    for (int i = 0; i < node.getChildren().size(); i++) {
        tree.addEdge(new Edge(node.getChildren().get(i).getParentValue()), node, node.getChildren().get(i));
        addChildren(node.getChildren().get(i), tree);
    }
}

      

EDIT 2 . This is part of the AWT ActionListener where I add new children to the tree.

while (there are still edges to be added) {
    value = name of new edge;
    child = new Node(this.m_node, value);
    this.m_node.addChild(child);
    graphTree.addEdge(new Edge(value), this.m_node, child);
}

      

+3


source to share


1 answer


Posting the method that is responsible for adding new edges will help here:

But at first glance it seems that you are adding 3 different edges between the same two nodes (OUTLOOK and Leaf). I assume you are doing this (or the equivalent with Node and Edge instances):

graphTree.addChild("sunny", "OUTLOOK", "Leaf");
graphTree.addChild("overcast", "OUTLOOK", "Leaf");
graphTree.addChild("rainy", "OUTLOOK", "Leaf");

      

In this case, since JUNG plots maintain unity of nodes, you only get two nodes and 3 different edges between them. When JUNG tries to display this graph, you will get two nodes and 3 overlapping edges, since you were using EdgeShape.Line.

If the original goal was to fit 3 different edges between two nodes, try using different edge shapes to avoid overlap and get better rendering, for example. EdgeShape.BentLine or such.

If you want 3 different nodes, you will need to use 3 different names or 3 different Node instances that are not equal.

Good luck :)



EDIT

After your comment, I took a look at the TreeLayout sources and there is a small issue that makes it impossible to dynamically update the layout.

To fix the problem , use this class:

import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import java.awt.Point;
import java.util.Collection;

import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.util.TreeUtils;

public class DynamicTreeLayout<V, E>
    extends TreeLayout<V, E>
{
public DynamicTreeLayout(Forest<V, E> g) {
    this(g, DEFAULT_DISTX, DEFAULT_DISTY);
}

public DynamicTreeLayout(Forest<V, E> g, int distx) {
    this(g, distx, DEFAULT_DISTY);
}

public DynamicTreeLayout(Forest<V, E> g, int distx, int disty) {
    super(g, distx, disty);
}

protected void buildTree() {
    alreadyDone.clear(); // This was missing and prevented the layout to update positions

    this.m_currentPoint = new Point(20, 20);
    Collection<V> roots = TreeUtils.getRoots(graph);
    if (roots.size() > 0 && graph != null) {
        calculateDimensionX(roots);
        for (V v : roots) {
            calculateDimensionX(v);
            m_currentPoint.x += this.basePositions.get(v) / 2 + this.distX;
            buildTree(v, this.m_currentPoint.x);
        }
    }
}

private int calculateDimensionX(V v) {
    int localSize = 0;
    int childrenNum = graph.getSuccessors(v).size();

    if (childrenNum != 0) {
        for (V element : graph.getSuccessors(v)) {
            localSize += calculateDimensionX(element) + distX;
        }
    }
    localSize = Math.max(0, localSize - distX);
    basePositions.put(v, localSize);

    return localSize;
}

private int calculateDimensionX(Collection<V> roots) {
    int localSize = 0;
    for (V v : roots) {
        int childrenNum = graph.getSuccessors(v).size();

        if (childrenNum != 0) {
            for (V element : graph.getSuccessors(v)) {
                localSize += calculateDimensionX(element) + distX;
            }
        }
        localSize = Math.max(0, localSize - distX);
        basePositions.put(v, localSize);
    }

    return localSize;
}
}

      

You also need to add the following if you want the layout to be updated and the viewer repainted for each modification of your graph:

layout.setGraph(g);
vv.repaint();

      

+3


source







All Articles