at.tuwien.ifs.somtoolbox.visualization.ClusterConnectionsVisualizer.java Source code

Java tutorial

Introduction

Here is the source code for at.tuwien.ifs.somtoolbox.visualization.ClusterConnectionsVisualizer.java

Source

/*
 * Copyright 2004-2010 Information & Software Engineering Group (188/1)
 *                     Institute of Software Technology and Interactive Systems
 *                     Vienna University of Technology, Austria
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package at.tuwien.ifs.somtoolbox.visualization;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.math.util.MathUtils;

import cern.colt.matrix.DoubleMatrix2D;

import at.tuwien.ifs.somtoolbox.SOMToolboxException;
import at.tuwien.ifs.somtoolbox.layers.GrowingLayer;
import at.tuwien.ifs.somtoolbox.models.GrowingSOM;
import at.tuwien.ifs.somtoolbox.util.GridBagConstraintsIFS;

/**
 * Implementation of the Cluster Connections Visualisation as described in <i><b>D. Merkl and A. Rauber.</b> Proceedings
 * of the Workshop on Self-Organizing Maps (WSOM97), Helsinki, Finland, June 4-6 1997.
 * 
 * @author Robert Thurnher
 * @author Michael Groh
 * @author Rudolf Mayer
 * @version $Id: ClusterConnectionsVisualizer.java 3874 2010-11-02 14:14:38Z mayer $
 */
public class ClusterConnectionsVisualizer extends AbstractBackgroundImageVisualizer
        implements BackgroundImageVisualizer {

    private double t1 = 0.8;

    private double t2 = 1.1;

    private double t3 = 1.6;

    public ClusterConnectionsVisualizer() {
        NUM_VISUALIZATIONS = 1;
        VISUALIZATION_NAMES = new String[] { "Cluster Connections" };
        VISUALIZATION_SHORT_NAMES = new String[] { "ClusterConn" };
        VISUALIZATION_DESCRIPTIONS = new String[] {
                " Implementation of the Cluster Connections Visualisation as described in \"D. Merkl and A. Rauber.\"\n"
                        + "Proceedings of the Workshop on Self-Organizing Maps (WSOM97),\n"
                        + "Helsinki, Finland, June 4-6 1997." };
        controlPanel = new ClusterConnectionsControlPanel();
    }

    @Override
    protected String getCacheKey(GrowingSOM gsom, int currentVariant, int width, int height) {
        return appendToCacheKey(gsom, currentVariant, width, height, "t1:" + t1, "t2:" + t2, "t3:" + t3);
    }

    @Override
    public BufferedImage createVisualization(int variantIndex, GrowingSOM gsom, int width, int height)
            throws SOMToolboxException {
        GrowingLayer layer = gsom.getLayer();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        g.setBackground(Color.WHITE);
        g.clearRect(0, 0, width, height);

        // need to calculate some params relative to the unit width/height, which is relative to the desired output size
        // a unitWidth/Height of 10, as used previously, works by default only fine in the SOMViewer
        int somWidth = layer.getXSize();
        int somHeight = layer.getYSize();
        double unitWidth = width / somWidth;
        double unitHeight = height / somHeight;

        DoubleMatrix2D unitDistanceMatrix = gsom.getLayer().getUnitDistanceMatrix();

        for (int col = 0; col < somWidth; col++) {
            for (int row = 0; row < somHeight; row++) {

                if (col < somWidth - 1) {
                    // draw horizontal connection
                    double distanceRight = unitDistanceMatrix.get(layer.getUnitIndex(col, row),
                            layer.getUnitIndex(col + 1, row));
                    g.setPaint(getColor(distanceRight));
                    int xPos = (int) (col * unitHeight + unitHeight * 0.7);
                    int yPos = (int) (row * unitWidth + unitWidth * 0.4);
                    g.fillRect(xPos, yPos, (int) (unitWidth * 0.6), (int) (unitHeight * 0.2));
                }

                if (row < somHeight - 1) {
                    // draw vertical connection
                    double distanceLower = unitDistanceMatrix.get(layer.getUnitIndex(col, row),
                            layer.getUnitIndex(col, row + 1));
                    g.setPaint(getColor(distanceLower));

                    int xPos = (int) (col * unitHeight + unitHeight * 0.4);
                    int yPos = (int) (row * unitWidth + unitWidth * 0.7);
                    g.fillRect(xPos, yPos, (int) (unitWidth * 0.2), (int) (unitHeight * 0.6));
                }
            }
        }

        return image;
    }

    /** Gets the colour representing a certain distance value. */
    private Color getColor(double distance) {
        if (distance <= t1) {
            return Color.BLACK;
        } else if (distance > t1 && distance <= t2) {
            return Color.GRAY;
        } else if (distance > t2 && distance <= t3) {
            return Color.LIGHT_GRAY;
        } else if (distance > t3) {
            return Color.WHITE;
        } else {
            throw new IllegalStateException("This can't happen.");
        }
    }

    public class ClusterConnectionsControlPanel extends VisualizationControlPanel implements ChangeListener {
        private static final long serialVersionUID = 1L;

        private JCheckBox instantUpdateCheckBox = new JCheckBox("Instant update", true);;

        private JLabel t1label;

        private JLabel t2label;

        private JLabel t3label;

        private JSlider t1slider;

        private JSlider t2slider;

        private JSlider t3slider;

        public ClusterConnectionsControlPanel() {
            super("Cluster Connections Control Panel");
            instantUpdateCheckBox.setToolTipText(
                    "Indicate whether the visualisation should be updated right away, or only at the end of the slider dragging");

            t1slider = new JSlider(0, 200, (int) (t1 * 100));
            t1slider.addChangeListener(this);
            t2slider = new JSlider(0, 200, (int) (t2 * 100));
            t2slider.addChangeListener(this);
            t3slider = new JSlider(0, 200, (int) (t3 * 100));
            t3slider.addChangeListener(this);

            t1label = new JLabel("t1: " + t1);
            t2label = new JLabel("t2: " + t2);
            t3label = new JLabel("t3: " + t3);

            JPanel panel = new JPanel(new GridBagLayout());
            GridBagConstraintsIFS gc = new GridBagConstraintsIFS(GridBagConstraints.NORTHWEST,
                    GridBagConstraints.HORIZONTAL);
            panel.add(instantUpdateCheckBox, gc.nextRow());
            panel.add(t1label, gc.nextRow());
            panel.add(t1slider, gc.nextRow());
            panel.add(t2label, gc.nextRow());
            panel.add(t2slider, gc.nextRow());
            panel.add(t3label, gc.nextRow());
            panel.add(t3slider, gc.nextRow());
            add(panel, c);
        }

        /*** Handles state changes of sliders control. */
        @Override
        public void stateChanged(ChangeEvent event) {
            JSlider source = (JSlider) event.getSource();

            if (source.equals(t1slider)) {
                if (t2slider.getValue() < t1slider.getValue()) {
                    t2slider.setValue(source.getValue());
                }
                if (instantUpdateCheckBox.isSelected() || !source.getValueIsAdjusting()) {
                    t1 = t1slider.getValue() / 100d;
                    t1label.setText("t1: " + t1);
                }
            } else if (source.equals(t2slider)) {
                if (t3slider.getValue() < t2slider.getValue()) {
                    t3slider.setValue(t2slider.getValue());
                }
                if (t1slider.getValue() > t2slider.getValue()) {
                    t1slider.setValue(t2slider.getValue());
                }
                if (instantUpdateCheckBox.isSelected() || !source.getValueIsAdjusting()) {
                    t2 = t2slider.getValue() / 100d;
                    t2label.setText("t2: " + t2);
                }
            } else if (source.equals(t3slider)) {
                if (t2slider.getValue() > t3slider.getValue()) {
                    t2slider.setValue(t3slider.getValue());
                }
                if (instantUpdateCheckBox.isSelected() || !source.getValueIsAdjusting()) {
                    t3 = t3slider.getValue() / 100d;
                    t3label.setText("t3: " + t3);
                }
            }
            if (instantUpdateCheckBox.isSelected() || !source.getValueIsAdjusting()) {
                visualizationUpdateListener.updateVisualization();
            }
        }
    }

    @Override
    public HashMap<String, BufferedImage> getVisualizationFlavours(int index, GrowingSOM gsom, int width,
            int height) throws SOMToolboxException {
        HashMap<String, BufferedImage> res = new HashMap<String, BufferedImage>();
        // modify t1 0.7 - 0.9
        // modify t2 1.0 - 1.2
        // modify t3 1.5 - 1.7
        double oldT1 = t1; // save original values
        double oldT2 = t2;
        double oldT3 = t3;

        double stepWidth = 0.05;
        for (t1 = 0.7; MathUtils.round(t1, 2) <= 0.9; t1 += stepWidth) {
            for (t2 = Math.max(t1, 1.0); MathUtils.round(t2, 2) <= 1.2; t2 += stepWidth) {
                for (t3 = Math.max(t2, 1.5); MathUtils.round(t3, 2) <= 1.7; t3 += stepWidth) {
                    String key = String.format("_%.2f_%.2f_%.2f", t1, t2, t3);
                    res.put(key, getVisualization(index, gsom, width, height));
                }
            }
        }

        t1 = oldT1; // reset to original values
        t2 = oldT2;
        t3 = oldT3;

        return res;
    }

    @Override
    public HashMap<String, BufferedImage> getVisualizationFlavours(int index, GrowingSOM gsom, int width,
            int height, int maxFlavours) throws SOMToolboxException {
        // TODO Auto-generated method stub
        return super.getVisualizationFlavours(index, gsom, width, height, maxFlavours);
    }

    @Override
    public HashMap<String, BufferedImage> getVisualizationFlavours(int index, GrowingSOM gsom, int width,
            int height, Map<String, String> flavourParameters) throws SOMToolboxException {
        // FIXME: Implement this
        return super.getVisualizationFlavours(index, gsom, width, height, flavourParameters);
    }

}