Question

I guess my prolem is best described with the following picture.

enter image description here

How can I tell JUNG to place everything in the visible area?

This is my VertexShapeTransformer (Scala)

vv.getRenderContext().setVertexShapeTransformer(
new org.apache.commons.collections15.Transformer[String,java.awt.Shape]() {
  def transform(label: String): java.awt.Shape = {
    val longest_name = label.length
    val width = longest_name * 10.0 // 12.0 is approx size of letter
    val circle = new java.awt.geom.Ellipse2D.Double(-(width/2), -12.5, width, 25);
    circle
  }
})

When I remove it, the small default circles fit in the window but the vertex label is still not in the window.

Was it helpful?

Solution

I found a solution. For vv: VisualizationViewer[String, String], the following function updates the layouter algorithm (scala code). It calls the relaxer on the layouter (if it supports relaxing) and then rearranges the vertices. The layout.setLocation function is called for every vertex, to make sure that it is in the printable screen area.

  /**
   * change the graph layouter
   * with fancy animation
   */
  def changeJUNGLayout(layout: jung.algorithms.layout.AbstractLayout[String, String]): Unit = 
  {

      layout.setSize(vv.getSize())

      assert(vv.getModel().getRelaxer() eq null)
      if(layout.isInstanceOf[edu.uci.ics.jung.algorithms.util.IterativeContext]){
          val relaxer: jung.algorithms.layout.util.Relaxer
            = new jung.algorithms.layout.util.VisRunner(
                layout.asInstanceOf[edu.uci.ics.jung.algorithms.util.IterativeContext])
          relaxer.stop()
          relaxer.prerelax()
      }

      {
          import collection.JavaConversions._
          val vs : Iterable[String] = layout.getGraph().getVertices()
          for (v <- vs){
              //println(v+" "+layout.getX(v)+" "+layout.getY(v))
              val minX = v.length()*5.0
              val maxX = vv.getSize().getWidth() - minX
              val X = layout.getX(v)
              val newX = if (X < minX) minX else if (X > maxX) maxX else X
              val minY = 12.5
              val maxY = vv.getSize().getHeight() - minY
              val Y = layout.getY(v)
              val newY = if (Y < minY) minY else if (Y > maxY) maxY else Y
              layout.setLocation(v, newX, newY)
          }
      }

      val staticLayout: jung.algorithms.layout.Layout[String, String] =
        new jung.algorithms.layout.StaticLayout[String, String](jung_graph, layout)

      val lt: jung.visualization.layout.LayoutTransition[String,String] =
        new jung.visualization.layout.LayoutTransition[String,String](vv, vv.getGraphLayout(),
            staticLayout)
      val animator = new jung.visualization.util.Animator(lt);
      animator.start();


      vv.repaint();
  }

OTHER TIPS

Your labels (and vertices) are being cut off because JUNG's layout algorithms do not take into account that vertices can be > than radius 1 (large ellipses in your case). So the middle of the vertex is actually placed inside the view screen, but the label and the shell of the ellipse are not.

This leaves you two options:

  1. Write your own layout to take size into account.

    This option isn't as difficult as it sounds. You can simply modify one of the force directed algorithms to take size into account.

  2. Layout your graph and them zoom out a wee bit.

    ScalingControl scaler = new CrossoverScalingControl();
    scaler.scale(viewer, 1 / 1.1f, viewer.getCenter());
    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top