edu.uci.ics.jung.samples.SpatialLensLargeGraphDemo.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.samples.SpatialLensLargeGraphDemo.java

Source

/*
 * Copyright (c) 2003, The JUNG Authors
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 *
 */
package edu.uci.ics.jung.samples;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import com.google.common.graph.MutableNetwork;
import com.google.common.graph.Network;
import com.google.common.graph.NetworkBuilder;
import edu.uci.ics.jung.layout.algorithms.FRBHVisitorLayoutAlgorithm;
import edu.uci.ics.jung.layout.algorithms.LayoutAlgorithm;
import edu.uci.ics.jung.layout.model.LayoutModel;
import edu.uci.ics.jung.visualization.BaseVisualizationModel;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.MultiLayerTransformer.Layer;
import edu.uci.ics.jung.visualization.VisualizationModel;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.LensMagnificationGraphMousePlugin;
import edu.uci.ics.jung.visualization.control.ModalLensGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.transform.HyperbolicTransformer;
import edu.uci.ics.jung.visualization.transform.LayoutLensSupport;
import edu.uci.ics.jung.visualization.transform.Lens;
import edu.uci.ics.jung.visualization.transform.LensSupport;
import edu.uci.ics.jung.visualization.transform.MagnifyTransformer;
import edu.uci.ics.jung.visualization.transform.shape.HyperbolicShapeTransformer;
import edu.uci.ics.jung.visualization.transform.shape.MagnifyShapeTransformer;
import edu.uci.ics.jung.visualization.transform.shape.ViewLensSupport;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import javax.swing.*;
import javax.swing.plaf.basic.BasicLabelUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Demonstrates the use of <code>HyperbolicTransform</code> and <code>MagnifyTransform</code>
 * applied to either the model (graph layout) or the view (VisualizationViewer) The hyperbolic
 * transform is applied in an elliptical lens that affects that part of the visualization.
 *
 * @author Tom Nelson
 */
@SuppressWarnings("serial")
public class SpatialLensLargeGraphDemo extends JPanel {

    private static final Logger log = LoggerFactory.getLogger(SpatialLensLargeGraphDemo.class);
    /** the graph */
    Network<String, Number> graph;

    LayoutAlgorithm<String> graphLayoutAlgorithm;

    /** the visual component and renderer for the graph */
    VisualizationViewer<String, Number> vv;

    /** provides a Hyperbolic lens for the view */
    LensSupport hyperbolicViewSupport;
    /** provides a magnification lens for the view */
    LensSupport magnifyViewSupport;

    /** provides a Hyperbolic lens for the model */
    LensSupport hyperbolicLayoutSupport;
    /** provides a magnification lens for the model */
    LensSupport magnifyLayoutSupport;

    ScalingControl scaler;

    public SpatialLensLargeGraphDemo() {
        setLayout(new BorderLayout());
        graph = SpatialLensLargeGraphDemo.getGraph();

        graphLayoutAlgorithm = new FRBHVisitorLayoutAlgorithm<>();

        Dimension preferredSize = new Dimension(800, 800);
        Dimension viewPreferredSize = new Dimension(800, 800);

        final VisualizationModel<String, Number> visualizationModel = new BaseVisualizationModel<>(graph,
                graphLayoutAlgorithm, preferredSize);
        vv = new VisualizationViewer<>(visualizationModel, viewPreferredSize);
        vv.getRenderContext().setNodeLabelFunction(Object::toString);
        vv.getRenderContext().setNodeShapeFunction(n -> new Rectangle2D.Float(-8, -8, 16, 16));
        vv.setBackground(Color.white);

        vv.getRenderContext().setNodeLabelFunction(Object::toString);

        GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
        add(gzsp);

        // the regular graph mouse for the normal view
        final DefaultModalGraphMouse<String, Number> graphMouse = new DefaultModalGraphMouse<>();

        vv.setGraphMouse(graphMouse);
        vv.addKeyListener(graphMouse.getModeKeyListener());

        // create a lens to share between the two hyperbolic transformers
        LayoutModel<String> layoutModel = vv.getModel().getLayoutModel();
        Dimension d = new Dimension(layoutModel.getWidth(), layoutModel.getHeight());
        Lens lens = new Lens(d);
        hyperbolicViewSupport = new ViewLensSupport<>(vv,
                new HyperbolicShapeTransformer(lens,
                        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)),
                new ModalLensGraphMouse());
        hyperbolicLayoutSupport = new LayoutLensSupport<>(vv,
                new HyperbolicTransformer(lens,
                        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT)),
                new ModalLensGraphMouse());

        // the magnification lens uses a different magnification than the hyperbolic lens
        // create a new one to share between the two magnigy transformers
        lens = new Lens(d);
        lens.setMagnification(3.f);
        magnifyViewSupport = new ViewLensSupport<>(vv,
                new MagnifyShapeTransformer(lens,
                        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)),
                new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f)));
        magnifyLayoutSupport = new LayoutLensSupport<>(vv,
                new MagnifyTransformer(lens,
                        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT)),
                new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f)));
        hyperbolicLayoutSupport.getLensTransformer().getLens()
                .setLensShape(hyperbolicViewSupport.getLensTransformer().getLens().getLensShape());
        magnifyViewSupport.getLensTransformer().getLens()
                .setLensShape(hyperbolicLayoutSupport.getLensTransformer().getLens().getLensShape());
        magnifyLayoutSupport.getLensTransformer().getLens()
                .setLensShape(magnifyViewSupport.getLensTransformer().getLens().getLensShape());

        final ScalingControl scaler = new CrossoverScalingControl();

        JButton plus = new JButton("+");
        plus.addActionListener(e -> scaler.scale(vv, 1.1f, vv.getCenter()));

        JButton minus = new JButton("-");
        minus.addActionListener(e -> scaler.scale(vv, 1 / 1.1f, vv.getCenter()));

        ButtonGroup radio = new ButtonGroup();
        JRadioButton normal = new JRadioButton("None");
        normal.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                if (hyperbolicViewSupport != null) {
                    hyperbolicViewSupport.deactivate();
                }
                if (hyperbolicLayoutSupport != null) {
                    hyperbolicLayoutSupport.deactivate();
                }
                if (magnifyViewSupport != null) {
                    magnifyViewSupport.deactivate();
                }
                if (magnifyLayoutSupport != null) {
                    magnifyLayoutSupport.deactivate();
                }
            }
        });

        final JRadioButton hyperView = new JRadioButton("Hyperbolic View");
        hyperView.addItemListener(e -> hyperbolicViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED));

        final JRadioButton hyperModel = new JRadioButton("Hyperbolic Layout");
        hyperModel.addItemListener(e -> hyperbolicLayoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED));

        final JRadioButton magnifyView = new JRadioButton("Magnified View");
        magnifyView.addItemListener(e -> magnifyViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED));

        final JRadioButton magnifyModel = new JRadioButton("Magnified Layout");
        magnifyModel.addItemListener(e -> magnifyLayoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED));

        JLabel modeLabel = new JLabel("     Mode Menu >>");
        modeLabel.setUI(new VerticalLabelUI(false));
        radio.add(normal);
        radio.add(hyperModel);
        radio.add(hyperView);
        radio.add(magnifyModel);
        radio.add(magnifyView);
        normal.setSelected(true);

        graphMouse.addItemListener(hyperbolicLayoutSupport.getGraphMouse().getModeListener());
        graphMouse.addItemListener(hyperbolicViewSupport.getGraphMouse().getModeListener());
        graphMouse.addItemListener(magnifyLayoutSupport.getGraphMouse().getModeListener());
        graphMouse.addItemListener(magnifyViewSupport.getGraphMouse().getModeListener());

        JMenuBar menubar = new JMenuBar();
        menubar.add(graphMouse.getModeMenu());
        gzsp.setCorner(menubar);

        JComboBox modeBox = graphMouse.getModeComboBox();
        modeBox.addItemListener(((DefaultModalGraphMouse<Integer, Number>) vv.getGraphMouse()).getModeListener());

        JRadioButton showSpatialEffects = new JRadioButton("Spatial Structure");
        showSpatialEffects.addItemListener(e -> {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                System.err.println("TURNED ON LOGGING");
                // turn on the logging
                // programmatically set the log level so that the spatial grid is drawn for this demo and the SpatialGrid logging is output
                ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) log;
                LoggerContext ctx = (LoggerContext) LoggerFactory.getILoggerFactory();
                ctx.getLogger("edu.uci.ics.jung.visualization.spatial").setLevel(Level.DEBUG);
                ctx.getLogger("edu.uci.ics.jung.visualization.spatial.rtree").setLevel(Level.DEBUG);
                ctx.getLogger("edu.uci.ics.jung.visualization.BasicVisualizationServer").setLevel(Level.TRACE);
                //            ctx.getLogger("edu.uci.ics.jung.visualization.picking").setLevel(Level.TRACE);
                repaint();

            } else if (e.getStateChange() == ItemEvent.DESELECTED) {
                System.err.println("TURNED OFF LOGGING");
                // turn off the logging
                // programmatically set the log level so that the spatial grid is drawn for this demo and the SpatialGrid logging is output
                ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) log;
                LoggerContext ctx = (LoggerContext) LoggerFactory.getILoggerFactory();
                ctx.getLogger("edu.uci.ics.jung.visualization.spatial").setLevel(Level.INFO);
                ctx.getLogger("edu.uci.ics.jung.visualization.spatial.rtree").setLevel(Level.INFO);
                ctx.getLogger("edu.uci.ics.jung.visualization.BasicVisualizationServer").setLevel(Level.INFO);
                ctx.getLogger("edu.uci.ics.jung.visualization.picking").setLevel(Level.INFO);
                repaint();
            }
        });

        Box controls = Box.createHorizontalBox();
        JPanel zoomControls = new JPanel(new GridLayout(2, 1));
        JPanel modeControls = new JPanel(new GridLayout(2, 1));
        JPanel leftControls = new JPanel();
        JPanel hyperControls = new JPanel(new GridLayout(3, 2));
        hyperControls.setBorder(BorderFactory.createTitledBorder("Examiner Lens"));
        zoomControls.add(plus);
        zoomControls.add(minus);
        modeControls.add(showSpatialEffects);
        modeControls.add(modeBox);
        leftControls.add(zoomControls);
        leftControls.add(modeControls);

        hyperControls.add(normal);
        hyperControls.add(new JLabel());

        hyperControls.add(hyperModel);
        hyperControls.add(magnifyModel);

        hyperControls.add(hyperView);
        hyperControls.add(magnifyView);

        controls.add(leftControls);
        controls.add(hyperControls);
        controls.add(modeLabel);
        add(controls, BorderLayout.SOUTH);
        vv.setNodeToolTipFunction(n -> n.toString());
    }

    static class VerticalLabelUI extends BasicLabelUI {
        static {
            labelUI = new VerticalLabelUI(false);
        }

        protected boolean clockwise;

        VerticalLabelUI(boolean clockwise) {
            super();
            this.clockwise = clockwise;
        }

        public Dimension getPreferredSize(JComponent c) {
            Dimension dim = super.getPreferredSize(c);
            return new Dimension(dim.height, dim.width);
        }

        private static Rectangle paintIconR = new Rectangle();
        private static Rectangle paintTextR = new Rectangle();
        private static Rectangle paintViewR = new Rectangle();
        private static Insets paintViewInsets = new Insets(0, 0, 0, 0);

        public void paint(Graphics g, JComponent c) {

            JLabel label = (JLabel) c;
            String text = label.getText();
            Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon();

            if ((icon == null) && (text == null)) {
                return;
            }

            FontMetrics fm = g.getFontMetrics();
            paintViewInsets = c.getInsets(paintViewInsets);

            paintViewR.x = paintViewInsets.left;
            paintViewR.y = paintViewInsets.top;

            // Use inverted height & width
            paintViewR.height = c.getWidth() - (paintViewInsets.left + paintViewInsets.right);
            paintViewR.width = c.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);

            paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0;
            paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0;

            String clippedText = layoutCL(label, fm, text, icon, paintViewR, paintIconR, paintTextR);

            Graphics2D g2 = (Graphics2D) g;
            AffineTransform tr = g2.getTransform();
            if (clockwise) {
                g2.rotate(Math.PI / 2);
                g2.translate(0, -c.getWidth());
            } else {
                g2.rotate(-Math.PI / 2);
                g2.translate(-c.getHeight(), 0);
            }

            if (icon != null) {
                icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
            }

            if (text != null) {
                int textX = paintTextR.x;
                int textY = paintTextR.y + fm.getAscent();

                if (label.isEnabled()) {
                    paintEnabledText(label, g, clippedText, textX, textY);
                } else {
                    paintDisabledText(label, g, clippedText, textX, textY);
                }
            }

            g2.setTransform(tr);
        }
    }

    Network<String, Number> buildOneNode() {
        MutableNetwork<String, Number> graph = NetworkBuilder.directed().allowsParallelEdges(true).build();
        graph.addNode("A");
        return graph;
    }

    private static void createEdge(MutableNetwork<String, Number> g, String v1Label, String v2Label, int weight) {
        g.addEdge(v1Label, v2Label, new Double(Math.random()));
    }

    public static String[][] pairs = { { "a", "b", "3" }, { "a", "c", "4" }, { "a", "d", "5" }, { "d", "c", "6" },
            { "d", "e", "7" }, { "e", "f", "8" }, { "f", "g", "9" }, { "h", "i", "1" }, { "h", "g", "2" } };

    public static Network<String, Number> getGraph() {
        MutableNetwork<String, Number> g = NetworkBuilder.undirected().allowsParallelEdges(true).build();

        for (int i = 0; i < pairs.length; i++) {
            String[] pair = pairs[i];
            createEdge(g, pair[0], pair[1], Integer.parseInt(pair[2]));
        }
        int edge = 10;
        for (int i = 1; i <= 10; i++) {
            for (int j = i + 1; j <= 10; j++) {
                String i1 = "c" + i;
                String i2 = "c" + j;
                g.addEdge(i1, i2, edge++);
            }
        }

        for (int i = 1; i <= 10; i++) {
            for (int j = i + 1; j <= 10; j++) {
                String i1 = "d" + i;
                String i2 = "d" + j;
                g.addEdge(i1, i2, edge++);
            }
        }

        // and, last, a partial clique
        for (int i = 1; i <= 20; i++) {
            for (int j = i + 1; j <= 20; j++) {
                if (Math.random() > 0.6) {
                    continue;
                }
                String i1 = "q" + i;
                String i2 = "q" + j;
                g.addEdge(i1, i2, edge++);
            }
        }

        // and, last, a partial clique
        for (int i = 1; i <= 20; i++) {
            for (int j = i + 1; j <= 20; j++) {
                if (Math.random() > 0.6) {
                    continue;
                }
                String i1 = "p" + i;
                String i2 = "p" + j;
                g.addEdge(i1, i2, edge++);
            }
        }
        Iterator<String> nodeIt = g.nodes().iterator();
        String current = nodeIt.next();
        while (nodeIt.hasNext()) {
            String next = nodeIt.next();
            g.addEdge(current, next, edge++);
        }
        return g;
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new SpatialLensLargeGraphDemo());
        f.pack();
        f.setVisible(true);
    }
}