/*
* 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.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import cern.colt.matrix.DoubleMatrix2D;
import cern.colt.matrix.impl.DenseDoubleMatrix2D;
import at.tuwien.ifs.somtoolbox.SOMToolboxException;
import at.tuwien.ifs.somtoolbox.data.InputData;
import at.tuwien.ifs.somtoolbox.data.InputDatum;
import at.tuwien.ifs.somtoolbox.data.SOMVisualisationData;
import at.tuwien.ifs.somtoolbox.layers.metrics.L2Metric;
import at.tuwien.ifs.somtoolbox.models.GrowingSOM;
import at.tuwien.ifs.somtoolbox.util.VectorTools;
/**
* This is the implementation of an Activity Histogram.<br>
* FIXME: there are a lot of common parts with {@link ComponentPlanesVisualizer} ==> make a superclass for both of them.
*
* @author Roman Gerger
* @author Florian Mistelbauer
* @author Rudolf Mayer
* @version $Id: ActivityHistogram.java 3849 2010-10-12 12:56:45Z frank $
*/
class ActivityHistogram extends AbstractItemVisualizer {
private String dataPoint;
private InputData inputData;
public ActivityHistogram() {
NUM_VISUALIZATIONS = 1;
VISUALIZATION_NAMES = new String[] { "Activity Histogram" };
VISUALIZATION_SHORT_NAMES = new String[] { "ActivityHistogram" };
VISUALIZATION_DESCRIPTIONS = new String[] { "Displays a colour-coding of the activity of a certain input vector over the whole map, i.e. in principle the vector's distances to all weight vectors.\nImplemented by Roman Gerger and Florian Mistelbauer" };
neededInputObjects = new String[] { SOMVisualisationData.INPUT_VECTOR };
setInterpolate(false);
}
@Override
protected String getCacheKey(GrowingSOM gsom, int index, int width, int height) {
return super.getCacheKey(gsom, index, width, height) + CACHE_KEY_SECTION_SEPARATOR + "input:" + dataPoint;
}
/**
* Draws the activity histogram. Given one input point it calculates the Euclidian distance to each weight vector.
*
* @throws SOMToolboxException If the {@link InputData} is not provided
*/
@Override
public BufferedImage createVisualization(int index, GrowingSOM gsom, int width, int height)
throws SOMToolboxException {
if (inputData == null) {
inputData = gsom.getSharedInputObjects().getInputData();
if (inputData == null) {
throw new SOMToolboxException("You need to specify the " + neededInputObjects[0]);
} else {
dataPoint = inputData.getInputDatum(0).getLabel();
}
}
if (!(controlPanel instanceof ActivityHistrogramControlPanel)) {
// create control panel once we have the input data vector, and if it is a generic panel
controlPanel = new ActivityHistrogramControlPanel(this, inputData);
}
// read the vector file to fetch the necessary data
InputDatum item = inputData.getInputDatum(dataPoint);
L2Metric metric = new L2Metric();
// calculate the distance matrix
// FIXME: maybe move the computation to GrowingLayer
DoubleMatrix2D plane = new DenseDoubleMatrix2D(gsom.getLayer().getYSize(), gsom.getLayer().getXSize());
for (int y = 0; y < gsom.getLayer().getYSize(); y++) {
for (int x = 0; x < gsom.getLayer().getXSize(); x++) {
plane.set(y, x, metric.distance(gsom.getLayer().getUnit(x, y).getWeightVector(), item));
}
}
// normalise distances, create image from matrix
VectorTools.divByMax(plane);
return createImage(gsom, plane, width, height, interpolate);
}
/** Implements the control UI for this visualisation. */
private class ActivityHistrogramControlPanel extends AbstractSelectedItemVisualizerControlPanel implements
ListSelectionListener {
private static final long serialVersionUID = 1L;
private ActivityHistrogramControlPanel(ActivityHistogram hist, InputData inputData) {
super("Activity Histogram Control");
JPanel histPanel = new JPanel(new GridBagLayout());
GridBagConstraints constr = new GridBagConstraints();
constr.gridwidth = GridBagConstraints.REMAINDER;
constr.fill = GridBagConstraints.BOTH;
constr.weightx = 1.0;
constr.weighty = 1.0;
initialiseList(inputData.getLabels());
JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(map.getState().controlElementsWidth, 150));
listScroller.setMaximumSize(new Dimension(map.getState().controlElementsWidth, 150));
histPanel.add(listScroller, constr);
text.setToolTipText("Enter a (part) of an input vector label, and start the search with the <enter> key");
text.setText(dataPoint);
histPanel.add(text, constr);
add(histPanel, c);
setVisible(true);
}
@Override
public void componentResized(ComponentEvent e) {
// setBorder(BorderFactory.createLineBorder(Color.green));
super.componentResized(e);
// updateListSize(list, getHeight(), inputData.numVectors());
}
@Override
public void valueChanged(ListSelectionEvent e) {
dataPoint = (String) list.getSelectedValue();
if (visualizationUpdateListener != null) {
visualizationUpdateListener.updateVisualization();
}
}
@Override
public Dimension getMinimumSize() {
return new Dimension(map.getState().controlElementsWidth, 300);
}
}
@Override
public HashMap<String, BufferedImage> getVisualizationFlavours(int index, GrowingSOM gsom, int width, int height)
throws SOMToolboxException {
return getVisualizationFlavours(index, gsom, width, height,
gsom.getSharedInputObjects().getInputData().numVectors());
}
@Override
public HashMap<String, BufferedImage> getVisualizationFlavours(int index, GrowingSOM gsom, int width, int height,
int maxFlavours) throws SOMToolboxException {
String currentDataPoint = dataPoint;
InputData currentInputData = inputData;
HashMap<String, BufferedImage> result = new HashMap<String, BufferedImage>();
String[] labels = gsom.getSharedInputObjects().getInputData().getLabels();
inputData = gsom.getSharedInputObjects().getInputData();
for (int i = 0; i < labels.length && i < maxFlavours; i++) {
dataPoint = inputData.getInputDatum(i).getLabel();
result.put("_" + labels[i], getVisualization(index, gsom, width, height));
}
dataPoint = currentDataPoint;
inputData = currentInputData;
return result;
}
@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);
}
}