/* * ------------------------------------------------------------------------- * $Id: SunSpots.java,v 1.2 2004/05/26 19:16:36 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. *-------------------------------------------------------------------------- */ package com.imsl.demo.SunSpots; import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.text.*; import com.imsl.stat.*; import com.imsl.chart.*; import com.imsl.demo.gallery.Describe; public class SunSpots extends JFrameChart implements ActionListener, ChangeListener, MouseListener, MouseMotionListener { private Chart chart; private AxisXY axis; private Data data, forecastData, upperLimit, lowerLimit; private JSlider slider; private JTextField predField, probField, displayField; private boolean toForecast, zoom, iszoom; private double[] from, to, current; private ARMA arma; private SimpleDateFormat dateFormat = new SimpleDateFormat("M/yyyy"); public SunSpots(boolean exitOnClose) { if (!exitOnClose) { // remove the WindowListener, installed by JFrameChart, that // exits the application when the window is closed. Object l[] = getListeners(java.awt.event.WindowListener.class); for (int k = 0; k < l.length; k++) { removeWindowListener((java.awt.event.WindowListener)l[k]); } } Describe des = new Describe(this, "/com/imsl/demo/SunSpots/SunSpots.html"); des.show(); Dimension ds = des.getSize(); Dimension ss = getToolkit().getScreenSize(); int h = Math.min(ss.width/2, ss.height-ds.height-32); int w = (int)(h/0.8); setSize(w, h); setLocation(ss.width-ds.width, ds.height); // Set default values. toForecast = zoom = false; chart = getChart(); axis = new AxisXY(chart); axis.getAxisX().getAxisLabel().setTextFormat(dateFormat); axis.getAxisX().getAxisLabel().setTextAngle(90); axis.getAxisX().getAxisTitle().setTitle("Year"); from = new double[2]; to = new double[2]; current = new double[2]; // Add MouseListener and MouseMotionListener to chart panel. chart.getLegend().setPaint(true); getPanel().addMouseListener(this); getPanel().addMouseMotionListener(this); Container cp = getContentPane(); // Create components in control panel. JButton draw = new JButton("Forecast"); draw.addActionListener(this); JButton reset = new JButton("Reset"); reset.addActionListener(this); JLabel prob = new JLabel("Confidence", JLabel.CENTER); probField = new JTextField("0.95", 4); slider = new JSlider(1, 31, 11); slider.setPaintTicks(true); slider.setPaintLabels(true); slider.setMajorTickSpacing(10); slider.setMinorTickSpacing(1); slider.setSnapToTicks(true); slider.addChangeListener(this); JLabel pred = new JLabel("Predicts", JLabel.CENTER); predField = new JTextField("11", 3); predField.setEditable(false); JPanel buttonPanel = new JPanel(); buttonPanel.add(draw); buttonPanel.add(prob); buttonPanel.add(probField); buttonPanel.add(slider); buttonPanel.add(pred); buttonPanel.add(predField); buttonPanel.add(reset); // Create the display panel JPanel displayPanel = new JPanel(); displayField = new JTextField("Current position: X = ?? Y = ??", 53); displayField.setBorder(null); displayField.setCaretPosition(0); displayField.setEditable(false); displayPanel.add(displayField); cp.add(buttonPanel, BorderLayout.NORTH); cp.add(displayPanel, BorderLayout.SOUTH); drawGraph(); setResizable(false); } // Get the description line. private String getDescription() { DecimalFormat nf = new DecimalFormat("0.0000"); StringBuffer sb = new StringBuffer(); if (iszoom) { sb.append("Zooming In from: "); sb.append("X = " + dateFormat.format(new Date((long) from[0])) + " Y = " + nf.format(from[1])); sb.append(" To: "); sb.append("X = " + dateFormat.format(new Date((long) to[0])) + " Y = " + nf.format(to[1])); } else { sb.append("Cursor At: X = " + dateFormat.format(new Date((long) current[0])) + " Y = " + nf.format(current[1])); } return sb.toString(); } // Draw the graph. private void drawGraph() { double[] y = {100.8, 81.6, 66.5, 34.8, 30.6, 7, 19.8, 92.5, 154.4, 125.9, 84.8, 68.1, 38.5, 22.8, 10.2, 24.1, 82.9, 132, 130.9, 118.1, 89.9, 66.6, 60, 46.9, 41, 21.3, 16, 6.4, 4.1, 6.8, 14.5, 34, 45, 43.1, 47.5, 42.2, 28.1, 10.1, 8.1, 2.5, 0, 1.4, 5, 12.2, 13.9, 35.4, 45.8, 41.1, 30.4, 23.9, 15.7, 6.6, 4, 1.8, 8.5, 16.6, 36.3, 49.7, 62.5, 67, 71, 47.8, 27.5, 8.5, 13.2, 56.9, 121.5, 138.3, 103.2, 85.8, 63.2, 36.8, 24.2, 10.7, 15, 40.1, 61.5, 98.5, 124.3, 95.9, 66.5, 64.5, 54.2, 39, 20.6, 6.7, 4.3, 22.8, 54.8, 93.8, 95.7, 77.2, 59.1, 44, 47, 30.5, 16.3, 7.3, 37.3, 73.9}; double[] x = new double[y.length]; // If in zooming mode, then zoom the graph. Otherwise, use default ranges. if (zoom) { axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisX().setWindow(Math.min(from[0], to[0]), Math.max(from[0], to[0])); axis.getAxisY().setWindow(Math.min(from[1], to[1]), Math.max(from[1], to[1])); } else { axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisX().setWindow((new GregorianCalendar(1770, 0, 1)).getTimeInMillis(), (new GregorianCalendar(1910, 0, 1)).getTimeInMillis()); axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); //axis.getAxisY().setWindow(-145.0, 235.0); axis.getAxisY().setWindow(-50.0, 200.0); } // Draw the actual data. for (int i = 0; i < y.length; i++) { x[i] = (new GregorianCalendar(1770 + i, 0, 1)).getTimeInMillis(); } data = new Data(axis, x, y); data.setTitle("Actual data"); data.setDataType(Data.DATA_TYPE_LINE | Data.DATA_TYPE_MARKER); data.setMarkerType(Data.MARKER_TYPE_FILLED_CIRCLE); data.setMarkerSize(0.7); data.setMarkerColor(Color.blue); data.setLineColor(Color.blue); // Use ARMA class (ARMA(2,1)) to get the forecast using backorigin = 3. // Number of predicts and confidence level are from the interface. if (toForecast) { try { int num = slider.getValue(); // Do this if Forecast is clicked. if (arma == null) { arma = new ARMA(2, 1, y); arma.setRelativeError(0.0); arma.setMaxIterations(0); arma.compute(); arma.setConfidence(Double.parseDouble(probField.getText())); arma.setBackwardOrigin(3); } double[][] forecast = arma.forecast(num); double[] tmp = new double[num]; double[] x1 = new double[num]; // Draw the forecast data. for (int i = 0; i < num; i++) { tmp[i] = forecast[i][3]; x1[i] = (new GregorianCalendar(1870+i, 0, 1)).getTimeInMillis(); } // Draw upper and lower limits. double[] dev = arma.getDeviations(); double[] ul = new double[dev.length]; double[] ll = new double[dev.length]; double min = 0.0; for (int i = 0; i < dev.length; i++) { ul[i] = tmp[i] + dev[i]; ll[i] = tmp[i] - dev[i]; if (min > ll[i]) min = ll[i]; } min = min - 0.01; upperLimit = new Data(axis, x1, ul); upperLimit.setTitle("Upper Limit"); upperLimit.setDataType(Data.DATA_TYPE_LINE | Data.DATA_TYPE_FILL); upperLimit.setReference(min); upperLimit.setFillColor(Color.yellow); upperLimit.setFillOutlineColor(Color.white); lowerLimit = new Data(axis, x1, ll); lowerLimit.setTitle("Lower Limit"); lowerLimit.setDataType(Data.DATA_TYPE_LINE | Data.DATA_TYPE_FILL); lowerLimit.setReference(min); lowerLimit.setFillColor(Color.white); lowerLimit.setFillOutlineColor(Color.white); forecastData = new Data(axis, x1, tmp); forecastData.setTitle("Forecast"); forecastData.setDataType(Data.DATA_TYPE_LINE); forecastData.setLineColor(Color.red); } catch (Exception e) { } } } // Get the information from the interface and redraw the chart. private void update() { double tmp = 0.0; // Check the range for the confidence level. Use 0.95 if there is // an error in the input. try { tmp = Double.parseDouble(probField.getText()); } catch (Exception exception) { tmp = 0.95; probField.setText("0.95"); } finally { if (data != null) data.remove(); if (forecastData != null) forecastData.remove(); if (upperLimit != null) upperLimit.remove(); if (lowerLimit != null) lowerLimit.remove(); if ((tmp <= 0.0) || (tmp >= 1.0)) probField.setText("0.95"); drawGraph(); repaint(); } } // Implement ActionListener public void actionPerformed(ActionEvent e) { // If Reset is clicked, re-size the chart using autoscale. // If Draw is clicked, redraw the chart. if (e.getActionCommand().equals("Reset")) { zoom = false; } else { toForecast = true; arma = null; } update(); } // Implement ChangeListener public void stateChanged(ChangeEvent e) { // Update text field for number of predicts. predField.setText(Integer.toString(slider.getValue())); } // Implement MouseListener public void mouseClicked(MouseEvent e) { } public void mousePressed(MouseEvent e) { // Get the starting position for zooming. axis.mapDeviceToUser(e.getX(), e.getY(), from); axis.mapDeviceToUser(e.getX(), e.getY(), to); zoom = true; iszoom = true; } public void mouseReleased(MouseEvent e) { int x = e.getX(); int y = e.getY(); // The selection must be from 2 different points. int[] point = new int[2]; axis.mapUserToDevice(from[0], from[1], point); if (point[0] == x) return; if (point[1] == y) return; // Get the ending position for zooming. axis.mapDeviceToUser(x, y, to); iszoom = false; update(); } public void mouseEntered(MouseEvent e) { setCursor(new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR)); } public void mouseExited(MouseEvent e) { setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); } // Implement MouseMotionListener public void mouseDragged(MouseEvent e) { // Draw the selection square and update display information. paint(e, true); displayField.setText(getDescription()); } public void mouseMoved(MouseEvent e) { // Update display information. axis.mapDeviceToUser(e.getX(), e.getY(), current); displayField.setText(getDescription()); } // Draw the selection in different color. protected void paint(MouseEvent mouseEvent, boolean erase) { Graphics2D g = (Graphics2D) SunSpots.this.getPanel().getGraphics(); if (erase) paint(g); axis.mapDeviceToUser(mouseEvent.getX(), mouseEvent.getY(), to); paint(g); g.dispose(); } protected void paint(Graphics2D g) { Color colorFill = new Color(255,0,255,128); Color colorOutline = new Color(0,255,0); int[] pointA = new int[2]; int[] pointB = new int[2]; axis.mapUserToDevice(from[0], from[1], pointA); axis.mapUserToDevice(to[0], to[1], pointB); Shape shape = new Rectangle(Math.min(pointA[0], pointB[0]), Math.min(pointA[1], pointB[1]), Math.abs(pointA[0]-pointB[0]), Math.abs(pointA[1]-pointB[1])); g.setXORMode(colorOutline); g.draw(shape); g.setXORMode(colorFill); g.fill(shape); } public static void main(String args[]) { boolean exitOnClose = true; if (args.length > 0 && args[0].equals("-noexit")) exitOnClose = false; new SunSpots(exitOnClose).show(); } }