/* * 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 flanagan.interpolation.BiCubicSplineFast; import at.tuwien.ifs.somtoolbox.SOMToolboxException; import at.tuwien.ifs.somtoolbox.models.GrowingSOM; /** * visualizes counts (e.g. number of documents per unit) in an Islands of Music like manner, i.e. like SDH with s=1 * * @author Thomas Lidy * @version $Id: SmoothedCountHistograms.java 3590 2010-05-21 10:43:45Z mayer $ */ public class SmoothedCountHistograms extends AbstractMatrixVisualizer { double[][] sdh = null; // histogram (basis for visualization) int xSize = 0; int ySize = 0; double maxValue = 0; double minValue = Double.MAX_VALUE; public SmoothedCountHistograms() { NUM_VISUALIZATIONS = 2; } public void setHistogram(double[][] hist) { this.sdh = hist; // ((Histogram)smoothingCache[index].get(new Integer(s))).mh; this.normalize(); } private void normalize() { if (sdh == null) { return; } xSize = sdh.length; ySize = sdh[0].length; /** determine max and min value of matrices * */ for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { /* logarithmise */ if (sdh[x][y] > 0) { sdh[x][y] = Math.log(sdh[x][y]); } else if (sdh[x][y] < 0) { sdh[x][y] = -Math.log(-sdh[x][y]); } if (sdh[x][y] > maxValue) { maxValue = sdh[x][y]; } if (sdh[x][y] < minValue) { minValue = sdh[x][y]; } } } /** normalize histogram values * */ for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { sdh[x][y] = (sdh[x][y] - minValue) / (maxValue - minValue); } } } @Override public BufferedImage createVisualization(int index, GrowingSOM gsom, int width, int height) throws SOMToolboxException { if (sdh == null || sdh.length == 0) { throw new SOMToolboxException("No histogram data provided for SmoothedCountHistograms visualization!"); // must call setHistogram first! } int unitWidth = width / xSize; int unitHeight = height / ySize; BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) res.getGraphics(); int ci = 0; double paletteLim = palette.maxColourIndex(); if (index == 0) /* flat histogram color image */ { BufferedImage smallimg = new BufferedImage(xSize, ySize, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { ci = (int) (sdh[x][y] * paletteLim); smallimg.setRGB(x, y, palette.getColor(ci).getRGB()); } } g.drawImage(smallimg, 0, 0, width, height, Color.BLACK, null); // smallimg.getScaledInstance(width, height, BufferedImage.SCALE_DEFAULT); } else /* index == 1 ... sdh-like image */ { /** start bicubic spline stuff * */ double[] x1 = new double[xSize + 2]; x1[0] = 0; for (int x = 0; x < xSize; x++) { x1[x + 1] = x * unitWidth + unitWidth / 2; } x1[xSize + 1] = width; double[] x2 = new double[ySize + 2]; x2[0] = 0; for (int y = 0; y < ySize; y++) { x2[y + 1] = y * unitHeight + unitHeight / 2; } x2[ySize + 1] = height; double[][] sdhWithBorders = new double[xSize + 2][ySize + 2]; sdhWithBorders[0][0] = sdh[0][0] - (sdh[1][1] - sdh[0][0]) / 2; // top-left corner sdhWithBorders[xSize + 1][0] = sdh[xSize - 1][0] - (sdh[xSize - 2][1] - sdh[xSize - 1][0]) / 2; // top-right // corner sdhWithBorders[0][ySize + 1] = sdh[0][ySize - 1] - (sdh[1][ySize - 2] - sdh[0][ySize - 1]) / 2; // bottom-left // corner sdhWithBorders[xSize + 1][ySize + 1] = sdh[xSize - 1][ySize - 1] - (sdh[xSize - 2][ySize - 2] - sdh[xSize - 1][ySize - 1]) / 2; // bottom-right // corner for (int x = 1; x < xSize + 1; x++) { sdhWithBorders[x][0] = sdh[x - 1][0] - (sdh[x - 1][1] - sdh[x - 1][0]) / 2; // top row sdhWithBorders[x][ySize + 1] = sdh[x - 1][ySize - 1] - (sdh[x - 1][ySize - 2] - sdh[x - 1][ySize - 1]) / 2; // bottom row } for (int y = 1; y < ySize + 1; y++) { sdhWithBorders[0][y] = sdh[0][y - 1] - (sdh[1][y - 1] - sdh[0][y - 1]) / 2; // left column sdhWithBorders[xSize + 1][y] = sdh[xSize - 1][y - 1] - (sdh[xSize - 2][y - 1] - sdh[xSize - 1][y - 1]) / 2; // right column } for (int y = 0; y < ySize; y++) { for (int x = 0; x < xSize; x++) { sdhWithBorders[x + 1][y + 1] = sdh[x][y]; } } BiCubicSplineFast bcs = new BiCubicSplineFast(x1, x2, sdhWithBorders); // bcs.calcDeriv(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { ci = (int) Math.round(bcs.interpolate(x + 0.5, y + 0.5) * paletteLim); // limit ci value between 0 & max value ci = Math.min(palette.getNumberOfColours() - 1, Math.max(0, ci)); // check for mnemonic SOM: if a unit is empty and has a low value, or the unit has no neighbours // if ((ci < 3 && gsom.getLayer().getUnit(x/unitWidth, y/unitHeight) == null) || // !gsom.getLayer().hasNeighbours(x/unitWidth, // y/unitHeight)) { // g.setPaint(Color.WHITE); // we draw this position white // } else { // g.setPaint(palette.getColor(ci)); // } // g.fill(new Rectangle(x,y,1,1)); res.setRGB(x, y, palette.getColor(ci).getRGB()); } } /** end bicubic spline stuff * */ } return res; } }