/* * ------------------------------------------------------------------------- * $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 }