umontreal.ssj.charts.ScatterChart.java Source code

Java tutorial

Introduction

Here is the source code for umontreal.ssj.charts.ScatterChart.java

Source

/*
 * Class:        ScatterChart
 * Description:  
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Universite de Montreal
 * Organization: DIRO, Universite de Montreal
 * @author       
 * @since
 *
 *
 * 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 umontreal.ssj.charts;

import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYDotRenderer;
import org.jfree.data.xy.XYSeriesCollection;
import java.util.Locale;
import java.util.Formatter;
import cern.colt.list.DoubleArrayList;
import javax.swing.JFrame;

/**
 * This class provides tools to create and manage scatter plots. Using the
 * @ref ScatterChart class is the simplest way to produce scatter plots only.
 * Each  @ref ScatterChart object is linked with a
 * @ref umontreal.ssj.charts.XYListSeriesCollection data set.
 *
 * <div class="SSJ-bigskip"></div>
 */
public class ScatterChart extends XYChart {

    protected void init(String title, String XLabel, String YLabel) {
        // create the chart...
        chart = ChartFactory.createScatterPlot(title, // chart title
                XLabel, // x axis label
                YLabel, // y axis label
                dataset.getSeriesCollection(), // data
                PlotOrientation.VERTICAL, true, // include legend
                true, // tooltips
                false // urls
        );

        ((XYPlot) chart.getPlot()).setRenderer(dataset.getRenderer());
        // Initialize axis variables
        initAxis();

        int nb = getSeriesCollection().getSeriesCollection().getSeriesCount();
        for (int i = 0; i < nb; i++) {
            getSeriesCollection().setDashPattern(i, "only marks");
            getSeriesCollection().setMarksType(i, "+");
        }
    }

    protected void initAxis() {
        XAxis = new Axis((NumberAxis) ((XYPlot) chart.getPlot()).getDomainAxis(), Axis.ORIENTATION_HORIZONTAL);
        YAxis = new Axis((NumberAxis) ((XYPlot) chart.getPlot()).getRangeAxis(), Axis.ORIENTATION_VERTICAL);
        setAutoRange(true, true);
    }

    /**
     * Initializes a new `ScatterChart` instance with an empty data set.
     */
    public ScatterChart() {
        super();
        dataset = new XYListSeriesCollection();
        init(null, null, null);
    }

    /**
     * Initializes a new `ScatterChart` instance with data `data`. `title`
     * is a title, `XLabel` is a short description of the @f$x@f$-axis and
     * `YLabel` a short description of the @f$y@f$-axis. The input
     * parameter `data` represents sets of plotting data. For example, if
     * one @f$n@f$-row matrix `data1` is given as argument `data`, then the
     * first row <tt>data1</tt>@f$[0]@f$ represents the @f$x@f$-coordinate
     * vector, and every other row <tt>data1</tt>@f$[i], i=1,, n-1@f$,
     * represents the @f$y@f$-coordinates of a set of points. Therefore
     * matrix `data1` corresponds to @f$n-1@f$ sets of points, all with the
     * same @f$x@f$-coordinates. However, one may want to plot sets of
     * points with different @f$x@f$-coordinates. In that case, one should
     * give the points as matrices with two rows. For examples, if the
     * argument `data` is made of three 2-row matrices `data1`, `data2` and
     * `data3`, then they represents three different sets of points,
     * <tt>data*</tt>@f$[0]@f$ giving the @f$x@f$-coordinates, and
     * <tt>data*</tt>@f$[1]@f$ the @f$y@f$-coordinates of the points.
     *  @param title        chart title.
     *  @param XLabel       Label on @f$x@f$-axis.
     *  @param YLabel       Label on @f$y@f$-axis.
     *  @param data         series of point sets.
     */
    public ScatterChart(String title, String XLabel, String YLabel, double[][]... data) {
        super();
        dataset = new XYListSeriesCollection(data);
        init(title, XLabel, YLabel);
    }

    /**
     * Initializes a new `ScatterChart` instance with sets of points
     * `data`. `title` is a title, `XLabel` is a short description of the
     * @f$x@f$-axis, and `YLabel` a short description of the @f$y@f$-axis.
     * If `data` is a @f$n@f$-row matrix, then the first row
     * <tt>data</tt>@f$[0]@f$ represents the @f$x@f$-coordinate vector, and
     * every other row <tt>data</tt>@f$[i], i=1,, n-1@f$, represents a
     * @f$y@f$-coordinate vector. Therefore matrix <tt>data</tt>@f$[i][
     * ]@f$, @f$i=0,, n-1@f$, corresponds to @f$n-1@f$ sets of points, all
     * with the same @f$x@f$-coordinates. However, only *the first*
     * `numPoints` of each set <tt>data</tt>@f$[i]@f$ (i.e. the first
     * `numPoints` columns of each row) will be plotted.
     *  @param title        chart title.
     *  @param XLabel       Label on @f$x@f$-axis.
     *  @param YLabel       Label on @f$y@f$-axis.
     *  @param data         series of point sets.
     *  @param numPoints    Number of points to plot
     */
    public ScatterChart(String title, String XLabel, String YLabel, double[][] data, int numPoints) {
        super();
        dataset = new XYListSeriesCollection(data, numPoints);
        init(title, XLabel, YLabel);
    }

    /**
     * Initializes a new `ScatterChart` instance using subsets of `data`.
     * `data[x][.]` will form the @f$x@f$-coordinates and `data[y][.]` will
     * form the @f$y@f$-coordinates of the chart. `title` sets a title,
     * `XLabel` is a short description of the @f$x@f$-axis, and `YLabel` is
     * a short description of the @f$y@f$-axis. Warning: if the new
     * @f$x@f$-axis coordinates are not monotone increasing, then they will
     * automatically be sorted in increasing order so the points will be
     * reordered, but the original `data` is not changed.
     *  @param title        chart title.
     *  @param XLabel       Label on @f$x@f$-axis.
     *  @param YLabel       Label on @f$y@f$-axis.
     *  @param data         series of point sets.
     *  @param x            Index of data forming the @f$x@f$-coordinates
     *  @param y            Index of data forming the @f$y@f$-coordinates
     */
    public ScatterChart(String title, String XLabel, String YLabel, double[][] data, int x, int y) {
        super();
        int len = data[0].length;
        double[][] proj = new double[2][len];
        for (int i = 0; i < len; i++) {
            proj[0][i] = data[x][i];
            proj[1][i] = data[y][i];
        }
        dataset = new XYListSeriesCollection(proj);
        init(title, XLabel, YLabel);
    }

    /**
     * Initializes a new `ScatterChart` instance with data `data`. The
     * input parameter `data` represents a set of plotting data. A
     * DoubleArrayList from the Colt library is used to store the data. The
     * description is similar to the above constructor with `double[]...
     * data`.
     *  @param title        chart title.
     *  @param XLabel       Label on @f$x@f$-axis.
     *  @param YLabel       Label on @f$y@f$-axis.
     *  @param data         series of point sets.
     */
    public ScatterChart(String title, String XLabel, String YLabel, DoubleArrayList... data) {
        super();
        dataset = new XYListSeriesCollection(data);
        init(title, XLabel, YLabel);
    }

    /**
     * Initializes a new `ScatterChart` instance with data `data`. The
     * input parameter `data` represents a set of plotting data.
     * @ref org.jfree.data.xy.XYSeriesCollection is a `JFreeChart`
     * container class to store @f$XY@f$ plots.
     *  @param title        chart title.
     *  @param XLabel       Label on @f$x@f$-axis.
     *  @param YLabel       Label on @f$y@f$-axis.
     *  @param data         series collection.
     */
    public ScatterChart(String title, String XLabel, String YLabel, XYSeriesCollection data) {
        super();
        dataset = new XYListSeriesCollection(data);
        init(title, XLabel, YLabel);
    }

    /**
     * Adds a data series into the series collection. Vector `x` represents
     * the @f$x@f$-coordinates and vector `y` represents the
     * @f$y@f$-coordinates of the series. `name` and `plotStyle` are the
     * name and the plot style associated to the series.
     *  @param x            @f$x_i@f$ coordinates.
     *  @param y            @f$y_i@f$ coordinates.
     *  @param name         Name of the series.
     *  @param plotStyle    Plot style of the series.
     *  @return Integer that represent the new point sets position in the
     * JFreeChart `XYSeriesCollection` object.
     */
    public int add(double[] x, double[] y, String name, String plotStyle) {
        int seriesIndex = add(x, y);
        getSeriesCollection().setName(seriesIndex, name);
        getSeriesCollection().setPlotStyle(seriesIndex, plotStyle);
        return seriesIndex;
    }

    /**
     * Adds a data series into the series collection. Vector `x` represents
     * the @f$x@f$-coordinates and vector `y` represents the
     * @f$y@f$-coordinates of the series.
     *  @param x            @f$x_i@f$ coordinates.
     *  @param y            @f$y_i@f$ coordinates.
     *  @return Integer that represent the new point sets position in the
     * JFreeChart `XYSeriesCollection` object.
     */
    public int add(double[] x, double[] y) {
        return add(x, y, x.length);
    }

    /**
     * Adds a data series into the series collection. Vector `x` represents
     * the @f$x@f$-coordinates and vector `y` represents the
     * @f$y@f$-coordinates of the series. Only *the first* `numPoints` of
     * `x` and `y` will be taken into account for the new series.
     *  @param x            @f$x_i@f$ coordinates.
     *  @param y            @f$y_i@f$ coordinates.
     *  @param numPoints    Number of points to add.
     *  @return Integer that represent the new point sets position in the
     * JFreeChart `XYSeriesCollection` object.
     */
    public int add(double[] x, double[] y, int numPoints) {
        int seriesIndex = getSeriesCollection().add(x, y, numPoints);
        initAxis();
        getSeriesCollection().setMarksType(seriesIndex, "+");
        getSeriesCollection().setDashPattern(seriesIndex, "only marks");
        return seriesIndex;
    }

    /**
     * Returns the charts dataset.
     *  @return the charts dataset.
     */
    public XYListSeriesCollection getSeriesCollection() {
        return (XYListSeriesCollection) dataset;
    }

    /**
     * Links a new dataset to the current chart.
     *  @param dataset      new dataset.
     */
    public void setSeriesCollection(XYListSeriesCollection dataset) {
        this.dataset = dataset;
    }

    /**
     * Synchronizes @f$X@f$-axis ticks to the @f$s@f$-th series
     * @f$x@f$-values.
     *  @param s            series used to define ticks.
     */
    public void setTicksSynchro(int s) {
        XYSeriesCollection seriesCollection = (XYSeriesCollection) this.dataset.getSeriesCollection();
        double[] values = new double[seriesCollection.getItemCount(s)];

        for (int i = 0; i < seriesCollection.getItemCount(s); i++)
            values[i] = seriesCollection.getXValue(s, i);

        XAxis.setLabels(values);
    }

    /**
     * Displays chart on the screen using Swing. This method creates an
     * application containing a chart panel displaying the chart. The
     * created frame is positioned on-screen, and displayed before it is
     * returned. The `width` and the `height` of the chart are measured in
     * pixels.
     *  @param width        frame width in pixels.
     *  @param height       frame height in pixels.
     *  @return frame containing the chart.
     *
     * ;
     */
    public JFrame view(int width, int height) {
        JFrame myFrame;
        if (chart.getTitle() != null)
            myFrame = new JFrame("ScatterChart from SSJ: " + chart.getTitle().getText());
        else
            myFrame = new JFrame("ScatterChart from SSJ");
        XYPlot plot = chart.getXYPlot();

        /*    // The drawn points are somewhat big, of different shapes, unfilled
              XYLineAndShapeRenderer shape = new XYLineAndShapeRenderer(false, true);
              int nb = getSeriesCollection().getSeriesCollection().getSeriesCount();
              for (int i = 0 ; i < nb ; i++) {
                 shape.setSeriesShapesFilled(i, false);
                 plot.setRenderer(i, shape);
              }
        */
        // The drawn points are all square, filled
        XYDotRenderer shape = new XYDotRenderer();
        final int dotSize = 3;
        shape.setDotWidth(dotSize);
        shape.setDotHeight(dotSize);
        int nb = getSeriesCollection().getSeriesCollection().getSeriesCount();
        for (int i = 0; i < nb; i++)
            plot.setRenderer(i, shape);

        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(width, height));
        myFrame.setContentPane(chartPanel);
        myFrame.pack();
        myFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        myFrame.setLocationRelativeTo(null);
        myFrame.setVisible(true);
        return myFrame;
    }

    /**
     * @name LaTex-specific method
     * @{
     */
    public String toLatex(double width, double height) {
        double xunit = 0, yunit = 0;
        double[] save = new double[4];

        if (dataset.getSeriesCollection().getSeriesCount() == 0)
            throw new IllegalArgumentException("Empty chart");

        //Calcul des parametres d'echelle et de decalage
        double XScale = computeXScale(XAxis.getTwinAxisPosition());
        double YScale = computeYScale(YAxis.getTwinAxisPosition());

        //taille d'une unite en x et en cm dans l'objet "tikzpicture"
        xunit = width / ((Math.max(XAxis.getAxis().getRange().getUpperBound(), XAxis.getTwinAxisPosition())
                * XScale)
                - (Math.min(XAxis.getAxis().getRange().getLowerBound(), XAxis.getTwinAxisPosition()) * XScale));
        //taille d'une unite en y et en cm dans l'objet "tikzpicture"
        yunit = height / ((Math.max(YAxis.getAxis().getRange().getUpperBound(), YAxis.getTwinAxisPosition())
                * YScale)
                - (Math.min(YAxis.getAxis().getRange().getLowerBound(), YAxis.getTwinAxisPosition()) * YScale));

        Formatter formatter = new Formatter(Locale.US);

        /*Entete du document*/
        if (latexDocFlag) {
            formatter.format("\\documentclass[12pt]{article}%n%n");
            formatter.format("\\usepackage{tikz}%n\\usetikzlibrary{plotmarks}%n\\begin{document}%n%n");
        }
        if (chart.getTitle() != null)
            formatter.format("%% PGF/TikZ picture from SSJ: %s%n", chart.getTitle().getText());
        else
            formatter.format("%% PGF/TikZ picture from SSJ %n");
        formatter.format("%% XScale = %s,  YScale = %s,  XShift = %s,  YShift = %s%n", XScale, YScale,
                XAxis.getTwinAxisPosition(), YAxis.getTwinAxisPosition());
        formatter.format("%% Therefore, thisFileXValue = (originalSeriesXValue+XShift)*XScale%n");
        formatter.format("%%        and thisFileYValue = (originalSeriesYValue+YShift)*YScale%n%n");
        if (chart.getTitle() != null)
            formatter.format("\\begin{figure}%n");
        formatter.format("\\begin{center}%n");
        formatter.format("\\begin{tikzpicture}[x=%scm, y=%scm]%n", xunit, yunit);
        formatter.format("\\footnotesize%n");
        if (grid)
            formatter.format("\\draw[color=lightgray] (%s, %s) grid[xstep = %s, ystep=%s] (%s, %s);%n",
                    (Math.min(XAxis.getAxis().getRange().getLowerBound(), XAxis.getTwinAxisPosition())
                            - XAxis.getTwinAxisPosition()) * XScale,
                    (Math.min(YAxis.getAxis().getRange().getLowerBound(), YAxis.getTwinAxisPosition())
                            - YAxis.getTwinAxisPosition()) * YScale,
                    xstepGrid * XScale, ystepGrid * YScale,
                    (Math.max(XAxis.getAxis().getRange().getUpperBound(), XAxis.getTwinAxisPosition())
                            - XAxis.getTwinAxisPosition()) * XScale,
                    (Math.max(YAxis.getAxis().getRange().getUpperBound(), YAxis.getTwinAxisPosition())
                            - YAxis.getTwinAxisPosition()) * YScale);
        setTick0Flags();
        formatter.format("%s", XAxis.toLatex(XScale));
        formatter.format("%s", YAxis.toLatex(YScale));

        formatter.format("%s",
                dataset.toLatex(XScale, YScale, XAxis.getTwinAxisPosition(), YAxis.getTwinAxisPosition(),
                        XAxis.getAxis().getLowerBound(), XAxis.getAxis().getUpperBound(),
                        YAxis.getAxis().getLowerBound(), YAxis.getAxis().getUpperBound()));

        formatter.format("\\end{tikzpicture}%n");
        formatter.format("\\end{center}%n");
        if (chart.getTitle() != null) {
            formatter.format("\\caption{");
            formatter.format(chart.getTitle().getText());
            formatter.format("}%n\\end{figure}%n");
        }
        if (latexDocFlag)
            formatter.format("\\end{document}%n");
        return formatter.toString();
    }

}

/**
 * @}
 */