org.jungrapht.samples.large.ShowLayoutsWithGraphFileImport Maven / Gradle / Ivy
Show all versions of jungrapht-visualization-samples Show documentation
package org.jungrapht.samples.large;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.Stroke;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import javax.swing.*;
import org.jgrapht.Graph;
import org.jgrapht.Graphs;
import org.jgrapht.alg.interfaces.VertexScoringAlgorithm;
import org.jgrapht.alg.scoring.*;
import org.jgrapht.graph.builder.GraphTypeBuilder;
import org.jungrapht.samples.spatial.RTreeVisualization;
import org.jungrapht.samples.util.*;
import org.jungrapht.visualization.MultiLayerTransformer;
import org.jungrapht.visualization.VisualizationViewer;
import org.jungrapht.visualization.control.DefaultGraphMouse;
import org.jungrapht.visualization.control.DefaultLensGraphMouse;
import org.jungrapht.visualization.layout.algorithms.BalloonLayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm;
import org.jungrapht.visualization.layout.algorithms.RadialTreeLayoutAlgorithm;
import org.jungrapht.visualization.transform.HyperbolicTransformer;
import org.jungrapht.visualization.transform.LayoutLensSupport;
import org.jungrapht.visualization.transform.Lens;
import org.jungrapht.visualization.transform.LensSupport;
import org.jungrapht.visualization.transform.MagnifyTransformer;
import org.jungrapht.visualization.transform.shape.HyperbolicShapeTransformer;
import org.jungrapht.visualization.transform.shape.MagnifyShapeTransformer;
import org.jungrapht.visualization.transform.shape.ViewLensSupport;
import org.jungrapht.visualization.util.Attributed.*;
import org.jungrapht.visualization.util.LayoutAlgorithmTransition;
import org.jungrapht.visualization.util.LayoutPaintable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Demonstrates several of the graph layout algorithms. Allows the user to interactively select one
* of several graphs, loaded from files using JGrapht io, and one of several layouts, and visualizes
* the combination.
*
* This application has been tested with the graphml sample files in
* https://github.com/melaniewalsh/sample-social-network-datasets
*
* @author Tom Nelson
*/
public class ShowLayoutsWithGraphFileImport extends JFrame {
private static final Logger log = LoggerFactory.getLogger(ShowLayoutsWithGraphFileImport.class);
LayoutPaintable.BalloonRings balloonLayoutRings;
LayoutPaintable.RadialRings radialLayoutRings;
LayoutPaintable.LayoutBounds layoutBounds;
JFileChooser fileChooser;
VisualizationViewer vv;
Paint[] colorArray =
new Paint[] {
Color.red,
Color.green,
Color.blue,
Color.cyan,
Color.magenta,
Color.yellow,
Color.pink,
Color.gray,
Color.darkGray,
Color.lightGray,
Color.orange
};
Function vertexFillPaintFunction = v -> Colors.getColor(v.getAttributeMap());
Graph graph =
GraphTypeBuilder.directed()
.vertexSupplier(new ASSupplier())
.allowingSelfLoops(true)
.allowingMultipleEdges(true)
.edgeSupplier(new AISupplier())
.buildGraph();
public ShowLayoutsWithGraphFileImport() {
JPanel container = new JPanel(new BorderLayout());
final DefaultGraphMouse graphMouse = new DefaultGraphMouse<>();
vv =
VisualizationViewer.builder(graph)
.layoutSize(new Dimension(1800, 1800))
.viewSize(new Dimension(900, 900))
.graphMouse(graphMouse)
.build();
vv.setVertexToolTipFunction(Object::toString);
vv.getRenderContext()
.setVertexLabelFunction(
vertex -> {
Map map = vertex.getAttributeMap();
return map.getOrDefault("label", map.getOrDefault("ID", "NONE"));
});
vv.setEdgeToolTipFunction(Object::toString);
vv.getRenderContext().setVertexFillPaintFunction(vertexFillPaintFunction);
Function vertexDrawPaintFunction =
v -> vv.getSelectedVertexState().isSelected(v) ? Color.pink : Color.black;
Function vertexStrokeFunction =
v ->
vv.getSelectedVertexState().isSelected(v) ? new BasicStroke(8.f) : new BasicStroke(2.f);
vv.getRenderContext().setVertexStrokeFunction(vertexStrokeFunction);
vv.scaleToLayout();
container.add(vv.getComponent(), BorderLayout.CENTER);
LayoutHelper.Layouts[] combos = LayoutHelper.getCombos();
final JToggleButton animateLayoutTransition = new JToggleButton("Animate Layout Transition");
final JComboBox layoutComboBox = new JComboBox(combos);
layoutComboBox.addActionListener(
e ->
SwingUtilities.invokeLater(
() -> {
LayoutHelper.Layouts layoutType =
(LayoutHelper.Layouts) layoutComboBox.getSelectedItem();
LayoutAlgorithm layoutAlgorithm = layoutType.getLayoutAlgorithm();
vv.removePreRenderPaintable(balloonLayoutRings);
vv.removePreRenderPaintable(radialLayoutRings);
if (animateLayoutTransition.isSelected()) {
LayoutAlgorithmTransition.animate(vv, layoutAlgorithm);
} else {
LayoutAlgorithmTransition.apply(vv, layoutAlgorithm);
}
if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) {
balloonLayoutRings =
new LayoutPaintable.BalloonRings(
vv, (BalloonLayoutAlgorithm) layoutAlgorithm);
vv.addPreRenderPaintable(balloonLayoutRings);
}
if (layoutAlgorithm instanceof RadialTreeLayoutAlgorithm) {
radialLayoutRings =
new LayoutPaintable.RadialRings(
vv, (RadialTreeLayoutAlgorithm) layoutAlgorithm);
vv.addPreRenderPaintable(radialLayoutRings);
}
if (layoutBounds != null) {
vv.removePreRenderPaintable(layoutBounds);
}
vv.addPreRenderPaintable(new LayoutPaintable.LayoutBounds(vv));
}));
layoutComboBox.setSelectedItem(LayoutHelper.Layouts.FR_BH_VISITOR);
// create a lens to share between the two hyperbolic transformers
Lens lens = new Lens(); /* provides a Hyperbolic lens for the view */
LensSupport hyperbolicViewSupport =
ViewLensSupport.builder(vv)
.lensTransformer(
HyperbolicShapeTransformer.builder(lens)
.delegate(
vv.getRenderContext()
.getMultiLayerTransformer()
.getTransformer(MultiLayerTransformer.Layer.VIEW))
.build())
.lensGraphMouse(
DefaultLensGraphMouse.builder()
.magnificationFloor(0.4f)
.magnificationCeiling(1.0f)
.magnificationDelta(0.05f)
.build())
.build();
LensSupport hyperbolicLayoutSupport =
LayoutLensSupport.builder(vv)
.lensTransformer(
HyperbolicTransformer.builder(lens)
.delegate(
vv.getRenderContext()
.getMultiLayerTransformer()
.getTransformer(MultiLayerTransformer.Layer.LAYOUT))
.build())
.lensGraphMouse(new DefaultLensGraphMouse<>())
.build();
// 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();
lens.setMagnification(3.f);
LensSupport magnifyViewSupport =
ViewLensSupport.builder(vv)
.lensTransformer(
MagnifyShapeTransformer.builder(lens)
.delegate(
vv.getRenderContext()
.getMultiLayerTransformer()
.getTransformer(MultiLayerTransformer.Layer.VIEW))
.build())
.lensGraphMouse( // override with range for magnificaion
DefaultLensGraphMouse.builder()
.magnificationFloor(1.0f)
.magnificationCeiling(4.0f)
.build())
.build();
LensSupport magnifyLayoutSupport =
LayoutLensSupport.builder(vv)
.lensTransformer(
MagnifyTransformer.builder(lens)
.delegate(
vv.getRenderContext()
.getMultiLayerTransformer()
.getTransformer(MultiLayerTransformer.Layer.LAYOUT))
.build())
.lensGraphMouse( // override with range for magnificaion
DefaultLensGraphMouse.builder()
.magnificationFloor(1.0f)
.magnificationCeiling(4.0f)
.build())
.build();
hyperbolicLayoutSupport
.getLensTransformer()
.getLens()
.setLensShape(hyperbolicViewSupport.getLensTransformer().getLens().getLensShape());
magnifyViewSupport
.getLensTransformer()
.getLens()
.setLensShape(hyperbolicLayoutSupport.getLensTransformer().getLens().getLensShape());
magnifyLayoutSupport
.getLensTransformer()
.getLens()
.setLensShape(magnifyViewSupport.getLensTransformer().getLens().getLensShape());
JComponent lensBox =
LensControlHelper.builder(
Map.of(
"Hyperbolic View", hyperbolicViewSupport,
"Hyperbolic Layout", hyperbolicLayoutSupport,
"Magnified View", magnifyViewSupport,
"Magnified Layout", magnifyLayoutSupport))
.containerSupplier(JPanel::new)
.containerLayoutManager(new GridLayout(0, 2))
.title("Lens Controls")
.build()
.container();
JPanel loadFilePanel = new JPanel();
JButton loadFileButton = new JButton("Load File");
loadFilePanel.add(loadFileButton);
loadFileButton.addActionListener(
e -> {
if (fileChooser == null) {
fileChooser = new JFileChooser();
}
int option = fileChooser.showOpenDialog(vv.getComponent());
if (option == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
if (!ASAILoader.load(file, graph)) {
JOptionPane.showMessageDialog(vv.getComponent(), "Unable to open " + file.getName());
return;
}
vv.getRenderContext().setVertexFillPaintFunction(vertexFillPaintFunction);
vv.getVisualizationModel().setGraph(graph);
setTitle(
"Graph of "
+ file.getName()
+ " with "
+ graph.vertexSet().size()
+ " vertices and "
+ graph.edgeSet().size()
+ " edges");
}
});
JButton pageRankButton = new JButton("Page Rank");
pageRankButton.addActionListener(event -> computeScores(new PageRank(graph)));
JButton betweennessButton = new JButton("Betweenness");
betweennessButton.addActionListener(event -> computeScores(new BetweennessCentrality<>(graph)));
JButton closenessButton = new JButton("Closeness");
closenessButton.addActionListener(event -> computeScores(new ClosenessCentrality<>(graph)));
JButton clusteringButton = new JButton("Clustering");
clusteringButton.addActionListener(event -> computeScores(new ClusteringCoefficient<>(graph)));
JButton eigenvectorButton = new JButton("Eigenvector");
eigenvectorButton.addActionListener(event -> computeScores(new EigenvectorCentrality<>(graph)));
JButton katzButton = new JButton("Katz");
katzButton.addActionListener(event -> computeScores(new KatzCentrality<>(graph)));
JButton harmonicButton = new JButton("Harmonic");
harmonicButton.addActionListener(event -> computeScores(new HarmonicCentrality<>(graph)));
JButton noScores = new JButton("None");
noScores.addActionListener(
event -> {
vv.getRenderContext().setVertexFillPaintFunction(vertexFillPaintFunction);
vv.repaint();
});
JPanel scoringGrid = new JPanel(new GridLayout(0, 2));
scoringGrid.add(pageRankButton);
scoringGrid.add(betweennessButton);
scoringGrid.add(closenessButton);
scoringGrid.add(clusteringButton);
scoringGrid.add(harmonicButton);
scoringGrid.add(eigenvectorButton);
scoringGrid.add(katzButton);
scoringGrid.add(noScores);
JPanel controlPanel = new JPanel(new GridLayout(2, 1));
JComponent top =
ControlHelpers.getContainer(
Box.createHorizontalBox(),
ControlHelpers.getCenteredContainer("Graph Source", loadFilePanel),
ControlHelpers.getCenteredContainer("Layouts", layoutComboBox),
ControlHelpers.getCenteredContainer("Scoring", scoringGrid));
controlPanel.add(top);
JButton showRTree = new JButton("Show RTree");
showRTree.addActionListener(e -> RTreeVisualization.showRTree(vv));
JComponent bottom =
ControlHelpers.getContainer(
Box.createHorizontalBox(),
// ControlHelpers.getZoomControls("Scale", vv),
lensBox,
ControlHelpers.getCenteredContainer(
"Effects", Box.createVerticalBox(), showRTree, animateLayoutTransition));
controlPanel.add(bottom);
container.add(controlPanel, BorderLayout.NORTH);
setTitle(
"Graph With "
+ graph.vertexSet().size()
+ " vertices and "
+ graph.edgeSet().size()
+ " edges");
getContentPane().add(container);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
private void computeScores(VertexScoringAlgorithm scoring) {
Map scores = scoring.getScores();
if (scores.isEmpty()) return;
double min = scores.values().stream().min(Double::compare).get();
double max = scores.values().stream().max(Double::compare).get();
double range = max - min;
log.info("min:{}, max:{}, range:{}", min, max, range);
double delta = range / colorArray.length;
log.info("delta:{}", delta);
vv.getRenderContext()
.setVertexFillPaintFunction(
v -> {
if (scores.isEmpty() || !scores.containsKey(v)) return Color.red;
double score = scores.get(v);
double index = score / delta;
int idx = (int) Math.max(0, Math.min(colorArray.length - 1, index));
return colorArray[idx];
});
vv.repaint();
}
void clear(Graph graph) {
Set edges = new HashSet(graph.edgeSet());
Set vertices = new HashSet(graph.vertexSet());
edges.forEach(graph::removeEdge);
vertices.forEach(graph::removeVertex);
}
private Collection getRoots(Graph graph) {
Set roots = new HashSet<>();
for (Object v : graph.vertexSet()) {
if (Graphs.predecessorListOf(graph, v).isEmpty()) {
roots.add(v);
}
}
return roots;
}
public static void main(String[] args) {
new ShowLayoutsWithGraphFileImport();
}
}