Curve-O-Matic
<< Determinant | OtherProjectsTrailIndex | State Applet >>
The runnable jar file is here: CurveOMatic.jar A Mac version is here : http://www.mathorama.com/Curve-O-Matic.dmg
CurveOMatic.java
import java.awt.*; import java.awt.event.*; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Scanner; import javax.swing.*; @SuppressWarnings("serial") public class CurveOMatic extends JFrame implements ActionListener { private Button openButton, curveButton, sortButton; private Button saveGQButton, showGQButton; Panel centerPanel, listPanel, titlePanel; JScrollPane sp; BarChart chart; ArrayList<LineItem> names; TextArea message; JTextField raw1=new JTextField(); JTextField raw2=new JTextField(); JTextField curve1=new JTextField(); JTextField curve2=new JTextField(); int r1,r2,c1,c2; String curveExplanation=""; final JComponent[] inputs = new JComponent[] { new JLabel("Map raw score "), raw1, new JLabel("to "), curve1, new JLabel("Map raw score "), raw2, new JLabel("to "), curve2 }; public CurveOMatic(){ super("Curve-O-Matic"); this.setSize(800,600); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); r1=1; c1=1; r2=100; c2=100; //add buttons and such message = new TextArea("Tab to next score, Enter to update\nStudent File format: ID, Last, First"); message.setPreferredSize(new Dimension (this.getWidth(),80)); this.setLayout(new BorderLayout()); this.add(message, BorderLayout.SOUTH); openButton = new Button("Load Student File"); openButton.addActionListener(this); curveButton = new Button("Set Curve"); curveButton.addActionListener(this); sortButton = new Button("Sort"); sortButton.addActionListener(this); saveGQButton = new Button("Save GQ File"); saveGQButton.addActionListener(this); showGQButton = new Button("Show GQ File"); showGQButton.addActionListener(this); Panel north = new Panel(new FlowLayout()); north.add(openButton); north.add(sortButton); north.add(curveButton); north.add(showGQButton); north.add(saveGQButton); this.add(north, BorderLayout.NORTH); listPanel=new Panel(new GridLayout(0,1)); names = new ArrayList<LineItem>(); for (int i=1; i<=32;i++){ Student s = new Student(i, " Name "+i+" "); LineItem item=new LineItem(s, this); names.add(item); Panel linePanel=new Panel(new FlowLayout(FlowLayout.LEFT)); linePanel.add(item.getNameLabel()); linePanel.add(item.getRawScoreField()); linePanel.add(item.getCurveScore()); linePanel.setPreferredSize(new Dimension(370, 23)); listPanel.add(linePanel); } sp = new JScrollPane(listPanel); centerPanel=new Panel(new GridLayout(0,2)); centerPanel.add(sp); chart = new BarChart(names); centerPanel.add(chart); add(centerPanel, BorderLayout.CENTER); } public static void main(String[] args) { CurveOMatic app= new CurveOMatic(); app.setVisible(true); } public void actionPerformed(ActionEvent e) { if (e.getSource()==openButton ){ try{ readFile(); }catch(IOException ex){ } }else if (e.getSource()==sortButton){ int sortBy=sortDialog(); if (sortBy>0){ doSort(sortBy); } }else if (e.getSource()==curveButton){ JOptionPane.showMessageDialog(null, inputs, "Set Curve", JOptionPane.PLAIN_MESSAGE); try{ r1=Integer.parseInt(raw1.getText()); r2=Integer.parseInt(raw2.getText()); c1=Integer.parseInt(curve1.getText()); c2=Integer.parseInt(curve2.getText()); setCurve(); chart.repaint(); }catch( Exception exception){ } }else if (e.getSource()==showGQButton){ showGQDialog(); }else if (e.getSource()==saveGQButton){ saveGQDialog(); }else { //User typed a return while changing a raw score for(int i=0;i<names.size();i++){ names.get(i).updateRawScore(); } setCurve(); chart.repaint(); //System.out.println(e.getActionCommand()+" "); } } private void doSort(int sortBy) { if (sortBy==LineItem.NamesAscending) Collections.sort(names); if (sortBy==LineItem.NamesDescending){ Comparator<LineItem> comp = Collections.reverseOrder(); Collections.sort(names, comp); } if (sortBy==LineItem.ScoresAsecending) Collections.sort(names, LineItem.ScoreComparator); if (sortBy==LineItem.ScoresDescending){ Comparator<LineItem> comp = Collections.reverseOrder(LineItem.ScoreComparator); Collections.sort(names, comp); } listPanel=new Panel(new GridLayout(0,1)); for (int i=0; i<names.size();i++){ Panel linePanel=new Panel(new FlowLayout(FlowLayout.LEFT)); linePanel.add(names.get(i).getNameLabel()); linePanel.add(names.get(i).getRawScoreField()); linePanel.add(names.get(i).getCurveScore()); linePanel.setPreferredSize(new Dimension(370, 23)); listPanel.add(linePanel); } sp = new JScrollPane(listPanel); remove(centerPanel); centerPanel=new Panel(new GridLayout(0,2)); centerPanel.add(sp); setCurve(); chart = new BarChart(names); centerPanel.add(chart); add(centerPanel, BorderLayout.CENTER); validate(); } public void readFile()throws IOException{ String path = new java.io.File(".").getCanonicalPath(); path=System.getProperty("user.dir"); JFileChooser chooser = new JFileChooser(path); if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { names = new ArrayList<LineItem>(); FileReader reader = new FileReader(chooser.getSelectedFile()); Scanner fileIn = new Scanner(reader); listPanel=new Panel(new GridLayout(0,1)); while (fileIn.hasNextLine()){ String line=fileIn.nextLine(); String [] args=line.split(","); Student s=new Student(args); LineItem item = new LineItem(s, this); names.add(item); Panel linePanel=new Panel(new FlowLayout(FlowLayout.LEFT)); linePanel.add(item.getNameLabel()); linePanel.add(item.getRawScoreField()); linePanel.add(item.getCurveScore()); linePanel.setPreferredSize(new Dimension(370, 23)); listPanel.add(linePanel); } fileIn.close(); sp = new JScrollPane(listPanel); remove(centerPanel); centerPanel=new Panel(new GridLayout(0,2)); centerPanel.add(sp); setCurve(); chart = new BarChart(names); centerPanel.add(chart); add(centerPanel, BorderLayout.CENTER); validate(); } } public void setCurve(){ if (r2-r1==0){ message.append( "\nDivision by zero - Try again"); return; } int rise=c2-c1; int run=r2-r1; Rational slope=new Rational(rise,run); curveExplanation= "Mapping "+r1+" --> "+c1+" and "+r2+" --> "+c2+"\r\n"; curveExplanation+="Curve = ("+slope.toString()+")(raw - "+r2+") + "+c2; message.setText(curveExplanation); for(int i=0; i<names.size();i++){ int r=names.get(i).getStudent().getRaw(); int c=(int)(c2+slope.value()*(r-r2)); if (r>=0){ names.get(i).getStudent().setCurve(c); names.get(i).updateCurveScore(); }else { names.get(i).getStudent().setCurve(-1); names.get(i).updateCurveScore(); } } validate(); } public int sortDialog(){ JRadioButton na = new JRadioButton("<html><font color=black>Names, Ascending</font></html>"); JRadioButton nd = new JRadioButton("<html><font color=black>Names, Descending</font></html>"); JRadioButton sa = new JRadioButton("<html><font color=blue>Scores, Ascending</font></html>"); JRadioButton sd = new JRadioButton("<html><font color=blue>Scores, Descending</font></html>"); na.setSelected(true); ButtonGroup group = new ButtonGroup(); group.add(na); group.add(nd); group.add(sa); group.add(sd); Object[] array = { new JLabel("Sort by:"), na, nd, sa, sd }; int res = JOptionPane.showConfirmDialog(null, array, "Select", JOptionPane.OK_CANCEL_OPTION); if (res == JOptionPane.CANCEL_OPTION) return 0; if (na.isSelected()) return LineItem.NamesAscending; if (nd.isSelected()) return LineItem.NamesDescending; if (sa.isSelected()) return LineItem.ScoresAsecending; return LineItem.ScoresDescending; } public void showGQDialog(){ String nameMessage="The output below is in the format GQ uses to \nimport test scores by Student NAME\nRoster starts on line 3"; nameMessage+="\nName starts on column 1,\nhas 26 characters,\nthe start column for the score is 27\nthe length of the score column is 4"; String idMessage="The output below is in the format GQ uses to \nimport test scores by Student ID\nRoster starts on line 3"; idMessage+="\nID starts on column 1,\nhas 10 characters,\nthe start column for the score is 11\nthe length of the score column is 4"; JRadioButton name = new JRadioButton("<html><font color=black>Scores by NAME</font></html>"); JRadioButton id = new JRadioButton("<html><font color=black>Scores by ID</font></html>"); name.setSelected(true); ButtonGroup group = new ButtonGroup(); group.add(name); group.add(id); Object[] array = { new JLabel("GQ can import scores by NAME or by ID. Choose a method:"), name, id }; int res = JOptionPane.showConfirmDialog(this, array, "Show GQ File", JOptionPane.OK_CANCEL_OPTION); if (res == JOptionPane.CANCEL_OPTION) return; if (res==JOptionPane.CLOSED_OPTION) return; if (name.isSelected()) res = JOptionPane.showConfirmDialog((Component) this, nameMessage, "Import scores by NAME Info", JOptionPane.DEFAULT_OPTION); if (id.isSelected()) res = JOptionPane.showConfirmDialog((Component) this, idMessage, "Import scores by ID Info", JOptionPane.DEFAULT_OPTION); setCurve(); for (int i=0; i< names.size();i++){ Student s = names.get(i).getStudent(); if (name.isSelected()) message.append("\r\n"+s.getGQName()); if (id.isSelected()) message.append("\r\n"+s.getGQID()); } } public void saveGQDialog(){ String nameMessage="The output below is in the format GQ uses to \nimport test scores by Student NAME\nRoster starts on line 3"; nameMessage+="\nName starts on column 1,\nhas 26 characters,\nthe start column for the score is 27\nthe length of the score column is 4"; String idMessage="The output below is in the format GQ uses to \nimport test scores by Student ID\nRoster starts on line 3"; idMessage+="\nID starts on column 1,\n has 10 characters,\nthe start column for the score is 11\nthe length of the score column is 4"; JRadioButton name = new JRadioButton("<html><font color=black>Scores by NAME</font></html>"); JRadioButton id = new JRadioButton("<html><font color=black>Scores by ID</font></html>"); name.setSelected(true); ButtonGroup group = new ButtonGroup(); group.add(name); group.add(id); Object[] array = { new JLabel("GQ can import scores by NAME or by ID. Choose a method:"), name, id }; int res = JOptionPane.showConfirmDialog(this, array, "Show GQ File", JOptionPane.OK_CANCEL_OPTION); if (res == JOptionPane.CANCEL_OPTION) return; if (res==JOptionPane.CLOSED_OPTION) return; if (name.isSelected()){ res = JOptionPane.showConfirmDialog((Component) this, nameMessage, "Import scores by NAME Info", JOptionPane.DEFAULT_OPTION); } if (id.isSelected()){ res = JOptionPane.showConfirmDialog((Component) this, idMessage, "Import scores by ID Info", JOptionPane.DEFAULT_OPTION); } setCurve(); String path = System.getProperty("user.dir");; JFileChooser chooser = new JFileChooser(path); if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { try { PrintWriter out = new PrintWriter(chooser.getSelectedFile()); String line=curveExplanation; out.print(line); for (int i=0; i< names.size();i++){ Student s = names.get(i).getStudent(); if (name.isSelected()) line="\r\n"+s.getGQName(); if (id.isSelected()) line="\r\n"+s.getGQID(); out.print(line); } out.print("\r\n"); out.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
BarChart.java
import java.awt.*; import java.util.ArrayList; @SuppressWarnings("serial") public class BarChart extends Canvas { int[] raw; int[]curve; int scale=10; ArrayList<LineItem> names; Stats rStats,cStats; String message1=""; String message2=""; public BarChart(ArrayList<LineItem> names) { super(); raw=new int[20]; curve=new int[20]; for(int i=0;i<20;i++){ raw[i]=0; curve[i]=0; } this.names=names; message1=""; message2=""; rStats=new Stats(); cStats=new Stats(); } public void paint(Graphics g){ refresh(); Color c= new Color((int)(255*Math.random()), (int)(255*Math.random()), (int)(255*Math.random())); g.setColor(c); int x1=this.getWidth()/2; for(int i=0; i<20;i++ ){ g.fillRect(x1-raw[i]*scale-10,8+20*i, raw[i]*scale, 10);//raw g.fillRect(x1+25,8+20*i, curve[i]*scale, 10);//curve } //Dimension d= this.getSize(); g.setColor(Color.BLACK); g.drawString(rStats.outliers(), 20, 20); g.drawString("n="+rStats.getN(), 20, 40); g.drawString("mean="+rStats.mean(), 20, 60); g.drawString("min="+rStats.min(), 20, 80); g.drawString("Q1="+rStats.q1(), 20, 100); g.drawString("med="+rStats.med(), 20, 120); g.drawString("Q3="+rStats.q3(), 20, 140); g.drawString("max="+rStats.max(), 20, 160); g.drawString("Before curve: "+rStats.gradeCount(), 20, getHeight()-22); g.setColor(Color.blue); g.drawString("After the curve:", 20, getHeight()-182); g.drawString(cStats.outliers(), 20, getHeight()-162); g.drawString("mean="+cStats.mean(), 20, getHeight()-142); g.drawString("min="+cStats.min(), 20, getHeight()-122); g.drawString("Q1="+cStats.q1(), 20, getHeight()-102); g.drawString("med="+cStats.med(), 20, getHeight()-82); g.drawString("Q3="+cStats.q3(), 20, getHeight()-62); g.drawString("max="+cStats.max(), 20, getHeight()-42); g.drawString("After curve: "+cStats.gradeCount(), 20, getHeight()-2); //g.drawString("width = "+this.getWidth(), 20, 60); g.setColor(Color.black); for (int i=5;i<=100; i+=5){ g.drawString(""+i, x1, 5+4*i); } } public void refresh(){ rStats=new Stats(); cStats=new Stats(); for(int i=0;i<20;i++){ raw[i]=0; curve[i]=0; } for(LineItem line:names){ Student n=line.getStudent(); int r=n.getRaw(); if (r>0) rStats.add(r); if(r>99){ raw[19]++; } else if (r>=0){ raw[r/5]++; } int c=n.getCurve(); if (c>0) cStats.add(c); if(c>99){ curve[19]++; } else if (r>=0){ curve[c/5]++; } } } }
Student.java
public class Student implements Comparable<Student> { private String id,last, first; private int raw, curve; public Student(String[] a){ id=a[0].trim(); last=a[1].trim(); first=a[2].trim(); first=first.replaceAll("/comma/", ","); last=last.replaceAll("/comma/", ","); try { setRaw(Integer.parseInt(a[3].trim())); setCurve(getRaw()); //System.out.print(a[3]); }catch (Exception e){ setRaw(-1); setCurve(-1); //System.out.print("'"+a[3]+"'"); } } public Student(int i, String n) { id =""+i; last = n.trim(); first=""; setRaw(-1); setCurve(-1); } public String getName(){ String result= id+" "+first+" "+last; return result; } public String getGQName(){ String result = last+", "+first; while (result.length()<26) result+=" "; if (curve<0) { result+="**"; }else{ result+=curveString(); } return result; } public String getGQID(){ String result = id; while (result.length()<10) result+=" "; if (curve<0) { result+="**"; }else{ result+=curveString(); } return result; } public String getLast(){ return last; } public String getFirst(){ return first; } public void setRaw(int raw) { this.raw = raw; } public int getRaw() { return raw; } public void setCurve(int score) { this.curve = score; } public int getCurve() { return curve; } public String curveString(){ String result=""+curve; while (result.length()<3) result=" "+result; return result; } @Override public int compareTo(Student o) { String thisLast = last.toUpperCase(); String thisFirst = first.toUpperCase(); String otherLast = o.getLast().toUpperCase(); String otherFirst = o.getFirst().toUpperCase(); if (thisLast.equals(otherLast)){ return thisFirst.compareTo(otherFirst); } return thisLast.compareTo(otherLast); } }
Rational.java
public class Rational { private int numerator; private int denominator; public Rational(String s){ int fBar=s.indexOf("/"); if (fBar==-1){ numerator=Integer.parseInt(s); denominator=1; } else { numerator=Integer.parseInt(s.substring(0,fBar)); denominator=Integer.parseInt(s.substring(fBar+1)); simplify(); } } public Rational(int n, int d){ numerator=n; denominator=d; simplify(); } public Rational(int n){ numerator=n; denominator=1; } public Rational(){ numerator=0; denominator=1; } public Rational (Rational r){ this.numerator=r.getNumerator(); this.denominator=r.getDenominator(); } public void setNumerator(int numerator) { this.numerator = numerator; } public int getNumerator() { return numerator; } public void setDenominator(int denominator) { this.denominator = denominator; } public int getDenominator() { return denominator; } public double value(){ return (double)(numerator)/denominator; } public String toString(){ if (denominator ==1) return Integer.toString(numerator); return Integer.toString(numerator)+"/"+Integer.toString(denominator); } public Rational multiply(Rational other){ int n=this.getNumerator()*other.getNumerator(); int d=this.getDenominator()*other.getDenominator(); Rational result=new Rational(n,d); return result; } public Rational add(Rational other){ int n=this.getNumerator()*other.getDenominator()+ other.getNumerator()*this.getDenominator(); int d=this.getDenominator()*other.getDenominator(); Rational result=new Rational(n,d); return result; } public void simplify(){ int p=2; while (p<= Math.max(numerator, denominator)){ while(numerator%p==0 && denominator%p==0){ numerator/=p; denominator/=p; } if (p==2) p++; else p+=2; } if (denominator<0){ denominator*=-1; numerator*=-1; } } }
LineItem.java
import java.awt.Dimension; import java.awt.Label; import java.awt.TextField; import java.awt.event.ActionListener; import java.util.Comparator; public class LineItem implements Comparable<LineItem> { private Student student; private TextField rawScore; private Label curveScore; private Label nameLabel; public final static int NamesAscending=1; public final static int NamesDescending=2; public final static int ScoresAsecending=3; public final static int ScoresDescending=4; public LineItem(Student s, ActionListener al){ setStudent(s); nameLabel = new Label(s.getName()); nameLabel.setPreferredSize(new Dimension(270, 23)); rawScore = new TextField(3); if (s.getRaw()>=0) rawScore.setText(""+s.getRaw()); rawScore.addActionListener(al); setCurveScore(new Label()); if (s.getCurve()>=0) curveScore.setText(""+s.getCurve()); } public void setStudent(Student name) { this.student = name; } public Student getStudent() { return student; } public void setCurveScore(Label curveScore) { this.curveScore = curveScore; } public Label getCurveScore() { return curveScore; } public TextField getRawScoreField() { return rawScore; } public void updateCurveScore(){ if (student.getCurve()>=0) curveScore.setText(""+student.getCurve()); } public void updateRawScore(){ //make sure student records newly updated score in rawScore TextField try{ student.setRaw(Integer.parseInt(rawScore.getText())); }catch (NumberFormatException e){ student.setRaw(-1); } } public void setNameLabel(Label nameLabel) { this.nameLabel = nameLabel; } public Label getNameLabel() { return nameLabel; } @Override public int compareTo(LineItem other) { return getStudent().compareTo(other.getStudent()); } public static Comparator<LineItem> ScoreComparator = new Comparator<LineItem>(){ @Override public int compare(LineItem o1, LineItem o2) { int score1 = o1.getStudent().getRaw(); int score2 = o2.getStudent().getRaw(); return score1-score2; } }; }
Stats.java
import java.util.ArrayList; import java.util.Collections; public class Stats { private ArrayList<Integer> scores; private int n; private int sum; public Stats(){ scores = new ArrayList<Integer>(); n=0; sum=0; } public void add(int x){ scores.add(x); sum+=x; n++; } public void add(String s){ scores.add(Integer.parseInt(s)); } public double mean() { if (n==0) return 0; return (double)(100*sum/n)/100.0; } public double med(){ if (n==0) return 0.0; Collections.sort(scores); if (n%2==0){ return (scores.get(n/2-1)+scores.get(n/2))/2.0; } return (scores.get(n/2)); } public double q1(){ if (n==0) return 0.0; Collections.sort(scores); if (n%4==0){ return (scores.get(n/4-1)+scores.get(n/4))/2.0; } return (scores.get(n/4)); } public double q3(){ if (n==0) return 0.0; Collections.sort(scores); if (n%4==0){ return (scores.get(3*n/4-1)+scores.get(3*n/4))/2.0; } return (scores.get(3*n/4)); } public double min(){ if (n==0) return 0.0; Collections.sort(scores); return (scores.get(0)); } public double max(){ if (n==0) return 0.0; Collections.sort(scores); return (scores.get(n-1)); } public int getN() { // TODO Auto-generated method stub return n; } public String gradeCount(){ if (n==0) return ""; int[] g=new int[5]; for(int i =0; i<n; i++){ int s=scores.get(i); if (s<60) g[0]++; if (s>=60 && s<70) g[1]++; if (s>=70 && s<80) g[2]++; if (s>=80 && s<90) g[3]++; if (s>=90 ) g[4]++; } return g[4]+" A's, "+g[3]+" B's, "+g[2]+" C's, "+g[1]+" D's, "+g[0]+" F's"; } public String outliers(){ String result = "Outliers: "; double iqr=q3()-q1(); double low=q1()-1.5*iqr; double high=q3()+1.5*iqr; for (int i=0; i<n; i++){ int s=scores.get(i); if (s< low || s> high) result+=s+" "; } if (result.length()==10) return "No outliers"; return result; } }