/*
	scatterRegress applet takes pairs of numbers from a 
	TEXT file, and computes R square and Linear regression
	Line.  Other features include an active Mouse pointer to
	help identify the coordinates of a data point, shows/hides 
	Regression line & r^2, and custom ranges of the x and y axes.
	
	Version 1.0 - 27 Oct 1999 Chris Thiel <cct@ktb.net>
	
	Next Version: Label x and Y axis
			
*/

import java.lang.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.util.*;
import java.io.*;

import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
	
public class scatterRegressFile extends Applet{
	int MAX=200;
	int MARGIN=30;
	int n=0;
	String dataFileName;
	String userInput=null;
	String s=null;
	String message=null;
	float x[] = new float[MAX];
	float y[] = new float[MAX];
	float xMean, yMean;
    float B0, B1, R_square,Var_x,Var_y;
	float xMin, yMin, xMax,yMax;
	int xM,yM,i=0;
	double w,h, xFactor, yFactor;
	boolean autoRange=true;
	boolean showLine=true;
	boolean showFormula=true;
	boolean mousePointer=true;
	String		title;
    Font		titleFont;
    FontMetrics		titleFontMetrics;
    int			titleHeight = 15;
    InputStream is;
/*
	Compute is the routine called to compute the Statistical Data
*/	

	public void  compute(){
	// Now calculate regression coeffecients
    	float Sx = 0, Sy =0;
    	float Sxx = 0, Sxy = 0, Syy = 0;
    	 w=(double)(size().width)-2*MARGIN;
    	 h=(double)(size().height)-2*MARGIN;
		// first see if axes' range will be based on data or not 
		if (autoRange) {
			xMin = (999999);
			yMin = (999999);
			xMax = (-999999);
			yMax = (-999999);
			for (int i=0; i<n; i++){
				if (x[i]<xMin) xMin=x[i];
    			if (x[i]>xMax) xMax=x[i];
    			if (y[i]<yMin) yMin=y[i];
    			if (y[i]>yMax) yMax=y[i];
			}
		}
    	for(int i=0; i< n; i++)
    	{
    		
      		Sx += x[i]; 
      		Sy += y[i];
    	}
    	xFactor= (w-10.0)/(xMax-xMin);
    	yFactor= (h-10.0)/(yMax-yMin);
    	xMean = Sx / n;
    	yMean = Sy / n;
    	for(int i=0; i< n; i++)
    	{
      		Sxx += (x[i]-xMean) * (x[i]-xMean);
      		Sxy += (x[i]-xMean) * (y[i]-yMean);
      		Syy += (y[i]-yMean) * (y[i]-yMean);
    	}
    	B1=Sxy/Sxx;
    	B0 = yMean - B1 * xMean;
    	R_square=(Sxy*Sxy)/(Sxx*Syy);
	}
	
   
    public void init() {
    	i =0;
    	String rs;
    	dataFileName = getParameter("data");
    	if (dataFileName == null)
	    dataFileName = "sampledata.txt";
	    rs = getParameter("n");
    	if (rs !=null) n = Integer.parseInt(rs);
	    try {
             BufferedReader dis = new BufferedReader( new InputStreamReader(new URL(getDocumentBase(), dataFileName).openStream()));
           
            
			int i=0;
            try {
                while (i<n) {
                	String s = dis.readLine();
                	if ( s.charAt(0) != '#'){
                		x[i]=Float.valueOf(s.substring(0,s.indexOf(" "))).floatValue(); 
	  					y[i]=Float.valueOf(s.substring(s.indexOf(" "),s.length())).floatValue(); 
      	 				i++;
      	 			}		
                }
            } catch (EOFException e) { message = "Ooops "+e.toString();
            }
            
            dis.close();
        } catch (FileNotFoundException e) {
            message = "Ooops "+e.toString();
        } catch (IOException e) {
            message = "Ooops "+e.toString();
        }
	
		titleFont = new java.awt.Font("Courier", Font.BOLD, 12);
		titleFontMetrics = getFontMetrics(titleFont);
		title = getParameter("title");
		autoRange=false;
		rs = getParameter("xMin");
		if (rs == null) {
	      autoRange=true;
		} else {
	    	xMin=Float.valueOf(rs).floatValue();
		}
		rs = getParameter("yMin");
		if (rs == null) {
	      autoRange=true;
		} else {
	    	yMin =Float.valueOf(rs).floatValue();
		}
		rs = getParameter("xMax");
		if (rs == null) {
	      autoRange=true;
		} else {
	    	xMax = Float.valueOf(rs).floatValue();
	    	
		}
		rs = getParameter("yMax");
		if (rs == null) {
	      autoRange=true;
		} else {
	    	yMax = Float.valueOf(rs).floatValue();
	    	
		}
		rs = getParameter("showLine");
		if ((rs=="false")||(rs == null)) {
	      showLine=false;
		} else {
	    	showLine=true;
		}
		rs = getParameter("showFormula");
		if ((rs=="false")|| (rs == null)) {
	      showFormula=false;
		} else {
	    	showFormula = true;
		}
		rs = getParameter("mousePointer");
		if ((rs=="false")|| (rs == null)) {
	        mousePointer=false;
		} else {
	    	mousePointer = true;
		}
		compute();
		repaint();
	}
	private int CX(float x0){
		return (int)( (x0-xMin)*xFactor)+MARGIN;
	}
	private int CY(float y0){
		return size().height-(int)((y0-yMin)*yFactor)-MARGIN;
	}
	public void paint( Graphics g ) {
		
		g.drawString( title, (size().width-title.length())/2, 15 );
		if (n == MAX) {
			g.drawString( "WARNING: Maximum number of Pairs found", 5,size().height-48);
		 	g.drawString( "subsequent pairs ignored", 35,size().height-36);
		 	}
		if (showFormula){
			g.drawString("n = "+n+" Regression Line Equation:",2*MARGIN,30);
    		g.drawString("y  = "+B1+" * x + "+B0,2*MARGIN,45);
    		g.drawString("r   = "+R_square,2*MARGIN,60); 
    		g.drawString("^",2*MARGIN,43);
        	g.drawString("2",2*MARGIN+5,57);
        }
        if (showLine){
        	g.setColor(Color.red);
        	g.drawLine(CX(xMin),CY(B1*xMin+B0) ,CX(xMax), CY(B1*xMax+B0));
        }
    	if (mousePointer){
    		g.setColor(Color.magenta);
    		g.drawString("("+xM+", "+yM+")", CX(xM),CY(yM));
		}
		//draw y labels and axis
		g.setColor(Color.black);
		g.drawLine(MARGIN,MARGIN, MARGIN,size().height-MARGIN);
		for (float i=yMin; i<= yMax; i+= (yMax-yMin)/10){
			g.drawString(" "+i,0, CY(i)+2);
			g.drawLine(MARGIN-2,CY(i),MARGIN+2,CY(i));
		}
		//draw xlabels and axis
		g.drawLine(MARGIN,size().height-MARGIN, size().width-MARGIN,size().height-MARGIN);
		for (float i=xMin; i<= xMax; i+= (xMax-xMin)/10){
			g.drawString(" "+i, CX(i)-10,size().height);
			g.drawLine(CX(i),size().height-MARGIN+2,CX(i),size().height-MARGIN-2);
		}
		//draw scatterplot
		g.setColor(Color.blue);
		for (int i=0; i<n; i++){
			g.fillOval( CX(x[i]), CY(y[i]), 3,3);
		
		}
		if (message != null) {
	    	g.drawString("Error in data: "+message, MARGIN, 150);
	    	g.drawString("Make sure there are two numbers per line, separated by space", MARGIN, 170);

			}
		}
	/*
     * Mouse methods
     */
    public boolean mouseDown(java.awt.Event evt, int x0, int y0) {
      
        repaint();
        return true;
    }
	
  	
  	
    public boolean mouseMove(java.awt.Event evt, int x0, int y0) {
        
         if (mousePointer){
        	y0 = size().height - y0 + 4;
         	requestFocus();
         	xM = (int)((x0-MARGIN)/xFactor+xMin);
        	yM = (int)((y0-MARGIN)/yFactor+yMin);
        	getAppletContext().showStatus("Location of mouse: (" + xM + ", " + yM + ")");
        repaint();
        }
        return true;
    }

    public void mouseEnter() {
        repaint();
    }

    public void mouseExit() {
       
        repaint();
    }

}    
    