Scatter Plot
/************************************************************************* * * * This source code file, and compiled classes derived from it, can * * be used and distributed without restriction, including for commercial * * use. (Attribution is not required but is appreciated.) * * * * David J. Eck * * Department of Mathematics and Computer Science * * Hobart and William Smith Colleges * * Geneva, New York 14456, USA * * Email: eck@hws.edu WWW: http://math.hws.edu/eck/ * * * *************************************************************************/ import edu.hws.jcm.awt.*; import edu.hws.jcm.data.*; import edu.hws.jcm.draw.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.util.*; import java.applet.Applet; /** * A ScatterPlotApplet shows a scatter plot of data from a DataTableInput. * The user can enter the data in a two-column table that is shown in * the applet. It is also possible to configure the applet with a menu * of file names. These files, which must be in the same directory as * the Web page on which the applet appears, will appear in a menu. * A file can contain data for the table, with two numbers per line. * When the user loads the file, the data replaces the data in the table. */ public class ScatterPlotApplet extends Applet implements ActionListener { private Frame frame; // If non-null, a separate window. private String frameTitle; // Title for the separate window. private Button launchButton; // If non-null, then clicking this buttons opens a separate window. private String launchButtonName; // Name for the launch button. private DataTableInput table; // The table for input of data. private ScatterPlot scatterPlot; // The scatter plot of the data. private DisplayCanvas canvas; // The DisplayCanvas on which the plot is drawn. private Button loadFileButton; // When clicked, a data file is loaded. private Choice fileMenu; // Pop-up menu containing names of functions. private String[] fileNames; // Names of data files associated with menu entries. private Controller mainController; // Controller from the main JCMPanel. /** * The init() method is called by the system to set up the applet. * If the applet does not appear as a button, then init() creates the main panel of the applet * and calls setUpMainPanel to set it up. */ public void init() { frameTitle = getParameter("FrameTitle"); // Get title to be used for separate window, if any. if (frameTitle == null) { frameTitle = "Scatter Plots"; int pos = frameTitle.lastIndexOf('.'); if (pos > -1) frameTitle = frameTitle.substring(pos+1); } setLayout(new BorderLayout()); int height = getSize().height; launchButtonName = getParameter("LaunchButtonName"); if ( (height > 0 && height <= 50) || launchButtonName != null) { // Use a separater window and only show a button in the applet. if (launchButtonName == null) launchButtonName = "Launch " + frameTitle; launchButton = new Button(launchButtonName); add(launchButton, BorderLayout.CENTER); launchButton.addActionListener(this); } else { // Show the main panel in the applet, not in a separate window. add(makeMainPanel(), BorderLayout.CENTER); } } /* * Create the main panel of the applet. */ public Panel makeMainPanel() { // Make the main panel JCMPanel panel = new JCMPanel(2); mainController = panel.getController(); panel.setBackground(new Color(0,0,180)); panel.setInsetGap(2); setLayout(new BorderLayout()); // Make a DataInputTable with two columns table = new DataTableInput(null, 2); table.setColumnName(0, getParameter("ColumnName1", "X")); table.setColumnName(1, getParameter("ColumnName2", "Y")); table.setThrowErrors(true); if ( "yes".equalsIgnoreCase(getParameter("ShowColumnTitles","yes"))) table.setShowColumnTitles(true); if ( "yes".equalsIgnoreCase(getParameter("ShowRowNumbers","yes"))) table.setShowRowNumbers(true); // Make input boxes for getting expressions that can include // the variables associated with the table. Initially, the // expressions are just the column names. Parser parser = new Parser(); table.addVariablesToParser(parser); ExpressionInput input1 = new ExpressionInput(table.getColumnName(0),parser); input1.setOnUserAction(mainController); ExpressionInput input2 = new ExpressionInput(table.getColumnName(1),parser); input2.setOnUserAction(mainController); // Make a scatter plot that graphs the first expressiong vs. the second expression. scatterPlot = new ScatterPlot(table, input1.getExpression(), input2.getExpression()); if ( ! "yes".equalsIgnoreCase(getParameter("ShowRegressionLine","yes"))) scatterPlot.setShowRegressionLine(false); if ( ! "yes".equalsIgnoreCase(getParameter("MissingValueIsError","yes"))) scatterPlot.setMissingValueIsError(false); // Create the display canvas where the scater plot will be shown. canvas = new DisplayCanvas(); canvas.add(new Axes()); canvas.add(scatterPlot); mainController.setErrorReporter(canvas); // A compute button to recompute everything. ComputeButton computeButton = new ComputeButton("Update Display"); computeButton.setOnUserAction(mainController); computeButton.setBackground(Color.lightGray); // A menu of files that can be loaded. If no filenames are provided as // applet parameters, then menu is null. Panel menu = makefileMenu(); // Lay out the components in the applet. JCMPanel inputPanel = null; Panel bottom = null; //might not be a JCMPanel if ( "yes".equalsIgnoreCase(getParameter("UseExpressionInputs","yes"))) { inputPanel = new JCMPanel(1,2); inputPanel.setBackground(Color.lightGray); JCMPanel leftInput = new JCMPanel(); leftInput.add(new Label(" Plot: "), BorderLayout.WEST); leftInput.add(input1, BorderLayout.CENTER); inputPanel.add(leftInput); JCMPanel rightInput = new JCMPanel(); rightInput.add(new Label(" versus: "), BorderLayout.WEST); rightInput.add(input2, BorderLayout.CENTER); inputPanel.add(rightInput); bottom = new JCMPanel(new BorderLayout(12,3)); bottom.add(inputPanel, BorderLayout.CENTER); bottom.add(computeButton, BorderLayout.EAST); } if ( scatterPlot.getShowRegressionLine() && "yes".equalsIgnoreCase(getParameter("ShowStats","yes")) ) { // Make a display label to show some statistics about the data. DisplayLabel dl = new DisplayLabel( "Slope = #; Intercept = #; Correlation = #", new Value[] { scatterPlot.getValueObject(ScatterPlot.SLOPE), scatterPlot.getValueObject(ScatterPlot.INTERCEPT), scatterPlot.getValueObject(ScatterPlot.CORRELATION) } ); dl.setAlignment(Label.CENTER); dl.setBackground(Color.lightGray); dl.setForeground(new Color(200,0,0)); dl.setFont(new Font("Serif",Font.PLAIN,14)); if (bottom != null) bottom.add(dl, BorderLayout.SOUTH); else { bottom = new JCMPanel(new BorderLayout(12,3)); bottom.add(dl, BorderLayout.CENTER); bottom.add(computeButton, BorderLayout.EAST); } } if (bottom == null) { if (menu != null) menu.add(computeButton, BorderLayout.EAST); else { bottom = new Panel(); bottom.add(computeButton); } } panel.add(canvas, BorderLayout.CENTER); panel.add(table, BorderLayout.WEST); if (bottom != null) panel.add(bottom, BorderLayout.SOUTH); if (menu != null) panel.add(menu, BorderLayout.NORTH); else { String title = getParameter("PanelTitle"); if (title != null) { Label pt = new Label(title, Label.CENTER); pt.setBackground(Color.lightGray); pt.setForeground(new Color(200,0,0)); pt.setFont(new Font("Serif",Font.PLAIN,14)); panel.add(pt, BorderLayout.NORTH); } } return panel; } // end makeMainPanel() private Panel makefileMenu() { // If the applet tag contains params named "File", "File1", "File2", ..., use // their values to make a file menu. If the value of the param contains a ";", // then the first part, up to the ";", goes into the menu and the second part // is the name of the file. If there is no ";", then the entire value is // shown in the menu and is also used as the name of the file. The actual // files must be in the same directory as the Web page that contains the applet. Vector names = new Vector(); fileMenu = new Choice(); String file = getParameter("File"); int ct = 1; if (file == null) { file = getParameter("File1"); ct = 2; } while (file != null) { file = file.trim(); int pos = file.indexOf(";"); String menuEntry; if (pos == -1) menuEntry = file; else { menuEntry = file.substring(0,pos).trim(); file = file.substring(pos+1).trim(); } names.addElement(file); fileMenu.add(menuEntry); file = getParameter("File" + ct); ct++; } if (names.size() == 0) { fileMenu = null; return null; } else { fileNames = new String[names.size()]; for (int i = 0; i < names.size(); i++) fileNames[i] = (String)names.elementAt(i); Panel p = new Panel(); p.setBackground(Color.lightGray); p.setLayout(new BorderLayout(5,5)); p.add(fileMenu,BorderLayout.CENTER); loadFileButton = new Button("Load Data File: "); loadFileButton.addActionListener(this); p.add(loadFileButton,BorderLayout.WEST); fileMenu.setBackground(Color.white); return p; } } private void doLoadFile(String name) { // Load the file from the same directory as the Web page and put the data // from the file into the table. The file should contain two numbers on // each line. InputStream in; try { URL url = new URL(getDocumentBase(), name); in = url.openStream(); } catch (Exception e) { canvas.setErrorMessage(null,"Unable to open file named \"" + name + "\": " + e); return; } Reader inputReader = new InputStreamReader(in); try { table.readFromStream(inputReader); inputReader.close(); } catch (Exception e) { canvas.setErrorMessage(null,"Unable to get data from file \"" + name + "\": " + e.getMessage()); return; } mainController.compute(); } /** * Respond when user clicks a button; not meant to be called directly. * This opens and closes the separate window. */ synchronized public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); if (loadFileButton != null && source == loadFileButton) { doLoadFile( fileNames[fileMenu.getSelectedIndex()] ); } else if (source == launchButton && launchButton != null) { // Open or close separate frame. launchButton.setEnabled(false); if (frame == null) { frame = new Frame(frameTitle); frame.add(makeMainPanel()); frame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent evt) { frame.dispose(); } public void windowClosed(WindowEvent evt) { frameClosed(); } } ); frame.pack(); frame.setLocation(50,50); frame.show(); launchButton.setLabel("Close Window"); launchButton.setEnabled(true); } else { frame.dispose(); } } } synchronized private void frameClosed() { // respond when separate window closes. frame = null; launchButton.setLabel(launchButtonName); launchButton.setEnabled(true); } /** * Return the applet parameter with a given param name, but if no * such applet param exists, return a default value instead. */ protected String getParameter(String paramName, String defaultValue) { String val = getParameter(paramName); return (val == null)? defaultValue : val; } public static void main(String[] a){ javax.swing.JFrame f = new javax.swing.JFrame(); Applet app = new SimpleGraph(); app.init(); f.getContentPane().add (app); f.pack(); f.setSize (new Dimension (500, 500)); f.setVisible(true); } } // end class ScatterPlotApplet