Java tutorial
/* * Copyright (c) 2003, the JUNG Project and the Regents of the University * of California * All rights reserved. * * This software is open-source under the BSD license; see either * "license.txt" or * http://jung.sourceforge.net/license.txt for a description. */ package gui; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Paint; import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.geom.Point2D; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JToggleButton; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.commons.collections15.Factory; import org.apache.commons.collections15.Transformer; import org.apache.commons.collections15.functors.ConstantTransformer; import org.apache.commons.collections15.functors.MapTransformer; import org.apache.commons.collections15.map.LazyMap; import edu.uci.ics.jung.algorithms.cluster.EdgeBetweennessClusterer; import edu.uci.ics.jung.algorithms.layout.AggregateLayout; import edu.uci.ics.jung.algorithms.layout.BalloonLayout; import edu.uci.ics.jung.algorithms.layout.CircleLayout; import edu.uci.ics.jung.algorithms.layout.FRLayout; import edu.uci.ics.jung.algorithms.layout.KKLayout; import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.algorithms.layout.TreeLayout; import edu.uci.ics.jung.algorithms.layout.util.Relaxer; import edu.uci.ics.jung.graph.Forest; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.SparseMultigraph; import edu.uci.ics.jung.graph.UndirectedGraph; import edu.uci.ics.jung.graph.UndirectedSparseMultigraph; import edu.uci.ics.jung.graph.util.TestGraphs; import edu.uci.ics.jung.io.PajekNetReader; import edu.uci.ics.jung.visualization.GraphZoomScrollPane; import edu.uci.ics.jung.visualization.VisualizationViewer; import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse; import java.util.ArrayList; import java.util.Hashtable; import java.util.TreeSet; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import wikipedia.explorer.data.WikiNode; /** * This simple app demonstrates how one can use our algorithms and visualization * libraries in unison. In this case, we generate use the Zachary karate club * data set, widely known in the social networks literature, then we cluster the * vertices using an edge-betweenness clusterer, and finally we visualize the * graph using Fruchtermain-Rheingold layout and provide a slider so that the * user can adjust the clustering granularity. * * @author Scott White */ @SuppressWarnings("serial") public class WikiCorpusClusteringView extends JApplet { VisualizationViewer<Number, Number> vv; // Factory<Graph<Number,Number>> graphFactory; Map<Number, Paint> vertexPaints = LazyMap.<Number, Paint>decorate(new HashMap<Number, Paint>(), new ConstantTransformer(Color.white)); Map<Number, Paint> edgePaints = LazyMap.<Number, Paint>decorate(new HashMap<Number, Paint>(), new ConstantTransformer(Color.blue)); public final Color[] similarColors = { new Color(216, 134, 134), new Color(135, 137, 211), new Color(134, 206, 189), new Color(206, 176, 134), new Color(194, 204, 134), new Color(145, 214, 134), new Color(133, 178, 209), new Color(103, 148, 255), new Color(60, 220, 220), new Color(30, 250, 100) }; public void open(HashMap<String, String> _iwlinks, String[] _links, String[] _catMembs, JPanel jpNETWORK, String[] a) throws IOException { centerPage = new WikiNode(a); links = _links; iwlinks = _iwlinks; catMembs = _catMembs; mode = 2; jpNETWORK.add(this, BorderLayout.CENTER); start(); // Add a restart button so the graph can be redrawn to fit the size of the frame } static HashMap<String, String> iwlinks; static String[] links; static String[] catMembs; public static void main(String[] args) throws IOException { WikiCorpusClusteringView cd = new WikiCorpusClusteringView(); cd.start(); // Add a restart button so the graph can be redrawn to fit the size of the frame JFrame jf = new JFrame(); jf.getContentPane().add(cd); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.pack(); jf.setVisible(true); } int mode = 1; public void start() { Graph<Number, Number> graph = null; switch (mode) { case 1: graph = loadDemoGraph(); break; case 2: graph = loadWikiGraph(); break; } try { setUpView(graph); } catch (IOException ex) { ex.printStackTrace(); Logger.getLogger(WikiCorpusClusteringView.class.getName()).log(Level.SEVERE, null, ex); } } public Graph loadDemoGraph() { InputStream is = this.getClass().getClassLoader().getResourceAsStream("datasets/zachary.net"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); final Graph<Number, Number> graph = new SparseMultigraph<Number, Number>(); try { Factory<Number> vertexFactory = new Factory<Number>() { int n = 0; public Number create() { return n++; } }; Factory<Number> edgeFactory = new Factory<Number>() { int n = 0; public Number create() { return n++; } }; PajekNetReader<Graph<Number, Number>, Number, Number> pnr = new PajekNetReader<Graph<Number, Number>, Number, Number>( vertexFactory, edgeFactory); pnr.load(br, graph); } catch (IOException e) { System.out.println("Error in loading graph"); e.printStackTrace(); } return graph; } /** * * @param br * @throws IOException */ private void setUpView(Graph graph) throws IOException { //Create a simple layout frame //specify the Fruchterman-Rheingold layout algorithm // final AggregateLayout<Number, Number> layout = // new AggregateLayout<Number, Number>(new FRLayout<Number, Number>(graph)); //layout = new TreeLayout<String,Integer>(graph); Layout<Number, Number> layout = new KKLayout<Number, Number>(graph); layout.setSize(new Dimension(900, 900)); vv = new VisualizationViewer<Number, Number>(layout); vv.setBackground(Color.white); //Tell the renderer to use our own customized color rendering vv.getRenderContext() .setVertexFillPaintTransformer(MapTransformer.<Number, Paint>getInstance(vertexPaints)); vv.getRenderContext().setVertexDrawPaintTransformer(new Transformer<Number, Paint>() { public Paint transform(Number v) { if (vv.getPickedVertexState().isPicked(v)) { return Color.cyan; } else { return Color.BLACK; } } }); vv.getRenderContext().setEdgeDrawPaintTransformer(MapTransformer.<Number, Paint>getInstance(edgePaints)); vv.getRenderContext().setEdgeStrokeTransformer(new Transformer<Number, Stroke>() { protected final Stroke THIN = new BasicStroke(1); protected final Stroke THICK = new BasicStroke(2); public Stroke transform(Number e) { Paint c = edgePaints.get(e); if (c == Color.LIGHT_GRAY) { return THIN; } else { return THICK; } } }); //add restart button JButton scramble = new JButton("Restart"); scramble.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { Layout layout = vv.getGraphLayout(); layout.initialize(); Relaxer relaxer = vv.getModel().getRelaxer(); if (relaxer != null) { relaxer.stop(); relaxer.prerelax(); relaxer.relax(); } } }); DefaultModalGraphMouse gm = new DefaultModalGraphMouse(); vv.setGraphMouse(gm); final JToggleButton groupVertices = new JToggleButton("Group Clusters"); //Create slider to adjust the number of edges to remove when clustering final JSlider edgeBetweennessSlider = new JSlider(JSlider.HORIZONTAL); edgeBetweennessSlider.setBackground(Color.WHITE); edgeBetweennessSlider.setPreferredSize(new Dimension(210, 50)); edgeBetweennessSlider.setPaintTicks(true); edgeBetweennessSlider.setMaximum(graph.getEdgeCount()); edgeBetweennessSlider.setMinimum(0); edgeBetweennessSlider.setValue(0); edgeBetweennessSlider.setMajorTickSpacing(10); edgeBetweennessSlider.setPaintLabels(true); edgeBetweennessSlider.setPaintTicks(true); // edgeBetweennessSlider.setBorder(BorderFactory.createLineBorder(Color.black)); //TO DO: edgeBetweennessSlider.add(new JLabel("Node Size (PageRank With Priors):")); //I also want the slider value to appear final JPanel eastControls = new JPanel(); eastControls.setOpaque(true); eastControls.setLayout(new BoxLayout(eastControls, BoxLayout.Y_AXIS)); eastControls.add(Box.createVerticalGlue()); eastControls.add(edgeBetweennessSlider); final String COMMANDSTRING = "Edges removed for clusters: "; final String eastSize = COMMANDSTRING + edgeBetweennessSlider.getValue(); final TitledBorder sliderBorder = BorderFactory.createTitledBorder(eastSize); eastControls.setBorder(sliderBorder); //eastControls.add(eastSize); eastControls.add(Box.createVerticalGlue()); groupVertices.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { //clusterAndRecolor(layout, edgeBetweennessSlider.getValue(), // similarColors, e.getStateChange() == ItemEvent.SELECTED); vv.repaint(); } }); //clusterAndRecolor(layout, 0, similarColors, groupVertices.isSelected()); edgeBetweennessSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { JSlider source = (JSlider) e.getSource(); if (!source.getValueIsAdjusting()) { int numEdgesToRemove = source.getValue(); //clusterAndRecolor(layout, numEdgesToRemove, similarColors, // groupVertices.isSelected()); sliderBorder.setTitle(COMMANDSTRING + edgeBetweennessSlider.getValue()); eastControls.repaint(); vv.validate(); vv.repaint(); } } }); Container content = getContentPane(); content.add(new GraphZoomScrollPane(vv)); JPanel south = new JPanel(); JPanel grid = new JPanel(new GridLayout(2, 1)); grid.add(scramble); grid.add(groupVertices); south.add(grid); south.add(eastControls); JPanel p = new JPanel(); p.setBorder(BorderFactory.createTitledBorder("Mouse Mode")); p.add(gm.getModeComboBox()); south.add(p); content.add(south, BorderLayout.SOUTH); } public void clusterAndRecolor(AggregateLayout<Number, Number> layout, int numEdgesToRemove, Color[] colors, boolean groupClusters) { //Now cluster the vertices by removing the top 50 edges with highest betweenness // if (numEdgesToRemove == 0) { // colorCluster( g.getVertices(), colors[0] ); // } else { // Graph<Number, Number> g = layout.getGraph(); // layout.removeAll(); // // EdgeBetweennessClusterer<Number, Number> clusterer = // new EdgeBetweennessClusterer<Number, Number>(numEdgesToRemove); // Set<Set<Number>> clusterSet = clusterer.transform(g); // List<Number> edges = clusterer.getEdgesRemoved(); // // int i = 0; // //Set the colors of each node so that each cluster's vertices have the same color // for (Iterator<Set<Number>> cIt = clusterSet.iterator(); cIt.hasNext();) { // // Set<Number> vertices = cIt.next(); // Color c = colors[i % colors.length]; // // colorCluster(vertices, c); // if (groupClusters == true) { // groupCluster(layout, vertices); // } // i++; // } // for (Number e : g.getEdges()) { // // if (edges.contains(e)) { // edgePaints.put(e, Color.lightGray); // } else { // edgePaints.put(e, Color.black); // } // } } private void colorCluster(Set<Number> vertices, Color c) { for (Number v : vertices) { vertexPaints.put(v, c); } } private void groupCluster(AggregateLayout<Number, Number> layout, Set<Number> vertices) { if (vertices.size() < layout.getGraph().getVertexCount()) { Point2D center = layout.transform(vertices.iterator().next()); Graph<Number, Number> subGraph = SparseMultigraph.<Number, Number>getFactory().create(); for (Number v : vertices) { subGraph.addVertex(v); } Layout<Number, Number> subLayout = new CircleLayout<Number, Number>(subGraph); subLayout.setInitializer(vv.getGraphLayout()); subLayout.setSize(new Dimension(40, 40)); layout.put(subLayout, center); vv.repaint(); } } private Graph<Number, Number> loadWikiGraph() { Graph<Number, Number> graph = getGraph(); return graph; } WikiNode centerPage = null; Hashtable<Integer, WikiNode> linksHASH = new Hashtable<Integer, WikiNode>(); Hashtable<WikiNode, Integer> linksHASH_INV = new Hashtable<WikiNode, Integer>(); public Graph<Number, Number> getGraph() { UndirectedGraph<Number, Number> g1 = new UndirectedSparseMultigraph<Number, Number>(); // KERN TreeSet<Number> s0 = new TreeSet<Number>(); s0.add(0); colorCluster(s0, Color.BLACK); linksHASH.put(0, centerPage); g1.addVertex(0); int i = 1; // add direct linked pages TreeSet<Number> s1 = new TreeSet<Number>(); for (String l : links) { WikiNode n = new WikiNode(centerPage.wiki, l); linksHASH.put(i, n); linksHASH_INV.put(n, i); s0.add(0); g1.addEdge(i, 0, i); g1.addVertex(i); i++; } colorCluster(s1, Color.BLUE); // add IWL-Pages TreeSet<Number> s2 = new TreeSet<Number>(); for (String key : iwlinks.keySet()) { String value = iwlinks.get(key); System.out.println("val=" + key + "_" + value); WikiNode n = new WikiNode(key, value); linksHASH.put(i, n); linksHASH_INV.put(n, i); s2.add(i); g1.addVertex(i); if (!linksHASH_INV.containsKey(value)) { g1.addEdge(i, 0, i); } i++; } colorCluster(s2, Color.RED); // add Categorie Members TreeSet<Number> s3 = new TreeSet<Number>(); for (String l : catMembs) { WikiNode n = new WikiNode(centerPage.wiki, l); g1.addVertex(i); if (linksHASH_INV.containsKey(l)) { g1.addEdge(i, 0, i); linksHASH.put(i, n); } i++; s3.add(i); } colorCluster(s3, Color.GREEN); return g1; } } class Link { double str = 0; int src = 0; int dest = 0; }