/*
* -------------------------------------------------------------------------
* $Id: LRPanel.java,v 1.4 2006/04/19 19:00:39 estewart Exp $
* -------------------------------------------------------------------------
* Copyright (c) 1999 Visual Numerics Inc. All Rights Reserved.
*
* This software is confidential information which is proprietary to
* and a trade secret of Visual Numerics, Inc. Use, duplication or
* disclosure is subject to the terms of an appropriate license
* agreement.
*
* VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
* SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL
* NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
* ITS DERIVATIVES.
*--------------------------------------------------------------------------
*/
/*
* LRPanel.java
*
* Created on August 19, 2003, 10:45 AM
*/
package com.imsl.demo.fitting;
import com.imsl.chart.*;
import java.util.Vector;
import java.awt.event.*;
import javax.swing.event.*;
public class LRPanel extends javax.swing.JPanel implements ActionListener, MouseListener {
private double intercept, x1, mse;
private boolean hasIntercept;
private Chart chart;
private AxisXY axis;
private Data point, line;
private Vector dataX, dataY;
private double[] xRange, yRange;
private javax.swing.JFrame parentFrame;
private javax.swing.JRadioButtonMenuItem[] jRadioButtons;
private final int numData = 4;
private final String dataName[] = {"Blank", "Advertising", "Age and Height", "Cigarette Smoke"};
/** Creates new form LRPanel */
public LRPanel(javax.swing.JFrame parent) {
this.parentFrame = parent;
// Set initial values.
hasIntercept = true;
mse = 0.0;
dataX = new Vector();
dataY = new Vector();
initComponents();
setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.85*parent.getSize().height)));
jButtonGenerate.addActionListener(this);
jButtonEnter.addActionListener(this);
jButtonReset.addActionListener(this);
checkBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
itemChanged();
}
});
addDataButtons();
setChart();
jPanelChart.setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.66*parent.getSize().height)));
getData();
update();
}
private void setChart() {
chart = jPanelChart.getChart();
chart.getLegend().setPaint(true);
chart.getLegend().setViewport(0.45,0.55,0.01,0.1);
axis = new AxisXY(chart);
axis.setViewport(0.12,0.88,0.05,0.88);
// Set axes ranges
axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
axis.getAxisX().setWindow(0.0, 50.0);
axis.getAxisY().setWindow(0.0, 75.0);
axis.getAxisX().setTextFormat(new java.text.DecimalFormat("###.##"));
axis.getAxisY().setTextFormat(new java.text.DecimalFormat("###.##"));
// Add MouseListeren to the chart.
jPanelChart.addMouseListener(this);
}
// add the available data sets to the dataMenu
private void addDataButtons() {
jRadioButtons = new javax.swing.JRadioButtonMenuItem[numData];
javax.swing.ButtonGroup group = new javax.swing.ButtonGroup();
for (int i=0; i<numData; i++) {
jRadioButtons[i] = new javax.swing.JRadioButtonMenuItem();
jRadioButtons[i].setText(dataName[i]);
jRadioButtons[i].addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
getData();
update();
}
});
group.add(jRadioButtons[i]);
((FittingMain)parentFrame).getDataMenu().add(jRadioButtons[i]);
}
jRadioButtons[1].setSelected(true);
}
// clear and load data sets determined by the menu selection
public void getData() {
dataX.clear();
dataY.clear();
xRange = new double[2];
yRange = new double[2];
String xTitle = "";
String yTitle = "";
int selected = -1;
for (int i=0; i<numData; i++) {
if (jRadioButtons[i].isSelected()) {
selected = i;
break;
}
}
switch (selected) {
case 0: // blank
xTitle = "X Value";
yTitle = "Y Value";
xRange[0] = 0.0;
xRange[1] = 50.0;
yRange[0] = 0.0;
yRange[1] = 50.0;
break;
case 1: /* These data are obtianed from http://www-personal.buseco.monash.edu.au/~hyndman/TSDL/index.htm
* which quotes the source as Advertising and sales data Source: Makridakis, Wheelwright and Hyndman (1998).
* http://www.businessbookmall.com/zstat1.htm
*/
//double x[] = {12,20.5,21,15.5,15.3,23.5,24.5,21.3,23.5,28,24,15.5,17.3,25.3,25,36.5,36.5,29.6,30.5,28,26,21.5,19.7,19,16,20.7,26.5,30.6,32.3,29.5,28.3,31.3,32.2,26.4,23.4,16.4};
//double y[] = {15,16,18,27,21,49,21,22,28,36,40,3,21,29,62,65,46,44,33,62,22,12,24,3,5,14,36,40,49,7,52,65,17,5,17,1};
double x[] = {5,2,7,6,10,4,6,5,3,8};
double y[] = {50,25,80,50,90,30,60,60,40,80};
for (int i=0; i<x.length; i++) {
dataX.add(new Double(x[i]));
dataY.add(new Double(y[i]));
}
xTitle = "Advertising Expenditure, Thousands of Dollars";
yTitle = "Sales Revenue, Thousands of Dollars";
xRange[0] = 0.0;
xRange[1] = 10.0;
yRange[0] = 0.0;
yRange[1] = 100.0;
break;
case 2: /* These data female age and weight data from
* Lewis, T. and Taylor, L.R. (1967), Introduction to Experimental Ecology, New York: Academic Press, Inc.
*/
double x2[] = {143,191,160,157,191,141,185,210,149,169,173,150,144,146,155,183,154,152,148,164,177,183,182,165,163,171,193,169,155,171,140,149,150,140,166,146,139,177,166,184,177,145,167,185,156,191,189,157,171,143,182,154,141,167,141,175,153,185,139,143,147,164,175,170,186,185,168,139,178,147,183,148,144,190,143,147,172,179,142,150,147,182,164,180,161,142,178,145,180,176,180,162,197,182,169,147,197,145,143,147,154,140,178,148,190,186,165,155,210,144,186};
double y2[] = {56.3,62.5,62,64.5,65.3,61.8,63.3,65.5,64.3,62.3,62.8,61.3,59.5,60,61.3,64.5,60,60.5,60.5,65.3,61.3,66.5,65.5,55.5,56.5,63,59.8,61.5,62.3,62.5,53.8,58.3,59.5,53.5,61.5,56.3,57.5,61.8,59.3,62.3,61.3,59,62.3,60,54.5,63.3,64.3,60.5,61.5,61.5,62,61,56,61,61.3,60.3,63.3,59,61.5,51.3,61.3,58,60.8,64.3,57.8,65.3,61.5,52.8,63.5,55.8,64.3,56.3,55.8,66.8,58.3,59.5,64.8,63,56,54.5,51.5,64,63.3,61.3,59,56.5,61.5,58.8,63.3,61.3,59,58,61.5,58.3,62,59.8,64.8,57.8,55.5,58.3,62.8,60,66.5,59,56.8,57,61.3,66,62,61,63.5};
for (int i=0; i<x2.length; i++) {
dataX.add(new Double(x2[i]));
dataY.add(new Double(y2[i]));
}
xTitle = "Age, months";
yTitle = "Height, inches";
xRange[0] = 100.0;
xRange[1] = 250.0;
yRange[0] = 50.0;
yRange[1] = 75.0;
break;
case 3: /* These data are female age and weight data from
* Lewis, T. and Taylor, L.R. (1967), Introduction to Experimental Ecology, New York: Academic Press, Inc.
*/
double x3[] = {14.1,16,29.8,8,4.1,15,8.8,12.4,16.6,14.9,13.7,15.1,7.8,11.4,9,1,17,12.8,15.8,4.5,14.5,7.3,8.6,15.2,12};
double y3[] = {13.6,16.6,23.5,10.2,5.4,15,9,12.3,16.3,15.4,13,14.4,10,10.2,9.5,1.5,18.5,12.6,17.5,4.9,15.9,8.5,10.6,13.9,14.9};
for (int i=0; i<x3.length; i++) {
dataX.add(new Double(x3[i]));
dataY.add(new Double(y3[i]));
}
xTitle = "Tar, mg";
yTitle = "CO, mg";
xRange[0] = 0.0;
xRange[1] = 30.0;
yRange[0] = 0.0;
yRange[1] = 30.0;
break;
}
axis.getAxisX().getAxisTitle().setTitle(xTitle);
axis.getAxisY().getAxisTitle().setTitle(yTitle);
axis.getAxisX().setWindow(xRange);
axis.getAxisY().setWindow(yRange);
}
// Draw the graph.
private void drawGraph() {
if ((dataX.size() != 0) && (dataY.size() != 0)) {
double[] x = new double[dataX.size()];
double[] y = new double[dataY.size()];
for (int i = 0; i < x.length; i++) {
x[i] = ((Double) dataX.get(i)).doubleValue();
y[i] = ((Double) dataY.get(i)).doubleValue();
}
// Draw the points.
point = new Data(axis, x, y);
point.setDataType(Data.DATA_TYPE_MARKER);
point.setMarkerType(Data.MARKER_TYPE_OCTAGON_X);
point.setMarkerSize(0.8);
point.setMarkerColor(java.awt.Color.blue);
// Draw the regression line.
getRegCoefficient(x, y);
ChartFunction fcn = new ChartFunction() {
public double f(double x) {
return x*x1 + intercept;
}
};
line = new Data(axis, fcn, xRange[0], xRange[1]);
line.setLineColor(java.awt.Color.red);
line.setTitle("Linear Fit");
line.setLineWidth(2);
} else {
intercept = 0.0;
x1 = 0.0;
}
}
// Get the coefficients for the regression line.
// y = a + bx
private void getRegCoefficient(double[] x, double[] y) {
com.imsl.stat.LinearRegression reg = new com.imsl.stat.LinearRegression(1, hasIntercept);
double[] ss = new double[1];
for (int i = 0; i < y.length; i++) {
ss[0] = x[i];
reg.update(ss, y[i]);
}
double[] coe = reg.getCoefficients();
mse = reg.getANOVA().getErrorMeanSquare();
// Set the values depending on whether intercept is chosen.
if (hasIntercept) {
intercept = coe[0];
x1 = coe[1];
} else {
intercept = 0.0;
x1 = coe[0];
}
}
// Get the description line.
private String getDescription() {
java.text.DecimalFormat formatStat = new java.text.DecimalFormat("0.000");
StringBuffer sb = new StringBuffer("# of Points: ");
if (dataX == null) {
sb.append(0);
} else {
sb.append(dataX.size());
}
if (dataX.size() < 3) {
sb.append(" Error Mean Square: ??");
} else {
sb.append(" Error Mean Square: " + formatStat.format(mse));
}
sb.append("\nRegression Line: y = (" + formatStat.format(x1) +
")x + (" + formatStat.format(intercept) + ")");
return sb.toString();
}
// Redraw the chart.
public void update() {
if (line != null) line.remove();
if (point != null) point.remove();
drawGraph();
displayText.setText(getDescription());
repaint();
}
public void setVisible(boolean show) {
super.setVisible(show);
if (show) {
addDataButtons();
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {//GEN-BEGIN:initComponents
jPanel = new javax.swing.JPanel();
jButtonEnter = new javax.swing.JButton();
jButtonGenerate = new javax.swing.JButton();
jLabelPoints = new javax.swing.JLabel();
numField = new javax.swing.JTextField("6", 4);
checkBox = new javax.swing.JCheckBox();
jButtonReset = new javax.swing.JButton();
displayText = new javax.swing.JTextArea(getDescription(), 2, 30);
jPanelChart = new com.imsl.chart.JPanelChart();
setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
setPreferredSize(new java.awt.Dimension(500, 600));
jButtonEnter.setText("Enter Points");
jPanel.add(jButtonEnter);
jButtonGenerate.setText("Generate");
jPanel.add(jButtonGenerate);
jLabelPoints.setText("# of Points: ");
jPanel.add(jLabelPoints);
numField.setColumns(4);
numField.setText("6");
jPanel.add(numField);
checkBox.setSelected(true);
checkBox.setText("intercept");
jPanel.add(checkBox);
jButtonReset.setText("Reset");
jPanel.add(jButtonReset);
add(jPanel);
displayText.setEditable(false);
displayText.setPreferredSize(new java.awt.Dimension(500, 16));
add(displayText);
jPanelChart.setPreferredSize(new java.awt.Dimension(500, 500));
add(jPanelChart);
}//GEN-END:initComponents
// Implement ActionListener
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Enter Points")) {
// Enter points using a text area.
javax.swing.JTextArea textArea = new javax.swing.JTextArea(10, 5);
javax.swing.JScrollPane scroll = new javax.swing.JScrollPane(textArea);
int option = 0;
try {
option = javax.swing.JOptionPane.showConfirmDialog(this, scroll,
"Enter Points", javax.swing.JOptionPane.OK_CANCEL_OPTION);
if (option == javax.swing.JOptionPane.CANCEL_OPTION) return;
} catch (Exception ex) {
}
java.util.StringTokenizer lineToken =
new java.util.StringTokenizer(textArea.getText(), "\n");
while (lineToken.hasMoreElements()) {
java.util.StringTokenizer token = new java.util.StringTokenizer(lineToken.nextToken(), "(){}[] ,\t\n");
// If the line does not contain 2 numbers, then ignore.
if (token.countTokens() == 2) {
try {
double x = Double.parseDouble(token.nextToken());
double y = Double.parseDouble(token.nextToken());
// Ignore any points that are not in the range.
if ((x >= xRange[0]) && (x <= xRange[1]) &&
(y >= yRange[0]) && (y <= yRange[1])) {
dataX.add(new Double(x));
dataY.add(new Double(y));
}
} catch (Exception ex) {
}
}
}
update();
} else if (e.getActionCommand().equals("Generate")) {
int i = 0;
try {
i = Integer.parseInt(numField.getText());
} catch (Exception exception) {
i = 6;
numField.setText("6");
} finally {
if (i <= 0) {
i = 6;
numField.setText("6");
}
for (int j = 0; j < i; j++) {
dataX.add(new Double(xRange[1] * Math.random() + xRange[0]));
dataY.add(new Double(yRange[1] * Math.random() + yRange[0]));
}
update();
}
} else {
// Reset button is clicked. Reset everything to default.
numField.setText("6");
checkBox.setSelected(true);
hasIntercept = true;
intercept = x1 = 0.0;
mse = 0.0;
dataX = new Vector();
dataY = new Vector();
update();
getData();
update();
}
}
// ItemListener action method
private void itemChanged() {
hasIntercept = !hasIntercept;
update();
}
// Implement MouseListener
public void mouseClicked(MouseEvent e) {
double user[] = {0,0};
axis.mapDeviceToUser(e.getX(), e.getY(), user);
// Do not add the point if it is not in the range.
if ((user[0] < xRange[0]) || (user[0] > xRange[1]) ||
(user[1] < yRange[0]) || (user[1] > yRange[1])) return;
// Button is to add points. Otherwise, remove points.
if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
dataX.add(new Double(user[0]));
dataY.add(new Double(user[1]));
update();
} else {
int idx = -1;
double min = 0.01;
final double ux = (user[0]-xRange[0])/(double)(xRange[1]-xRange[0]);
final double uy = (user[1]-yRange[0])/(double)(yRange[1]-yRange[0]);
for (int i = 0; i < dataX.size(); i++) {
double x = (((Double)dataX.get(i)).doubleValue()-xRange[0])/
(double)(xRange[1]-xRange[0]);
double y = (((Double)dataY.get(i)).doubleValue()-yRange[0])/
(double)(yRange[1]-yRange[0]);
double dist = Math.sqrt((ux - x)*(ux - x) + (uy - y)*(uy - y));
if (dist < min) {
min = dist;
idx = i;
}
}
if (idx != -1) {
dataX.remove(idx);
dataY.remove(idx);
update();
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel jLabelPoints;
private javax.swing.JButton jButtonGenerate;
private javax.swing.JButton jButtonReset;
private javax.swing.JTextField numField;
private com.imsl.chart.JPanelChart jPanelChart;
private javax.swing.JCheckBox checkBox;
private javax.swing.JTextArea displayText;
private javax.swing.JButton jButtonEnter;
private javax.swing.JPanel jPanel;
// End of variables declaration//GEN-END:variables
}