/* * 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.image.BufferedImage; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Hashtable; import java.util.Set; import org.jfree.util.PaintList; import at.tuwien.ifs.somtoolbox.SOMToolboxException; import at.tuwien.ifs.somtoolbox.apps.viewer.MapPNode; import at.tuwien.ifs.somtoolbox.data.SOMVisualisationData; import at.tuwien.ifs.somtoolbox.layers.LayerAccessException; import at.tuwien.ifs.somtoolbox.layers.Unit; import at.tuwien.ifs.somtoolbox.models.GrowingSOM; import at.tuwien.ifs.somtoolbox.visualization.thematicmap.RegionManager; import at.tuwien.ifs.somtoolbox.visualization.thematicmap.SOMRegion; /** * @author Martin Waitzbauer (0226025) * @version $Id: EntropyVisualizer.java 3587 2010-05-21 10:35:33Z mayer $ */ public class EntropyVisualizer extends AbstractMatrixVisualizer implements QualityMeasureVisualizer { private int zoom = MapPNode.DEFAULT_UNIT_WIDTH / preferredScaleFactor; double min_visible_class = 0; public final SOMRegion MAXENTROPY_REGION = null; public final SOMRegion MINENTROPY_REGION = null; protected Hashtable<String, RegionManager> regionCache = new Hashtable<String, RegionManager>(); private RegionManager regionManager; private ArrayList<Double> entropyclass_list = new ArrayList<Double>(); private ArrayList<HashMap<String, Integer>> entropyclassnames_list = new ArrayList<HashMap<String, Integer>>(); public EntropyVisualizer() { NUM_VISUALIZATIONS = 1; VISUALIZATION_NAMES = new String[] { "Entropy Visualiser" }; VISUALIZATION_SHORT_NAMES = new String[] { "Entropy", "PseudoSilhouetteVal", "SOMSilhouette" }; VISUALIZATION_DESCRIPTIONS = new String[] { "TODO!" }; neededInputObjects = new String[] { SOMVisualisationData.CLASS_INFO }; } @Override public BufferedImage createVisualization(int index, GrowingSOM gsom, int width, int height) throws SOMToolboxException { checkNeededObjectsAvailable(gsom); // need to set the zoom level for exports zoom = width / gsom.getLayer().getXSize(); BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = res.createGraphics(); int xSize = gsom.getLayer().getXSize(); int ySize = gsom.getLayer().getYSize(); PaintList paintList = inputObjects.getClassInfo().getPaintList(); String key = min_visible_class + "_" + width + "_" + height; g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); try { this.regionManager = new RegionManager(inputObjects.getClassInfo(), paintList, width, height, min_visible_class, zoom); for (int j = 0; j < ySize; j++) { for (int i = 0; i < xSize; i++) { Unit unit = gsom.getLayer().getUnit(i, j); if (unit != null && unit.getNumberOfMappedInputs() != 0) { this.regionManager.addNewRegion(unit); } } } this.regionManager.build(); this.regionCache.put(key, this.regionManager); } catch (LayerAccessException e) { e.printStackTrace(); return null; } this.regionManager = regionCache.get(key); this.fillRegions(index, g); this.regionManager.drawRegions(g); // System.out.print("RegionManagerregions: "+this.regionManager.regions.size()); return res; } /** * Fills the Regions * * @param index Index specifies the Class to be displayed, if index is set to -1, all the classes are painted */ public void fillRegions(int index, Graphics2D g) { double max = this.regionManager.getMaximumEntropyRegion().calculateEntropy(); double temp = 0.0; ArrayList<String[][]> temp_regionclassnames = new ArrayList<String[][]>(); for (int i = 0; i < this.regionManager.getRegions().size(); i++) { SOMRegion r = this.regionManager.getRegions().get(i); double c1 = r.calculateEntropy(); Color c = this.getBestFittingColor(c1, max); g.setColor(c); if (index > -1) { /* only Paint the specified ClassID */ if (r.resolveMainClassIndex(index) > -1) {/* check if the Current Region is populated wit at least 1 individual of the index class */ g.fillPolygon(r); temp_regionclassnames.add(r.getClasses()); temp += c1; } } else { // paint the full image g.fillPolygon(r); } } if (index > -1) {/*-1 is all classes by definition*/ this.entropyclass_list.add(temp); this.mergeClasses(temp_regionclassnames); } } /** * Spreads the current Region Entropy Error along the whole Palette Interval. (Entropy Error uses to be very small, * and thus generates only colors in a small interval) */ private Color getBestFittingColor(double c1, double max) { int x; if (c1 == max) { x = (int) Math.round(c1 / max * palette.maxColourIndex()); } else { x = (int) Math.round(c1 / max * palette.getNumberOfColours()); } // System.out.println("Farbe: "+x); return palette.getColor(x); } /** returns the maximum entropy regions value as double;F */ public double getMaximumEntropy() { return this.regionManager.getMaximumEntropyRegion().calculateEntropy(); } /** returns the minimum entropy regions value as double; */ public double getMinimumEntropy() { return this.regionManager.getMinimumEntropyRegion().calculateEntropy(); } /** returns the Maximum Entropy Region's Class Names */ public String[][] getMaximumEntropyRegionNames() { return this.regionManager.getMaximumEntropyRegion().getClasses(); } /** * returns the percentage of regions with 0 Entropy * * @return counter */ public double getPercOfZeroEntropyRegions() { double counter = 0; for (int i = 0; i < this.regionManager.getRegions().size(); i++) { SOMRegion r = this.regionManager.getRegions().get(i); if (r.calculateEntropy() == 0.0) { counter++; } } return counter / this.regionManager.getRegions().size() * 100; } /** returns the entropy for class with 'index' */ public double ClassEntropy(int index) { return this.entropyclass_list.get(index); } /** * helper method: go through all regions in the arraylist(all of which have the same index) and count classnames and * hits. * * @param target is an arraylist , containing all different Regions with the specified Class index as Main class */ private void mergeClasses(ArrayList<String[][]> target) { HashMap<String, Integer> hmap = new HashMap<String, Integer>(); for (int i = 0; i < target.size(); i++) { String[][] temp = target.get(i); for (int b = 0; b < temp.length; b++) { if (!hmap.containsKey(temp[b][0])) { hmap.put(temp[b][0], Integer.valueOf(temp[b][1])); } else { int c = hmap.get(temp[b][0]); c += Integer.valueOf(temp[b][1]); hmap.put(temp[b][0], c); } } } this.entropyclassnames_list.add(hmap); } /** * returns every other class+hits contained in the regions with classmembers from the given index, or null if index * exceeds the possible number of classes */ public String[][] ClassEntropyNames(int index) { HashMap<String, Integer> hmap = this.entropyclassnames_list.get(index); String[][] sarray = null; if (index <= this.inputObjects.getClassInfo().numClasses()) { sarray = new String[hmap.size()][2]; Set<String> set = hmap.keySet(); Collection<Integer> col = hmap.values(); String[] kString = set.toArray(new String[hmap.size()]); Integer[] vInt = col.toArray(new Integer[hmap.size()]); for (int i = 0; i < hmap.size(); i++) { sarray[i][0] = kString[i]; sarray[i][1] = String.valueOf(vInt[i]); } } return sarray; } }