/* * @(#)NumericGrouper.java 0.0.0 99/07/05 * * Copyright (c) 1999 by Willie Wheeler. All rights reserved. */ package stats; import java.text.*; import java.util.*; import javax.swing.event.*; /** * ... *

* The lower bound of a group is inclusive, and the upper bound is * exclusive. In particular, the lower bound of the first group is * inclusive, and the upper bound of the last group is exclusive. * * @version 0.0.0 07/05/99 * @author Willie Wheeler */ public class NumericGrouper implements TableModelListener { public static final int GROUP_COLUMN = 0; protected static NumberFormat nf; static { nf = NumberFormat.getNumberInstance(); nf.setMinimumFractionDigits(3); nf.setMaximumFractionDigits(3); } protected DataTableModel dataIn, dataOut; protected int columnIndex; protected double[] bounds; protected String[] groups; public NumericGrouper(DataTableModel dataIn, int columnIndex, double lowerBd, double upperBd, int numGroups) { setBounds(lowerBd, upperBd, numGroups); setDataIn(dataIn, columnIndex); } public NumericGrouper(DataTableModel dataIn, int columnIndex, double[] bounds) { setBounds(bounds); setDataIn(dataIn, columnIndex); } public void setBounds(double lowerBd, double upperBd, int numGroups) { // Build bounds array from passed params. double range = upperBd - lowerBd; double[] bounds = new double[numGroups + 1]; for (int i = 0; i < numGroups + 1; i++) { double ratio = (double)i / (double)numGroups; bounds[i] = lowerBd + (ratio * range); } setBounds(bounds); } public void setBounds(double[] bounds) { this.bounds = bounds; // Build groups array from bounds array. groups = new String[bounds.length - 1]; for (int i = 0; i < bounds.length - 1; i++) { groups[i] = "[" + nf.format(bounds[i]) + ", " + nf.format(bounds[i+1]) + ")"; } } public double[] getBounds() { return bounds; } public String[] getGroups() { return groups; } /** * This method presupposes that the bounds have already been set. */ public void setDataIn(DataTableModel dataIn, int columnIndex) { if (this.dataIn != null) { this.dataIn.removeTableModelListener(this); } this.dataIn = dataIn; this.dataIn.addTableModelListener(this); this.columnIndex = columnIndex; initDataOut(); } protected void initDataOut() { Variable var = dataIn.getVariable(columnIndex); // This probably shouldn't be a nominal variable, but right now it's // the only thing that will work. Variable varClone = new TextVariable(var.getName(), groups); dataOut = new DataTableModel(new Variable[] { varClone }, 0); group(); } public DataTableModel getDataOut() { return dataOut; } public void group() { Vector tableData = dataOut.getDataVector(); tableData.clear(); for (int i = 0; i < dataIn.getRowCount(); i++) { // Convert current datum to a double. double dblVal = 0.0; Object val = dataIn.getValueAt(i, columnIndex); if (val instanceof Double) { dblVal = ((Double)val).doubleValue(); } else if (val instanceof Integer) { dblVal = ((Integer)val).intValue(); } else if (val instanceof String) { throw new ClassCastException("Can't yet parse type String."); } // Compute group index; -1 = ungrouped. int grpIndex = -1; for (int j = 0; j < bounds.length; j++) { if (dblVal < bounds[j]) { grpIndex = j - 1; break; } } Vector rowData = new Vector(1); rowData.add(grpIndex == -1 ? (Object)"ungrouped" : (Object)(new Integer(grpIndex))); tableData.add(rowData); } dataOut.fireTableDataChanged(); } public void tableChanged(TableModelEvent e) { group(); } }