/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.graphs; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.commons.collections15.Factory; import com.rapidminer.operator.similarity.SimilarityMeasure; import com.rapidminer.tools.Tools; import edu.uci.ics.jung.graph.Graph; import edu.uci.ics.jung.graph.UndirectedSparseGraph; import edu.uci.ics.jung.graph.util.EdgeType; /** * The graph model creator for similarity measurements. * * @author Ingo Mierswa * @version $Id: SimilarityGraphCreator.java,v 1.14 2008/05/09 19:23:24 ingomierswa Exp $ */ public class SimilarityGraphCreator extends GraphCreatorAdaptor { private static class SortableEdge implements Comparable<SortableEdge> { public static final int DIRECTION_DISTANCE = 1; public static final int DIRECTION_SIMILARITY = -1; private String vertex1; private String vertex2; private double similarity; private int direction; public SortableEdge(String v1, String v2, double sim, int direction) { this.vertex1 = v1; this.vertex2 = v2; this.similarity = sim; this.direction = direction; } public int hashCode() { return Double.valueOf(this.similarity).hashCode(); } public boolean equals(Object o) { if (!(o instanceof SortableEdge)) return false; return ((SortableEdge)o).similarity == this.similarity; } public int compareTo(SortableEdge o) { return direction * Double.compare(this.similarity, o.similarity); } public double getSimilarity() { return this.similarity; } public String getFirstVertex() { return this.vertex1; } public String getSecondVertex() { return this.vertex2; } } private Factory<String> edgeFactory = new Factory<String>() { int i = 0; public String create() { return "E" + i++; } }; private JSlider distanceSlider = new JSlider(SwingConstants.HORIZONTAL, 0, 1000, 100) { private static final long serialVersionUID = -6931545310805789589L; public Dimension getMinimumSize() { return new Dimension(40, (int)super.getMinimumSize().getHeight()); } public Dimension getPreferredSize() { return new Dimension(40, (int)super.getPreferredSize().getHeight()); } public Dimension getMaximumSize() { return new Dimension(40, (int)super.getMaximumSize().getHeight()); } }; private Graph<String,String> graph; private List<String> idList = new ArrayList<String>(); private SimilarityMeasure sim; private Map<String, String> edgeLabelMap = new HashMap<String, String>(); private SimilarityObjectViewer objectViewer = new SimilarityObjectViewer(); public SimilarityGraphCreator(SimilarityMeasure sim) { this.sim = sim; } public Graph<String,String> createGraph() { graph = new UndirectedSparseGraph<String, String>(); Iterator<String> it = sim.getIds(); while (it.hasNext()) { idList.add(it.next()); } for (int i = 0; i < idList.size(); i++) { String id = idList.get(i); graph.addVertex(id); } addEdges(); return graph; } public String getEdgeName(String id) { return edgeLabelMap.get(id); } public String getVertexName(String id) { return id; } public String getVertexToolTip(String id) { return id; } /** Returns the label offset. In most case, using -1 is just fine (default offset). * Some tree like graphs might prefer to use 0 since they manage the offset themself. */ public int getLabelOffset() { return -1; } public int getNumberOfOptionComponents() { return 2; } public JComponent getOptionComponent(final GraphViewer viewer, int index) { if (index == 0) { return new JLabel("Number of Edges:"); } else if (index == 1) { this.distanceSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (!distanceSlider.getValueIsAdjusting()) { addEdges(); viewer.updateLayout(); } } }); return distanceSlider; } else { return null; } } private void addEdges() { Iterator<String> e = edgeLabelMap.keySet().iterator(); while (e.hasNext()) { graph.removeEdge(e.next()); } edgeLabelMap.clear(); int direction = sim.isDistance() ? SortableEdge.DIRECTION_DISTANCE : SortableEdge.DIRECTION_SIMILARITY; List<SortableEdge> sortableEdges = new LinkedList<SortableEdge>(); for (int i = 0; i < idList.size(); i++) { String x = idList.get(i); for (int j = i + 1; j < idList.size(); j++) { String y = idList.get(j); if (sim.isSimilarityDefined(x, y)) { double simV = sim.similarity(x, y); sortableEdges.add(new SortableEdge(x, y, simV, direction)); } } } Collections.sort(sortableEdges); int numberOfEdges = distanceSlider.getValue(); int counter = 0; for (SortableEdge sortableEdge : sortableEdges) { if (counter > numberOfEdges) break; String id = edgeFactory.create(); graph.addEdge(id, sortableEdge.getFirstVertex(), sortableEdge.getSecondVertex(), EdgeType.UNDIRECTED); edgeLabelMap.put(id, Tools.formatIntegerIfPossible(sortableEdge.getSimilarity())); counter++; } } /** Returns false. */ public boolean showEdgeLabelsDefault() { return false; } /** Returns false. */ public boolean showVertexLabelsDefault() { return false; } public Object getObject(String id) { return id; } public GraphObjectViewer getObjectViewer() { return objectViewer; } }