Subversion Repositories wimsdev

Rev

Rev 3653 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*************************************************************************
  2. *                                                                        *
  3. *  This source code file, and compiled classes derived from it, can      *
  4. *  be used and distributed without restriction, including for commercial *
  5. *  use.  (Attribution is not required but is appreciated.)               *
  6. *                                                                        *
  7. *   David J. Eck                                                         *
  8. *   Department of Mathematics and Computer Science                       *
  9. *   Hobart and William Smith Colleges                                    *
  10. *   Geneva, New York 14456,   USA                                        *
  11. *   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
  12. *                                                                        *
  13. *************************************************************************/
  14.  
  15.  
  16.  
  17. import edu.hws.jcm.awt.*;
  18. import edu.hws.jcm.data.*;
  19. import edu.hws.jcm.draw.*;
  20.  
  21. import java.awt.*;
  22. import java.awt.event.*;
  23. import java.io.*;
  24. import java.net.*;
  25. import java.util.*;
  26. import java.applet.Applet;
  27.  
  28. /**
  29.  * A ScatterPlotApplet shows a scatter plot of data from a DataTableInput.
  30.  * The user can enter the data in a two-column table that is shown in
  31.  * the applet.  It is also possible to configure the applet with a menu
  32.  * of file names.  These files, which must be in the same directory as
  33.  * the Web page on which the applet appears, will appear in a menu.
  34.  * A file can contain data for the table, with two numbers per line.
  35.  * When the user loads the file, the data replaces the data in the table.
  36.  */
  37.  
  38. public class ScatterPlotApplet extends Applet implements ActionListener {
  39.  
  40.    private Frame frame;       // If non-null, a separate window.
  41.    private String frameTitle; // Title for the separate window.
  42.    private Button launchButton;  // If non-null, then clicking this buttons opens a separate window.
  43.    private String launchButtonName;  // Name for the launch button.
  44.    
  45.    private DataTableInput table;    //  The table for input of data.
  46.    private ScatterPlot scatterPlot; //  The scatter plot of the data.
  47.    private DisplayCanvas canvas;    //  The DisplayCanvas on which the plot is drawn.
  48.    private Button loadFileButton;   //  When clicked, a data file is loaded.
  49.    private Choice fileMenu;         //  Pop-up menu containing names of functions.
  50.    private String[] fileNames;      //  Names of data files associated with menu entries.
  51.    private Controller mainController;  // Controller from the main JCMPanel.
  52.  
  53.    /**
  54.     * The init() method is called by the system to set up the applet.
  55.     * If the applet does not appear as a button, then init() creates the main panel of the applet
  56.     * and calls setUpMainPanel to set it up.
  57.     */
  58.    public void init() {
  59.       frameTitle = getParameter("FrameTitle"); // Get title to be used for separate window, if any.
  60.       if (frameTitle == null) {
  61.          frameTitle = "Scatter Plots";
  62.          int pos = frameTitle.lastIndexOf('.');
  63.          if (pos > -1)
  64.             frameTitle =  frameTitle.substring(pos+1);
  65.       }
  66.       setLayout(new BorderLayout());
  67.       int height = getSize().height;
  68.       launchButtonName = getParameter("LaunchButtonName");
  69.       if ( (height > 0 && height <= 50) || launchButtonName != null) {
  70.               // Use a separater window and only show a button in the applet.
  71.           if (launchButtonName == null)
  72.                launchButtonName = "Launch " + frameTitle;
  73.           launchButton = new Button(launchButtonName);
  74.           add(launchButton, BorderLayout.CENTER);
  75.           launchButton.addActionListener(this);
  76.       }
  77.       else {
  78.              // Show the main panel in the applet, not in a separate window.
  79.           add(makeMainPanel(), BorderLayout.CENTER);
  80.       }
  81.    }
  82.  
  83.    /*
  84.     * Create the main panel of the applet.
  85.     */
  86.    public Panel makeMainPanel() {
  87.    
  88.       // Make the main panel
  89.    
  90.       JCMPanel panel = new JCMPanel(2);
  91.       mainController = panel.getController();
  92.       panel.setBackground(new Color(0,0,180));
  93.       panel.setInsetGap(2);
  94.       setLayout(new BorderLayout());
  95.      
  96.       // Make a DataInputTable with two columns
  97.      
  98.       table = new DataTableInput(null, 2);
  99.       table.setColumnName(0, getParameter("ColumnName1", "X"));
  100.       table.setColumnName(1, getParameter("ColumnName2", "Y"));
  101.       table.setThrowErrors(true);
  102.       if ( "yes".equalsIgnoreCase(getParameter("ShowColumnTitles","yes")))
  103.          table.setShowColumnTitles(true);
  104.       if ( "yes".equalsIgnoreCase(getParameter("ShowRowNumbers","yes")))
  105.          table.setShowRowNumbers(true);
  106.                                  
  107.       // Make input boxes for getting expressions that can include
  108.       // the variables associated with the table.  Initially, the
  109.       // expressions are just the column names.
  110.  
  111.       Parser parser = new Parser();
  112.       table.addVariablesToParser(parser);
  113.       ExpressionInput input1 = new ExpressionInput(table.getColumnName(0),parser);
  114.       input1.setOnUserAction(mainController);
  115.       ExpressionInput input2 = new ExpressionInput(table.getColumnName(1),parser);
  116.       input2.setOnUserAction(mainController);
  117.      
  118.       // Make a scatter plot that graphs the first expressiong vs. the second expression.
  119.  
  120.       scatterPlot = new ScatterPlot(table, input1.getExpression(), input2.getExpression());
  121.       if ( ! "yes".equalsIgnoreCase(getParameter("ShowRegressionLine","yes")))
  122.         scatterPlot.setShowRegressionLine(false);
  123.       if ( ! "yes".equalsIgnoreCase(getParameter("MissingValueIsError","yes")))
  124.         scatterPlot.setMissingValueIsError(false);
  125.        
  126.       // Create the display canvas where the scater plot will be shown.
  127.  
  128.       canvas = new DisplayCanvas();
  129.       canvas.add(new Axes());
  130.       canvas.add(scatterPlot);
  131.       mainController.setErrorReporter(canvas);
  132.      
  133.       // A compute button to recompute everything.
  134.      
  135.       ComputeButton computeButton = new ComputeButton("Update Display");
  136.       computeButton.setOnUserAction(mainController);
  137.       computeButton.setBackground(Color.lightGray);
  138.      
  139.       // A menu of files that can be loaded.  If no filenames are provided as
  140.       // applet parameters, then menu is null.
  141.      
  142.       Panel menu = makefileMenu();
  143.      
  144.       // Lay out the components in the applet.
  145.      
  146.       JCMPanel inputPanel = null;
  147.       Panel bottom = null;  //might not be a JCMPanel
  148.       if ( "yes".equalsIgnoreCase(getParameter("UseExpressionInputs","yes"))) {
  149.          inputPanel = new JCMPanel(1,2);
  150.          inputPanel.setBackground(Color.lightGray);
  151.          JCMPanel leftInput = new JCMPanel();
  152.          leftInput.add(new Label("  Plot:  "), BorderLayout.WEST);
  153.          leftInput.add(input1, BorderLayout.CENTER);
  154.          inputPanel.add(leftInput);
  155.          JCMPanel rightInput = new JCMPanel();
  156.          rightInput.add(new Label(" versus: "), BorderLayout.WEST);
  157.          rightInput.add(input2, BorderLayout.CENTER);
  158.          inputPanel.add(rightInput);
  159.          bottom = new JCMPanel(new BorderLayout(12,3));
  160.          bottom.add(inputPanel, BorderLayout.CENTER);
  161.          bottom.add(computeButton, BorderLayout.EAST);
  162.       }
  163.      
  164.       if ( scatterPlot.getShowRegressionLine() && "yes".equalsIgnoreCase(getParameter("ShowStats","yes")) ) {
  165.             // Make a display label to show some statistics about the data.
  166.          DisplayLabel dl = new DisplayLabel(
  167.                "Slope = #;  Intercept = #;  Correlation = #",
  168.                 new Value[] { scatterPlot.getValueObject(ScatterPlot.SLOPE),
  169.                               scatterPlot.getValueObject(ScatterPlot.INTERCEPT),
  170.                               scatterPlot.getValueObject(ScatterPlot.CORRELATION) }
  171.             );
  172.          dl.setAlignment(Label.CENTER);
  173.          dl.setBackground(Color.lightGray);
  174.          dl.setForeground(new Color(200,0,0));
  175.          dl.setFont(new Font("Serif",Font.PLAIN,14));
  176.          if (bottom != null)
  177.             bottom.add(dl, BorderLayout.SOUTH);
  178.          else {
  179.             bottom = new JCMPanel(new BorderLayout(12,3));
  180.             bottom.add(dl, BorderLayout.CENTER);
  181.             bottom.add(computeButton, BorderLayout.EAST);
  182.          }
  183.       }
  184.      
  185.       if (bottom == null) {
  186.          if (menu != null)
  187.             menu.add(computeButton, BorderLayout.EAST);
  188.          else {
  189.             bottom = new Panel();
  190.             bottom.add(computeButton);
  191.          }
  192.       }
  193.      
  194.       panel.add(canvas, BorderLayout.CENTER);
  195.       panel.add(table, BorderLayout.WEST);
  196.       if (bottom != null)
  197.          panel.add(bottom, BorderLayout.SOUTH);
  198.       if (menu != null)
  199.          panel.add(menu, BorderLayout.NORTH);
  200.       else {
  201.          String title = getParameter("PanelTitle");
  202.          if (title != null) {
  203.             Label pt = new Label(title, Label.CENTER);
  204.             pt.setBackground(Color.lightGray);
  205.             pt.setForeground(new Color(200,0,0));
  206.             pt.setFont(new Font("Serif",Font.PLAIN,14));
  207.             panel.add(pt, BorderLayout.NORTH);
  208.          }
  209.       }
  210.          
  211.       return panel;
  212.      
  213.    } // end makeMainPanel()
  214.    
  215.    
  216.    private Panel makefileMenu() {
  217.          // If the applet tag contains params named "File", "File1", "File2", ..., use
  218.          // their values to make a file menu.  If the value of the param contains a ";",
  219.          // then the first part, up to the ";", goes into the menu and the second part
  220.          // is the name of the file.  If there is no ";", then the entire value is
  221.          // shown in the menu and is also used as the name of the file.  The actual
  222.          // files must be in the same directory as the Web page that contains the applet.
  223.       Vector names = new Vector();
  224.       fileMenu = new Choice();
  225.       String file = getParameter("File");
  226.       int ct = 1;
  227.       if (file == null) {
  228.          file = getParameter("File1");
  229.          ct = 2;
  230.       }
  231.       while (file != null) {
  232.          file = file.trim();
  233.          int pos = file.indexOf(";");
  234.          String menuEntry;
  235.          if (pos == -1)
  236.             menuEntry = file;
  237.          else {
  238.             menuEntry = file.substring(0,pos).trim();
  239.             file = file.substring(pos+1).trim();
  240.          }
  241.          names.addElement(file);
  242.          fileMenu.add(menuEntry);
  243.          file = getParameter("File" + ct);
  244.          ct++;
  245.       }
  246.       if (names.size() == 0) {
  247.          fileMenu = null;
  248.          return null;
  249.       }
  250.       else {
  251.          fileNames  = new String[names.size()];
  252.          for (int i = 0; i < names.size(); i++)
  253.             fileNames[i] = (String)names.elementAt(i);
  254.          Panel p = new Panel();
  255.          p.setBackground(Color.lightGray);
  256.          p.setLayout(new BorderLayout(5,5));
  257.          p.add(fileMenu,BorderLayout.CENTER);
  258.          loadFileButton = new Button("Load Data File: ");
  259.          loadFileButton.addActionListener(this);
  260.          p.add(loadFileButton,BorderLayout.WEST);
  261.          fileMenu.setBackground(Color.white);
  262.          return p;
  263.       }
  264.    }
  265.    
  266.    private void doLoadFile(String name) {
  267.         // Load the file from the same directory as the Web page and put the data
  268.         // from the file into the table.  The file should contain two numbers on
  269.         // each line.
  270.       InputStream in;
  271.       try {
  272.          URL url = new URL(getDocumentBase(), name);
  273.          in = url.openStream();
  274.       }
  275.       catch (Exception e) {
  276.          canvas.setErrorMessage(null,"Unable to open file named \"" + name + "\": " + e);
  277.          return;
  278.       }
  279.       Reader inputReader = new InputStreamReader(in);
  280.       try {
  281.          table.readFromStream(inputReader);
  282.          inputReader.close();
  283.       }
  284.       catch (Exception e) {
  285.          canvas.setErrorMessage(null,"Unable to get data from file \"" + name + "\": " + e.getMessage());
  286.          return;
  287.       }
  288.       mainController.compute();
  289.    }
  290.  
  291.    /**
  292.     *  Respond when user clicks a button; not meant to be called directly.
  293.     *  This opens and closes the separate window.
  294.     */
  295.    synchronized public void actionPerformed(ActionEvent evt) {
  296.       Object source = evt.getSource();
  297.       if (loadFileButton != null && source == loadFileButton) {
  298.          doLoadFile( fileNames[fileMenu.getSelectedIndex()] );
  299.       }
  300.       else if (source == launchButton && launchButton != null) {
  301.             // Open or close separate frame.
  302.          launchButton.setEnabled(false);
  303.          if (frame == null) {
  304.             frame = new Frame(frameTitle);
  305.             frame.add(makeMainPanel());
  306.             frame.addWindowListener( new WindowAdapter() {
  307.                   public void windowClosing(WindowEvent evt) {
  308.                      frame.dispose();
  309.                   }
  310.                   public void windowClosed(WindowEvent evt) {
  311.                      frameClosed();
  312.                   }
  313.                } );
  314.             frame.pack();
  315.             frame.setLocation(50,50);
  316.             frame.setVisible(true);
  317.             launchButton.setLabel("Close Window");
  318.             launchButton.setEnabled(true);
  319.          }
  320.          else {
  321.             frame.dispose();
  322.          }
  323.       }
  324.    }
  325.    
  326.    synchronized private void frameClosed() {
  327.         // respond when separate window closes.
  328.       frame = null;
  329.       launchButton.setLabel(launchButtonName);
  330.       launchButton.setEnabled(true);
  331.    }
  332.    
  333.    /**
  334.     *  Return the applet parameter with a given param name, but if no
  335.     *  such applet param exists, return a default value instead.
  336.     */
  337.    protected String getParameter(String paramName, String defaultValue) {
  338.        String val = getParameter(paramName);
  339.        return (val == null)? defaultValue : val;
  340.    }
  341.    
  342. } // end class ScatterPlotApplet
  343.  
  344.