/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Copyright (C) 2004 * & Matthias Schubert (schubert@dbs.ifi.lmu.de) * & Zhanna Melnikova-Albrecht (melnikov@cip.ifi.lmu.de) * & Rainer Holzmann (holzmann@cip.ifi.lmu.de) */ package weka.clusterers.forOPTICSAndDBScan.OPTICS_GUI; import weka.clusterers.forOPTICSAndDBScan.DataObjects.DataObject; import weka.core.FastVector; import weka.core.RevisionHandler; import weka.core.RevisionUtils; import weka.core.Utils; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JComponent; /** * <p> * GraphPanel.java <br/> * Authors: Rainer Holzmann, Zhanna Melnikova-Albrecht <br/> * Date: Sep 16, 2004 <br/> * Time: 10:28:19 AM <br/> * $ Revision 1.4 $ <br/> * </p> * * @author Zhanna Melnikova-Albrecht (melnikov@cip.ifi.lmu.de) * @author Rainer Holzmann (holzmann@cip.ifi.lmu.de) * @version $Revision: 1.4 $ */ public class GraphPanel extends JComponent implements RevisionHandler { /** for serialization */ private static final long serialVersionUID = 7917937528738361470L; /** * Holds the clustering results */ private FastVector resultVector; /** * Holds the value that is multiplied with the original values of core- and reachability * distances in order to get better graphical views */ private int verticalAdjustment; /** * Specifies the color for displaying core-distances */ private Color coreDistanceColor; /** * Specifies the color for displaying reachability-distances */ private Color reachabilityDistanceColor; /** * Specifies the width for displaying the distances */ private int widthSlider; /** * Holds the flag for showCoreDistances */ private boolean showCoreDistances; /** * Holds the flag for showrRechabilityDistances */ private boolean showReachabilityDistances; /** * Holds the index of the last toolTip */ private int recentIndex = -1; // ***************************************************************************************************************** // constructors // ***************************************************************************************************************** public GraphPanel(FastVector resultVector, int verticalAdjustment, boolean showCoreDistances, boolean showReachbilityDistances) { this.resultVector = resultVector; this.verticalAdjustment = verticalAdjustment; coreDistanceColor = new Color(100, 100, 100); reachabilityDistanceColor = Color.orange; widthSlider = 5; this.showCoreDistances = showCoreDistances; this.showReachabilityDistances = showReachbilityDistances; addMouseMotionListener(new MouseHandler()); } // ***************************************************************************************************************** // methods // ***************************************************************************************************************** /** * Draws the OPTICS Plot * @param g */ protected void paintComponent(Graphics g) { if (isOpaque()) { Dimension size = getSize(); g.setColor(getBackground()); g.fillRect(0, 0, size.width, size.height); } int stepSize = 0; int cDist = 0; int rDist = 0; for (int vectorIndex = 0; vectorIndex < resultVector.size(); vectorIndex++) { double coreDistance = ((DataObject) resultVector.elementAt(vectorIndex)).getCoreDistance(); double reachDistance = ((DataObject) resultVector.elementAt(vectorIndex)).getReachabilityDistance(); if (coreDistance == DataObject.UNDEFINED) cDist = getHeight(); else cDist = (int) (coreDistance * verticalAdjustment); if (reachDistance == DataObject.UNDEFINED) rDist = getHeight(); else rDist = (int) (reachDistance * verticalAdjustment); int x = vectorIndex + stepSize; if (isShowCoreDistances()) { /** * Draw coreDistance */ g.setColor(coreDistanceColor); g.fillRect(x, getHeight() - cDist, widthSlider, cDist); } if (isShowReachabilityDistances()) { int sizer = widthSlider; if (!isShowCoreDistances()) sizer = 0; /** * Draw reachabilityDistance */ g.setColor(reachabilityDistanceColor); g.fillRect(x + sizer, getHeight() - rDist, widthSlider, rDist); } if (isShowCoreDistances() && isShowReachabilityDistances()) { stepSize += (widthSlider * 2); } else stepSize += widthSlider; } } /** * Sets a new resultVector * @param resultVector */ public void setResultVector(FastVector resultVector) { this.resultVector = resultVector; } /** * Displays a toolTip for the selected DataObject * @param toolTip */ public void setNewToolTip(String toolTip) { setToolTipText(toolTip); } /** * Adjusts the size of this panel in respect of the shown content * @param serObject SERObject that contains the OPTICS clustering results */ public void adjustSize(SERObject serObject) { int i = 0; if (isShowCoreDistances() && isShowReachabilityDistances()) i = 10; else if ((isShowCoreDistances() && !isShowReachabilityDistances()) || !isShowCoreDistances() && isShowReachabilityDistances()) i = 5; setSize(new Dimension((i * serObject.getDatabaseSize()) + serObject.getDatabaseSize(), getHeight())); setPreferredSize(new Dimension((i * serObject.getDatabaseSize()) + serObject.getDatabaseSize(), getHeight())); } /** * Returns the flag for showCoreDistances * @return True or false */ public boolean isShowCoreDistances() { return showCoreDistances; } /** * Sets the flag for showCoreDistances * @param showCoreDistances */ public void setShowCoreDistances(boolean showCoreDistances) { this.showCoreDistances = showCoreDistances; } /** * Returns the flag for showReachabilityDistances * @return True or false */ public boolean isShowReachabilityDistances() { return showReachabilityDistances; } /** * Sets the flag for showReachabilityDistances * @param showReachabilityDistances */ public void setShowReachabilityDistances(boolean showReachabilityDistances) { this.showReachabilityDistances = showReachabilityDistances; } /** * Sets a new value for the vertical verticalAdjustment * @param verticalAdjustment */ public void setVerticalAdjustment(int verticalAdjustment) { this.verticalAdjustment = verticalAdjustment; } /** * Sets a new color for the coreDistance * @param coreDistanceColor */ public void setCoreDistanceColor(Color coreDistanceColor) { this.coreDistanceColor = coreDistanceColor; repaint(); } /** * Sets a new color for the reachabilityDistance * @param reachabilityDistanceColor */ public void setReachabilityDistanceColor(Color reachabilityDistanceColor) { this.reachabilityDistanceColor = reachabilityDistanceColor; repaint(); } // ***************************************************************************************************************** // inner classes // ***************************************************************************************************************** private class MouseHandler extends MouseMotionAdapter implements RevisionHandler { /** * Invoked when the mouse button has been moved on a component * (with no buttons no down). */ public void mouseMoved(MouseEvent e) { showToolTip(e.getX()); } /** * Shows a toolTip with the dataObjects parameters (c-dist, r-dist, key, attributes . . .) * @param x MouseCoordinate X * @return boolean */ private boolean showToolTip(int x) { int i = 0; if (isShowCoreDistances() && isShowReachabilityDistances()) i = 11; else if ((isShowCoreDistances() && !isShowReachabilityDistances()) || !isShowCoreDistances() && isShowReachabilityDistances() || !isShowCoreDistances() && !isShowReachabilityDistances()) i = 6; if ((x / i) == recentIndex) return false; else recentIndex = x / i; DataObject dataObject = null; try { dataObject = (DataObject) resultVector.elementAt(recentIndex); } catch (Exception e) { } if (dataObject != null) { if (!isShowCoreDistances() && !isShowReachabilityDistances()) { setNewToolTip("<html><body><b>Please select a distance" + "</b></body></html>" ); } else setNewToolTip("<html><body><table>" + "<tr><td>DataObject:</td><td>" + dataObject + "</td></tr>" + "<tr><td>Key:</td><td>" + dataObject.getKey() + "</td></tr>" + "<tr><td>" + (isShowCoreDistances() ? "<b>" : "") + "Core-Distance:" + (isShowCoreDistances() ? "</b>" : "") + "</td><td>" + (isShowCoreDistances() ? "<b>" : "") + ((dataObject.getCoreDistance() == DataObject.UNDEFINED) ? "UNDEFINED" : Utils.doubleToString(dataObject.getCoreDistance(), 3, 5)) + (isShowCoreDistances() ? "</b>" : "") + "</td></tr>" + "<tr><td>" + (isShowReachabilityDistances() ? "<b>" : "") + "Reachability-Distance:" + (isShowReachabilityDistances() ? "</b>" : "") + "</td><td>" + (isShowReachabilityDistances() ? "<b>" : "") + ((dataObject.getReachabilityDistance() == DataObject.UNDEFINED) ? "UNDEFINED" : Utils.doubleToString(dataObject.getReachabilityDistance(), 3, 5)) + (isShowReachabilityDistances() ? "</b>" : "") + "</td></tr>" + "</table></body></html>" ); } return true; } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 1.4 $"); } } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 1.4 $"); } }