Search code examples
javalayoutjungdendrogram

JUNG2 layout problems: resultant graphs end up too wide


I have been working on JUNG2 for a while now, trying to visualize a pretty complicated hierarchy of a set of objects. Unfortunately, this hierarchy is not really like a tree in the sense that:

  1. some nodes will have multiple parents. Furthermore, these parents could be at different branches of the tree.
  2. some nodes might have duplicates (this is has to be allowed, I cant just ignore them)

As of now I am using a SparseGraph; put all nodes in the graph, draw sub/super relationships with directed, and duplicates as undirected edges between nodes. Then following the MinimumSpanningTreeDemo source code, I create a MinimumSpanningTreeForest2 object, and send the Forest to a TreeLayout. Long story short, I get the layouts however they are about 15000 pixels wide! Since I don't use these graphs in an interactive manner but rather as static images, this is simply not feasible for use in reports.

I realized that the node labels take quite a bit of space if there are too many nodes that are side-by-side, so I figured that I could rotate the labels and have them vertical instead. This has failed miserably, I manage to rotate labels using a custom class that extends DefaultVertexLabelRenderer, but when I set rotation to Math.PI/2 then I simply see no labels! So here are my questions:

  1. Is it possible to force the layout to be slimmer? I would like to make something like a dendrogram, which is claimed to be possible using JUNG2. Is this really possible? In that case how?
  2. Is there a miss in my thinking that it should be possible to render the node labels vertically? I tried to change the anchor point in the VertexLabelAsShapeRenderer class but still no joy. Speaking of matter; the connection between Renderers RendererContext and the actual rendered objects is really fuzzy. There are a lot of classes and I'm having hard times figuring out which ones are actually used to render. For instance BasicVertexLabelRenderer seems like it's not used at all by default. Thus the whole positioning of labels is just mystical...

I know that JUNG developers have put hours of hard work into the library and I would hate to sound bitter or unthankful, but I really think there's a long gap between this tutorial and figuring out how the demos are written and how the rendering works.

In any case; here's the bit of my code where the graph is created:

public void visualizeGraph(File saveFolder){

    MinimumSpanningForest2<PHGNode, PHGEdge> prim = new MinimumSpanningForest2<PHGNode, PHGEdge>(
            g,  new DelegateForest<PHGNode, PHGEdge>(), DelegateTree.<PHGNode, PHGEdge>getFactory(),
                new ConstantTransformer(1.0));

    Forest<PHGNode, PHGEdge> tree = prim.getForest();

    Layout<PHGNode, PHGEdge> layout = new TreeLayout<PHGNode, PHGEdge>(tree);
    // custom visualization viewer that allows writing to disk
    final WritingVisualizationViewer<PHGNode, PHGEdge> vv = new WritingVisualizationViewer<PHGNode, PHGEdge>(layout,layout.getSize());

    // this class extends VertexLabelAsShapeRenderer and supplies means of fiddling with label coordinates
    VerticalVertexLabelAsShapeRenderer<PHGNode,PHGEdge> vlasr = 
            new VerticalVertexLabelAsShapeRenderer<PHGNode,PHGEdge>(vv.getRenderContext()); 

    vv.getRenderContext().setVertexLabelTransformer(
            new ChainedTransformer<PHGNode,String>(new Transformer[]{
                    new ToStringLabeller<PHGEdge>(),new Transformer<String,String>() {
                            public String transform(String input) { return input;       }}})); 

    //  Change the background of node labels so that they appear transparent
    Transformer<PHGNode,Paint> vertexPaint = new Transformer<PHGNode,Paint>() {
        public Paint transform(PHGNode n) { return vv.getBackground();  }
    };

        // extends DefaultVertexLabelRendeder to provide rotation of labels
    VerticalVertexLabelRenderer vvlr = new VerticalVertexLabelRenderer();
    vv.getRenderContext().setVertexLabelRenderer(vvlr); 

    vv.getRenderContext().setVertexFontTransformer(new VertexFontTransformer<PathwayHierarchyGraph.PHGNode>()); 
    vv.getRenderContext().setVertexShapeTransformer(vlasr); 
    vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
    vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.BentLine<PHGNode, PHGEdge>()); 
    vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);


    //printGraphStats(tree);
    vv.writeToDisk(saveFolder,"hierarchyTree.png");


}

Solution

  • To answer your questions:

    (1) JUNG doesn't have a dendrogram layout. I, too, would be interested in seeing what the commenter on the linked question did to use JUNG to generate a dendrogram. However, you can specify what the x-separation between siblings is (and what the y-separation between parents and children is).

    (2) I didn't write most of the JUNG visualization code, so I'd have to dig into it. Offhand I'd say that AFAIK there is probably no direct support for rotating vertex labels (no one's ever asked for it that I recall) but what you're trying sounds plausible and I don't know of any reason why setting the angle to pi/2 should cause it to fail. I'd look at the console trace, though; when that's happening there's almost certainly some exceptions being thrown.

    As a practical solution, you might try to render a part of the vertex label and use hover text to display the rest.

    Speaking as one of the creators and primary maintainers of JUNG, I would like to have more time to devote to both development and documentation. Anyone that wants to help out should ping me, I'd be happy to talk about what you can do. :)