/*******************************************************************************
 * Copyright (c) 2010 Haifeng Li
 *   
 * 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.apache.org/licenses/LICENSE-2.0
 *
 * 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 smile.plot;

import java.awt.Color;
import java.util.Arrays;
import smile.math.Math;
import smile.math.matrix.SparseMatrix;

/**
 * A graphical representation of sparse matrix data. Optionally, the values
 * in the matrix can be represented as colors.
 * 
 * @author Haifeng Li
 */
public class SparseMatrixPlot extends Plot {

    /**
     * The sparse matrix.
     */
    private SparseMatrix sparse;
    /**
     * The x coordinate of matrix entries.
     */
    private double[] x;
    /**
     * The y coordinate of matrix entries.
     */
    private double[] y;
    /**
     * The minimum of the data.
     */
    private double min;
    /**
     * The minimum of the data.
     */
    private double max;
    /**
     * The window width of values for each color.
     */
    private double width;
    /**
     * The color palette to represent values.
     */
    private Color[] palette;

    /**
     * Constructor. Use blue color for nonzero entries.
     */
    public SparseMatrixPlot(SparseMatrix sparse) {
        this(sparse, Color.BLUE);
    }

    /**
     * Constructor.
     */
    public SparseMatrixPlot(SparseMatrix sparse, Color color) {
        super(color);
        this.sparse = sparse;

        int m = sparse.nrows();
        int n = sparse.ncols();
        x = new double[n];
        for (int i = 0; i < x.length; i++) {
            x[i] = i + 0.5;
        }

        y = new double[m];
        for (int i = 0; i < y.length; i++) {
            y[i] = y.length - i - 0.5;
        }
    }

    /**
     * Constructor. Use jet color palette.
     * @param k the number of colors in the palette.
     */
    public SparseMatrixPlot(SparseMatrix sparse, int k) {
        this(sparse, Palette.jet(k, 1.0f));
    }

    /**
     * Constructor.
     * @param palette the color palette.
     */
    public SparseMatrixPlot(SparseMatrix sparse, Color[] palette) {
        this.sparse = sparse;
        this.palette = palette;

        int m = sparse.nrows();
        int n = sparse.ncols();
        x = new double[n];
        for (int i = 0; i < x.length; i++) {
            x[i] = i + 0.5;
        }

        y = new double[m];
        for (int i = 0; i < y.length; i++) {
            y[i] = y.length - i - 0.5;
        }

        min = Double.POSITIVE_INFINITY;
        max = Double.NEGATIVE_INFINITY;
        for (double z : sparse.values()) {
            if (z < min) {
                min = z;
            }
            if (z > max) {
                max = z;
            }
        }

        // In case of outliers, we use 1% and 99% quantiles as lower and
        // upper limits instead of min and max.
        double[] values = new double[sparse.size()];
        int i = 0;
        for (double z : sparse.values()) {
            if (!Double.isNaN(z)) {
                values[i++] = z;
            }
        }

        if (i > 0) {
            Arrays.sort(values, 0, i);
            min = values[(int) Math.round(0.01 * i)];
            max = values[(int) Math.round(0.99 * (i-1))];
            width = (max - min) / palette.length;
        }
    }

    @Override
    public void paint(Graphics g) {
        Color c = g.getColor();

        double[] start = new double[2];
        double[] end = new double[2];

        if (palette != null) {
            int m = sparse.nrows();
            int n = sparse.ncols();
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    double z = sparse.get(i, j);
                    if (z != 0.0 && !Double.isNaN(z)) {
                        int k = (int) ((z - min) / width);
                        
                        if (k < 0) {
                            k = 0;
                        }

                        if (k >= palette.length) {
                            k = palette.length - 1;
                        }
                        
                        g.setColor(palette[k]);

                        start[0] = x[j];
                        if (j == 0) {
                            start[0] -= Math.abs(x[j + 1] - x[j]) / 2;
                        } else {
                            start[0] -= Math.abs(x[j] - x[j - 1]) / 2;
                        }

                        start[1] = y[i];
                        if (i == 0) {
                            start[1] += Math.abs(y[i + 1] - y[i]) / 2;
                        } else {
                            start[1] += Math.abs(y[i] - y[i - 1]) / 2;
                        }

                        end[0] = x[j];
                        if (j == x.length - 1) {
                            end[0] += Math.abs(x[j] - x[j - 1]) / 2;
                        } else {
                            end[0] += Math.abs(x[j + 1] - x[j]) / 2;
                        }

                        end[1] = y[i];
                        if (i == y.length - 1) {
                            end[1] -= Math.abs(y[i] - y[i - 1]) / 2;
                        } else {
                            end[1] -= Math.abs(y[i + 1] - y[i]) / 2;
                        }
                        g.fillRect(start, end);
                    }
                }
            }
        } else {
            g.setColor(getColor());
            int m = sparse.nrows();
            int n = sparse.ncols();
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    double z = sparse.get(i, j);
                    if (z != 0.0) {
                        start[0] = x[j];
                        if (j == 0) {
                            start[0] -= Math.abs(x[j + 1] - x[j]) / 2;
                        } else {
                            start[0] -= Math.abs(x[j] - x[j - 1]) / 2;
                        }

                        start[1] = y[i];
                        if (i == 0) {
                            start[1] += Math.abs(y[i + 1] - y[i]) / 2;
                        } else {
                            start[1] += Math.abs(y[i] - y[i - 1]) / 2;
                        }

                        end[0] = x[j];
                        if (j == x.length - 1) {
                            end[0] += Math.abs(x[j] - x[j - 1]) / 2;
                        } else {
                            end[0] += Math.abs(x[j + 1] - x[j]) / 2;
                        }

                        end[1] = y[i];
                        if (i == y.length - 1) {
                            end[1] -= Math.abs(y[i] - y[i - 1]) / 2;
                        } else {
                            end[1] -= Math.abs(y[i + 1] - y[i]) / 2;
                        }
                        g.fillRect(start, end);
                    }
                }
            }
        }

        if (palette != null) {
            g.clearClip();

            double height = 0.7 / palette.length;
            start[0] = 1.1;
            start[1] = 0.15;
            end[0] = 1.13;
            end[1] = start[1] - height;

            for (int i = 0; i < palette.length; i++) {
                g.setColor(palette[i]);
                g.fillRectBaseRatio(start, end);
                start[1] += height;
                end[1] += height;
            }

            g.setColor(Color.BLACK);
            start[1] -= height;
            end[1] = 0.15 - height;
            g.drawRectBaseRatio(start, end);
            start[0] = 1.14;
            double log = Math.log10(Math.abs(max));
            int decimal = 1;
            if (log < 0) {
                decimal = (int) -log + 1;
            }
            g.drawTextBaseRatio(String.valueOf(Math.round(max, decimal)), 0.0, 1.0, start);

            start[1] = 0.15 - height;
            log = Math.log10(Math.abs(min));
            decimal = 1;
            if (log < 0) {
                decimal = (int) -log + 1;
            }
            g.drawTextBaseRatio(String.valueOf(Math.round(min, decimal)), 0.0, 0.0, start);
        }

        g.setColor(c);
    }

    /**
     * Create a sparse matrix plot canvas.
     * @param sparse a sparse matrix.
     */
    public static PlotCanvas plot(SparseMatrix sparse) {
        double[] lowerBound = {0, 0};
        double[] upperBound = {sparse.ncols(), sparse.nrows()};
        PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound, false);
        canvas.add(new SparseMatrixPlot(sparse));

        canvas.getAxis(0).setLabelVisible(false);
        canvas.getAxis(0).setGridVisible(false);
        canvas.getAxis(1).setLabelVisible(false);
        canvas.getAxis(1).setGridVisible(false);

        return canvas;
    }

    /**
     * Create a sparse matrix plot canvas.
     * @param sparse a sparse matrix.
     */
    public static PlotCanvas plot(SparseMatrix sparse, Color color) {
        double[] lowerBound = {0, 0};
        double[] upperBound = {sparse.ncols(), sparse.nrows()};
        PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound, false);
        canvas.add(new SparseMatrixPlot(sparse, color));

        canvas.getAxis(0).setLabelVisible(false);
        canvas.getAxis(0).setGridVisible(false);
        canvas.getAxis(1).setLabelVisible(false);
        canvas.getAxis(1).setGridVisible(false);

        return canvas;
    }

    /**
     * Create a sparse matrix plot canvas.
     * @param sparse a sparse matrix.
     */
    public static PlotCanvas plot(SparseMatrix sparse, Color[] palette) {
        double[] lowerBound = {0, 0};
        double[] upperBound = {sparse.ncols(), sparse.nrows()};
        PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound, false);
        canvas.add(new SparseMatrixPlot(sparse, palette));

        canvas.getAxis(0).setLabelVisible(false);
        canvas.getAxis(0).setGridVisible(false);
        canvas.getAxis(1).setLabelVisible(false);
        canvas.getAxis(1).setGridVisible(false);

        return canvas;
    }
}

 

Ads help maintain this website.