org.jls.toolbox.math.chart.XYBlockChart.java Source code

Java tutorial

Introduction

Here is the source code for org.jls.toolbox.math.chart.XYBlockChart.java

Source

/*#
 * The MIT License (MIT)
 * 
 * Copyright (c) 2016 LE SAUCE Julien
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 #*/

package org.jls.toolbox.math.chart;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;

import javax.swing.JLabel;
import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.GrayPaintScale;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jls.toolbox.math.Point;

/**
 * Permet de crer un graphique en deux dimensions mais  3 variables. En effet,
 * le graphique se prsente comme un simple graphique en deux dimensions mais la
 * troisme dimension est reprsente par une chelle de couleur.
 * 
 * @author LE SAUCE Julien
 * @date Feb 13, 2015
 */
public class XYBlockChart {

    private final Color CHART_BACKGROUND_COLOR = new JPanel().getBackground();
    private final Color CHART_FOREGROUND_COLOR = new JLabel().getForeground();
    private final Color CROSSHAIR_COLOR = Color.BLUE;

    private final String title; // Titre du graphique
    private final String xTitle; // Titre de l'axe des abscisses
    private final String yTitle; // Titre de l'axe des ordonnes
    private final String zTitle; // Titre de l'axe des z
    private final XYZDataset dataset; // Les donnes affiches dans le graphique

    private JFreeChart chart; // Le graphique
    private XYPlot plot; // La zone de dessin des courbes
    private XYBlockRenderer renderer; // Renderer de la courbe
    private PaintScaleLegend scaleLegend; // Echelle des couleurs du graphique

    /**
     * Permet d'instancier un graphique en blocs.
     * 
     * @param title
     *            Titre du graphique.
     * @param xAxisLabel
     *            Titre de l'axe des abcisses.
     * @param yAxisLabel
     *            Titre de l'axe des ordonnes.
     * @param zAxisLabel
     *            Titre de l'chelle de couleurs.
     * @param dataset
     *            Donnes associes au graphique.
     */
    public XYBlockChart(String title, String xAxisLabel, String yAxisLabel, String zAxisLabel, XYZDataset dataset) {
        this.title = title;
        this.xTitle = xAxisLabel;
        this.yTitle = yAxisLabel;
        this.zTitle = zAxisLabel;
        this.dataset = dataset;

        createChart();
        setChartStyle();
    }

    /**
     * Permet de modifier l'chelle de couleur utilise par le graphique. Cela
     * va crer un gradient de couleur entre les deux couleurs spcifies, la
     * premire couleur correspondant aux valeurs les plus fortes de l'chelle
     * des donnes  reprsenter. Les bornes infrieure et suprieure permettent
     * de prciser l'tendue des donnes reprsentes par cette chelle de
     * couleur.
     * 
     * @param colorMin
     *            Couleur d'arrive du gradient reprsentant les plus faibles
     *            valeurs de l'chelle.
     * @param colorMax
     *            Couleur de dpart du gradient reprsentant les plus fortes
     *            valeurs de l'chelle.
     * @param lowerBound
     *            Borne infrieure de l'chelle des donnes reprsentes.
     * @param upperBound
     *            Bornes suprieure de l'chelle des donnes reprsentes.
     */
    public void setColorGradient(Color colorMin, Color colorMax, double lowerBound, double upperBound) {
        LookupPaintScale scale = new LookupPaintScale(lowerBound, upperBound, Color.lightGray);
        double r1, r2, dr, g1, g2, dg, b1, b2, db;
        int nbVal = (int) (upperBound - lowerBound + 0.5);

        // Acquisition des composantes
        r1 = colorMax.getRed();
        g1 = colorMax.getGreen();
        b1 = colorMax.getBlue();
        r2 = colorMin.getRed();
        g2 = colorMin.getGreen();
        b2 = colorMin.getBlue();

        // Calcul du delta entre les composantes
        dr = (r2 - r1) / nbVal;
        dg = (g2 - g1) / nbVal;
        db = (b2 - b1) / nbVal;

        // Cration du gradient
        for (int i = 0; i < nbVal; i++) {
            scale.add(lowerBound + i, new Color((int) r2, (int) g2, (int) b2));
            r2 = r2 - dr;
            g2 = g2 - dg;
            b2 = b2 - db;
        }

        // Mise  jour du graphique
        this.renderer.setPaintScale(scale);
        this.scaleLegend.setScale(scale);

        // Du fait que la lgende n'est pas lie aux modifications de la courbe,
        // il faut rcrer la lgende  la main.
        this.chart.removeSubtitle(this.scaleLegend);
        createPaintScaleLegend(scale);
    }

    /**
     * Permet d'ajuster automatiquement l'chelle de couleur de la courbe en
     * fonction des donnes affiches.
     * 
     * @param colorMin
     *            Permet de spcifier la couleur associe  la valeur maximale.
     * @param colorMax
     *            Permet de spcifier la couleur associe  la valeur minimale.
     * @return Renvoie un Point contenant la valeur du minimum et du maximum
     *         dtects.
     */
    public Point adjustColorScale(Color colorMin, Color colorMax) {
        double min = 0, max = 0;
        // S'il y a bien des donnes
        if (this.dataset.getItemCount(0) > 0) {
            min = this.dataset.getZValue(0, 0);
            max = this.dataset.getZValue(0, 0);
            // Recherche du min/max
            for (int i = 0; i < this.dataset.getItemCount(0); i++) {
                double value = this.dataset.getZValue(0, i);
                if (value < min) {
                    min = value;
                }
                if (value > max) {
                    max = value;
                }
            }
            // Mise  jour de l'chelle
            if (max - min > 2000000) {
                throw new IllegalArgumentException("Too much values");
            }
            setColorGradient(colorMin, colorMax, min, max);
        }
        return new Point(min, max);
    }

    /**
     * Permet de modifier la largeur des blocs affichs par le renderer.
     * 
     * @param width
     *            Largeur en data/axis units.
     */
    public void setBlockWidth(double width) {
        this.renderer.setBlockWidth(width);
    }

    /**
     * Permet de crer le graphique  partir des paramtres spcifis.
     */
    private void createChart() {
        // Cration des axes
        NumberAxis xAxis = new NumberAxis(this.xTitle);
        xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        xAxis.setLabelFont(new Font("Dialog", Font.BOLD, 14));
        xAxis.setLowerMargin(0.0);
        xAxis.setUpperMargin(0.0);

        NumberAxis yAxis = new NumberAxis(this.yTitle);
        yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        yAxis.setLabelFont(new Font("Dialog", Font.BOLD, 14));
        yAxis.setLowerMargin(0.0);
        yAxis.setUpperMargin(0.0);

        this.renderer = new XYBlockRenderer();
        PaintScale scale = new GrayPaintScale(0, 10);
        this.renderer.setPaintScale(scale);

        // Cration de la courbe
        this.plot = new XYPlot(this.dataset, xAxis, yAxis, this.renderer);

        // Cration du graphique
        this.chart = new JFreeChart(this.title, this.plot);
        this.chart.removeLegend();

        createPaintScaleLegend(scale);
        setColorGradient(Color.yellow, Color.red, 0, 1);
    }

    /**
     * Permet de paramtrer le graphique une fois cr.
     */
    private void setChartStyle() {
        this.plot.setBackgroundAlpha((float) 0.0);
        this.plot.setDomainCrosshairLockedOnData(false);
        this.plot.setRangeCrosshairLockedOnData(false);
        this.plot.setDomainCrosshairVisible(true);
        this.plot.setRangeCrosshairVisible(true);
        this.plot.setRangeAxisLocation(AxisLocation.TOP_OR_LEFT);
        this.plot.setDomainGridlinesVisible(true);
        this.plot.setRangeGridlinesVisible(true);
        this.plot.setRangeGridlinePaint(Color.white);

        this.plot.setDomainCrosshairStroke(new BasicStroke(1f));
        this.plot.setRangeCrosshairStroke(new BasicStroke(1f));
        this.chart.setBackgroundPaint(this.CHART_BACKGROUND_COLOR);

        NumberAxis xAxis = (NumberAxis) this.plot.getDomainAxis();
        NumberAxis yAxis = (NumberAxis) this.plot.getRangeAxis();

        xAxis.setAxisLinePaint(this.CHART_FOREGROUND_COLOR);
        xAxis.setLabelPaint(this.CHART_FOREGROUND_COLOR);
        xAxis.setTickLabelPaint(this.CHART_FOREGROUND_COLOR);
        xAxis.setTickMarkPaint(this.CHART_FOREGROUND_COLOR);
        xAxis.setAutoRange(true);
        xAxis.setAutoRangeIncludesZero(false);

        yAxis.setAxisLinePaint(this.CHART_FOREGROUND_COLOR);
        yAxis.setLabelPaint(this.CHART_FOREGROUND_COLOR);
        yAxis.setTickLabelPaint(this.CHART_FOREGROUND_COLOR);
        yAxis.setTickMarkPaint(this.CHART_FOREGROUND_COLOR);
        yAxis.setAutoRange(true);
        yAxis.setAutoRangeIncludesZero(false);

        this.plot.setBackgroundPaint(this.CHART_FOREGROUND_COLOR);
        this.plot.setDomainGridlinePaint(this.CHART_FOREGROUND_COLOR);
        this.plot.setRangeGridlinePaint(this.CHART_FOREGROUND_COLOR);
        this.plot.setDomainCrosshairPaint(this.CROSSHAIR_COLOR);
        this.plot.setRangeCrosshairPaint(this.CROSSHAIR_COLOR);
    }

    /**
     * Permet de crer l'chelle de couleur du graphique.
     * 
     * @param scale
     *            Echelle de couleur utilise pour reprsenter les donnes.
     */
    private void createPaintScaleLegend(PaintScale scale) {
        NumberAxis axis = new NumberAxis(this.zTitle);
        axis.setLabelFont(new Font("Dialog", Font.BOLD, 14));
        this.scaleLegend = new PaintScaleLegend(scale, axis);
        this.scaleLegend.setPosition(RectangleEdge.RIGHT);
        this.scaleLegend.setAxisLocation(AxisLocation.TOP_OR_RIGHT);
        this.scaleLegend.setMargin(new RectangleInsets(0.0, 10.0, 25.0, 0.0));
        this.scaleLegend.setBackgroundPaint(this.CHART_BACKGROUND_COLOR);
        this.chart.addSubtitle(this.scaleLegend);
    }

    /**
     * Renvoie la courbe {@link JFreeChart} permettant d'tre ajoute  un
     * {@link ChartPanel}.
     * 
     * @return Courbe {@link JFreeChart}.
     */
    public JFreeChart getChart() {
        return this.chart;
    }
}