/*******************************************************************************
* 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.stat.distribution.Distribution;
import smile.stat.distribution.DiscreteDistribution;
import smile.stat.distribution.GaussianDistribution;
/**
* A Q-Q plot ("Q" stands for quantile) is a probability plot, a kind of
* graphical method for comparing two probability distributions, by
* plotting their quantiles against each other. In addition, Q-Q plots
* can be used as a graphical means of estimating parameters in a
* location-scale family of distributions.
* @author Haifeng Li
*/
public class QQPlot extends Plot {
/**
* The coordinates of points.
*/
private double[][] data;
/**
* Constructor of one sample Q-Q plot to standard normal distribution.
*/
public QQPlot(double[] x) {
data = quantile(x, GaussianDistribution.getInstance());
}
/**
* Constructor of one sample Q-Q plot to given distribution.
*/
public QQPlot(double[] x, Distribution d) {
data = quantile(x, d);
}
/**
* Constructor of one sample Q-Q plot to given distribution.
*/
public QQPlot(int[] x, DiscreteDistribution d) {
data = quantile(x, d);
}
/**
* Constructor of two sample Q-Q plot.
*/
public QQPlot(double[] x, double[] y) {
data = quantile(x, y);
}
/**
* Constructor of two sample Q-Q plot.
*/
public QQPlot(int[] x, int[] y) {
data = quantile(x, y);
}
/**
* Generate the quantile-quantile pairs.
*/
private static double[][] quantile(double[] x, double[] y) {
Arrays.sort(x);
Arrays.sort(y);
int n = Math.min(x.length, y.length);
double[][] q = new double[n][2];
for (int i = 0; i < n; i++) {
double p = (i + 1) / (n + 1.0);
q[i][0] = x[(int) Math.round(p * x.length)];
q[i][1] = y[(int) Math.round(p * y.length)];
}
return q;
}
/**
* Generate the quantile-quantile pairs.
*/
private static double[][] quantile(int[] x, int[] y) {
Arrays.sort(x);
Arrays.sort(y);
int n = Math.min(x.length, y.length);
double[][] q = new double[n][2];
for (int i = 0; i < n; i++) {
double p = (i + 1) / (n + 1.0);
q[i][0] = x[(int) Math.round(p * x.length)];
q[i][1] = y[(int) Math.round(p * y.length)];
}
return q;
}
/**
* Generate the quantile-quantile pairs.
*/
private static double[][] quantile(double[] x, Distribution d) {
Arrays.sort(x);
int n = x.length;
double[][] q = new double[n][2];
for (int i = 0; i < n; i++) {
double p = (i + 1) / (n + 1.0);
q[i][0] = x[(int) Math.round(p * x.length)];
q[i][1] = d.quantile(p);
}
return q;
}
/**
* Generate the quantile-quantile pairs.
*/
private static double[][] quantile(int[] x, DiscreteDistribution d) {
Arrays.sort(x);
int n = x.length;
double[][] q = new double[n][2];
for (int i = 0; i < n; i++) {
double p = (i + 1) / (n + 1.0);
q[i][0] = x[(int) Math.round(p * x.length)];
q[i][1] = d.quantile(p);
}
return q;
}
@Override
public void paint(Graphics g) {
Color c = g.getColor();
g.setColor(getColor());
double[] lowerEnd = g.getLowerBound();
lowerEnd[0] = Math.min(lowerEnd[0], lowerEnd[1]);
lowerEnd[1] = lowerEnd[0];
double[] upperEnd = g.getUpperBound();
upperEnd[0] = Math.max(upperEnd[0], upperEnd[1]);
upperEnd[1] = upperEnd[0];
g.drawLine(lowerEnd, upperEnd);
for (int i = 0; i < data.length; i++) {
g.drawPoint('o', data[i]);
}
g.setColor(c);
}
/**
* Create a plot canvas with the one sample Q-Q plot to standard normal
* distribution. The x-axis is the quantiles of x and the y-axis is the
* quantiles of normal distribution.
* @param x a sample set.
*/
public static PlotCanvas plot(double[] x) {
double[] lowerBound = {Math.min(x), GaussianDistribution.getInstance().quantile(1 / (x.length + 1.0))};
double[] upperBound = {Math.max(x), GaussianDistribution.getInstance().quantile(x.length / (x.length + 1.0))};
PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound);
canvas.add(new QQPlot(x));
return canvas;
}
/**
* Create a plot canvas with the one sample Q-Q plot to given distribution.
* The x-axis is the quantiles of x and the y-axis is the quantiles of
* given distribution.
* @param x a sample set.
* @param d a distribution.
*/
public static PlotCanvas plot(double[] x, Distribution d) {
double[] lowerBound = {Math.min(x), d.quantile(1 / (x.length + 1.0))};
double[] upperBound = {Math.max(x), d.quantile(x.length / (x.length + 1.0))};
PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound);
canvas.add(new QQPlot(x, d));
return canvas;
}
/**
* Create a plot canvas with the two sample Q-Q plot.
* The x-axis is the quantiles of x and the y-axis is the quantiles of y.
* @param x a sample set.
* @param y a sample set.
*/
public static PlotCanvas plot(double[] x, double[] y) {
double[] lowerBound = {Math.min(x), Math.min(y)};
double[] upperBound = {Math.max(x), Math.max(y)};
PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound);
canvas.add(new QQPlot(x, y));
return canvas;
}
/**
* Create a plot canvas with the one sample Q-Q plot to given distribution.
* The x-axis is the quantiles of x and the y-axis is the quantiles of
* given distribution.
* @param x a sample set.
* @param d a distribution.
*/
public static PlotCanvas plot(int[] x, DiscreteDistribution d) {
double[] lowerBound = {Math.min(x), d.quantile(1 / (x.length + 1.0))};
double[] upperBound = {Math.max(x), d.quantile(x.length / (x.length + 1.0))};
PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound);
canvas.add(new QQPlot(x, d));
return canvas;
}
/**
* Create a plot canvas with the two sample Q-Q plot.
* The x-axis is the quantiles of x and the y-axis is the quantiles of y.
* @param x a sample set.
* @param y a sample set.
*/
public static PlotCanvas plot(int[] x, int[] y) {
double[] lowerBound = {Math.min(x), Math.min(y)};
double[] upperBound = {Math.max(x), Math.max(y)};
PlotCanvas canvas = new PlotCanvas(lowerBound, upperBound);
canvas.add(new QQPlot(x, y));
return canvas;
}
}
Ads help maintain this website.