Prefuse example graph partly outside of JPanel

2019-01-28 05:31发布

问题:

I want to use Prefuse to visualise a graph. I followed their tutorial and tried their sample application. Its sourcecode can be found here

However, even if I simply copy the full code, the resulting graph does not look as displayed in the tutorial. It is only half visible, stuck in JPanel's upper left corner. Some parts of it are missing becuase they would have to be displayed outside the panel. I tried with some graphs of my own, but I keep running into the same phenomenon.

I suppose this is not expected behaviour, but I have no idea where to hunt for the problem. I don't know if this is a problem with Swing(x) or prefuse or ... ?

Update: This is the revised code. I did not change much from the example, only added what trashgod suggested.

package visualise;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import prefuse.Constants;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.DataColorAction;
import prefuse.action.layout.graph.ForceDirectedLayout;
import prefuse.activity.Activity;
import prefuse.controls.DragControl;
import prefuse.controls.PanControl;
import prefuse.controls.ZoomControl;
import prefuse.data.Graph;
import prefuse.data.io.DataIOException;
import prefuse.data.io.GraphMLReader;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.LabelRenderer;
import prefuse.util.ColorLib;
import prefuse.visual.VisualItem;

public class PrefuseExample {

public static void main(String[] argv) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
             // -- 1. load the data ------------------------------------------------

            // load the socialnet.xml file. it is assumed that the file can be
            // found at the root of the java classpath
            Graph graph = null;
            try {
                graph = new GraphMLReader().readGraph("../../resources/visualisation/prefuse/Prefuse-master/data/socialnet.xml");
            } catch ( DataIOException e ) {
                e.printStackTrace();
                System.err.println("Error loading graph. Exiting...");
                System.exit(1);
            }


            // -- 2. the visualization --------------------------------------------

            // add the graph to the visualization as the data group "graph"
            // nodes and edges are accessible as "graph.nodes" and "graph.edges"
            Visualization vis = new Visualization();
            vis.add("graph", graph);
            vis.setInteractive("graph.edges", null, false);

            // -- 3. the renderers and renderer factory ---------------------------

            // draw the "name" label for NodeItems
            LabelRenderer r = new LabelRenderer("name");
            r.setRoundedCorner(8, 8); // round the corners

            // create a new default renderer factory
            // return our name label renderer as the default for all non-EdgeItems
            // includes straight line edges for EdgeItems by default
            vis.setRendererFactory(new DefaultRendererFactory(r));


            // -- 4. the processing actions ---------------------------------------

            // create our nominal color palette
            // pink for females, baby blue for males
            int[] palette = new int[] {
                ColorLib.rgb(255,180,180), ColorLib.rgb(190,190,255)
            };
            // map nominal data values to colors using our provided palette
            DataColorAction fill = new DataColorAction("graph.nodes", "gender",
                    Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
            // use black for node text
            ColorAction text = new ColorAction("graph.nodes",
                    VisualItem.TEXTCOLOR, ColorLib.gray(0));
            // use light grey for edges
            ColorAction edges = new ColorAction("graph.edges",
                    VisualItem.STROKECOLOR, ColorLib.gray(200));

            // create an action list containing all color assignments
            ActionList color = new ActionList();
            color.add(fill);
            color.add(text);
            color.add(edges);

            // create an action list with an animated layout
            ActionList layout = new ActionList(Activity.INFINITY);
            layout.add(new ForceDirectedLayout("graph"));
            layout.add(new RepaintAction());

            // add the actions to the visualization
            vis.putAction("color", color);
            vis.putAction("layout", layout);


            // -- 5. the display and interactive controls -------------------------

            Display d = new Display(vis);
            d.setSize(720, 500); // set display size
            // drag individual items around
            d.addControlListener(new DragControl());
            // pan with left-click drag on background
            d.addControlListener(new PanControl()); 
            // zoom with right-click drag
            d.addControlListener(new ZoomControl());

            // -- 6. launch the visualization -------------------------------------

            // create a new window to hold the visualization
            JFrame frame = new JFrame("prefuse example");
            // ensure application exits when window is closed
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(d);
            frame.pack();           // layout components in window
            frame.setVisible(true); // show the window

            // assign the colors
            vis.run("color");
            // start up the animated layout
            vis.run("layout");
        }
    });
}

}

回答1:

I'm new to Prefuse, but a number of common errors can contribute to the observed problem. Looking at the example,

  • As discussed here, don't use setSize() on the Display when you really mean to override getPreferredSize().

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread‌​.

  • The initial clustering is an artifact of the graph's origin falling on the top-left corner of the Display component at the point (0, 0). Having chosen a preferred size, one can pan() to the center.

private static final int W = 640;
private static final int H = 480;
…
Display d = new Display(vis) {

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(W, H);
    }
};
d.pan(W / 2, H / 2);