package demo.combo;
import org.zkoss.chart.Charts;
import org.zkoss.chart.Series;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.Window;
public class ComboRegressionComposer extends SelectorComposer<Window> {
@Wire
Charts chart;
public void doAfterCompose(Window comp) throws Exception {
super.doAfterCompose(comp);
double[][] dataset = {
{4.648, 2.013}, {4.583, 1.354}, {-2.548, 1.066}, {-2.321, -0.733},
{3.684, 1.013}, {2.888, -0.539}, {2.358, 1.496}, {-0.535, 1.718},
{1.848, -0.462}, {1.854, 2.748}, {1.65, 3.253}, {-1.733, 2.058},
{0.445, 2.586}, {0.148, 1.168}, {2.784, 1.399}, {4.959, 4.581},
{4.595, 3.141}, {1.353, 2.451}, {0.559, 2.402}, {-0.854, 0.831},
{-2.713, 0.781}, {-2.78, -1.127}, {0.719, 0.905}, {-0.452, 3.767},
{0.04, 2.959}, {4.134, 1.68}, {1.206, 1.339}, {1.484, 1.781},
{-1.111, 1.82}, {-2.809, -0.987}, {-0.399, 2.752}, {-1.906, 0.949},
{1.082, 1.394}, {4.989, 4.606}, {2.396, 0.42}, {-1.545, 1.738},
{4.149, 2.807}, {3.374, 1.321}, {2.875, 0.939}, {4.253, 3.535},
{3.103, -0.248}, {3.318, 2.644}, {-0.17, 1.078}, {4.848, 3.636},
{4.695, 2.203}, {-1.711, 1.126}, {3.032, -0.522}, {2.721, 0.315},
{0.691, 2.694}, {1.243, 2.708}, {0.92, 2.536}, {4.399, 2.117},
{1.007, 2.395}, {3.652, 1.265}, {-0.169, 2.138}, {4.063, 1.791},
{4.198, 1.705}, {0.688, 3.712}, {1.542, 1.832}, {4.363, 1.436},
{2.79, 0.954}, {0.893, 1.342}, {-1.226, 3.519}, {-0.403, 2.466},
{2.597, -0.78}, {-1.671, 0.765}, {4.264, 2.736}, {-0.855, 3.988},
{4.291, 2.888}, {-0.523, 2.865}, {4.659, 3.201}, {2.65, 2.046},
{1.034, 0.55}, {1.142, 1.522}, {2.211, 1.456}, {1.704, 2.286},
{-0.505, 3.947}, {-1.337, 1.281}, {1.095, 1.113}, {4.473, 1.199},
{1.986, 2.308}, {-2.397, 1.838}, {3.563, 1.649}, {2.808, 1.676},
{4.261, 0.631}, {-1.469, 2.266}, {2.958, 0.901}, {-2.53, 0.325},
{2.223, 1.89}, {-0.815, 2.656}, {-1.187, 2.236}, {4.004, 1.712},
{-2.15, -0.832}, {1.179, 2.359}, {3.832, 2.834}, {-1.041, 3.408},
{-1.316, 1.606}, {4.045, 1.696}, {0.383, 3.496}, {2.736, 0.766}
};
chart.getXAxis().setMinPadding(0.1);
chart.getXAxis().setMaxPadding(0.1);
Series scatter = chart.getSeries();
scatter.setType("scatter");
scatter.setName("Observations");
for (double[] d : dataset) scatter.addPoint(d[0], d[1]);
scatter.getMarker().setRadius(4);
for (int degree = 1; degree <= 3; degree++) {
double[] coeffs = linearRegression(dataset, degree);
double[][] lineData = generateLineData(coeffs, -3, 5, 10);
Series line = chart.getSeries(degree);
line.setType("spline");
line.setName(ordinal(degree) + " degree regression line");
for (double[] d : lineData) line.addPoint(d[0], d[1]);
line.getMarker().setEnabled(false);
line.setEnableMouseTracking(false);
line.getStates().getHover().setLineWidth(0);
}
}
private String ordinal(int n) {
return n == 1 ? "1st" : n == 2 ? "2nd" : "3rd";
}
private double[] linearRegression(double[][] dataset, int nDegrees) {
int n = dataset.length;
int m = nDegrees + 1;
double[] x = new double[n];
double[] y = new double[n];
for (int i = 0; i < n; i++) {
x[i] = dataset[i][0];
y[i] = dataset[i][1];
}
double[][] X = new double[m][n];
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) X[i][j] = Math.pow(x[j], i);
double[][] Xt = new double[n][m];
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) Xt[i][j] = X[j][i];
double[][] XtX = new double[m][m];
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++) {
double sum = 0;
for (int k = 0; k < n; k++) sum += X[i][k] * Xt[k][j];
XtX[i][j] = sum;
}
double[][] invXtX = inverse(XtX);
double[] Xty = new double[m];
for (int j = 0; j < m; j++) {
double sum = 0;
for (int k = 0; k < n; k++) sum += y[k] * Xt[k][j];
Xty[j] = sum;
}
double[] b = new double[m];
for (int j = 0; j < m; j++) {
double sum = 0;
for (int k = 0; k < m; k++) sum += Xty[k] * invXtX[k][j];
b[j] = sum;
}
return b;
}
private double[][] inverse(double[][] matrix) {
int n = matrix.length;
double[][] aug = new double[n][2 * n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) aug[i][j] = matrix[i][j];
aug[i][n + i] = 1;
}
for (int col = 0; col < n; col++) {
int maxRow = col;
for (int row = col + 1; row < n; row++)
if (Math.abs(aug[row][col]) > Math.abs(aug[maxRow][col])) maxRow = row;
if (maxRow != col) {
double[] tmp = aug[col]; aug[col] = aug[maxRow]; aug[maxRow] = tmp;
}
double pivot = aug[col][col];
for (int j = 0; j < 2 * n; j++) aug[col][j] /= pivot;
for (int row = 0; row < n; row++) {
if (row != col && aug[row][col] != 0) {
double factor = aug[row][col];
for (int j = 0; j < 2 * n; j++) aug[row][j] -= factor * aug[col][j];
}
}
}
double[][] inv = new double[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) inv[i][j] = aug[i][n + j];
return inv;
}
private double[][] generateLineData(double[] coeffs, double start, double end, int resolution) {
java.util.List<double[]> out = new java.util.ArrayList<>();
double step = 1.0 / resolution;
for (double x = start; x <= end; x += step) {
double y = 0;
for (int j = 0; j < coeffs.length; j++) y += coeffs[j] * Math.pow(x, j);
out.add(new double[]{x, y});
}
return out.toArray(new double[0][]);
}
}