/* * @(#)Chart.java 0.0.2 99/08/06 * * Copyright (c) 1999 by Willie Wheeler. All rights reserved. */ package stats; import java.awt.*; import java.text.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; import lang.*; /** * Abstract base class for displaying probabilities in a graphical form. * * @version 0.0.2 08/06/99 * @author Willie Wheeler */ public abstract class Chart extends JComponent implements TableModelListener { public static final String MODEL_PROPERTY = "model"; public static final String TITLE_PROPERTY = "title"; public static final String COLORS_PROPERTY = "colors"; public static Color[] defaultColors = new Color[] { Color.red, Color.blue, Color.green, Color.yellow, Color.lightGray, Color.cyan, Color.magenta, Color.orange, Color.gray, Color.white, Color.pink, Color.black }; protected static NumberFormat nf = NumberFormat.getNumberInstance(); static { nf.setMinimumFractionDigits(3); nf.setMaximumFractionDigits(3); } protected MVDTableModel model; protected int[] independentIndices; protected int dependentIndex; protected int[] conditioningState; protected String title; protected int[][] states; protected String[] stateNames; protected double[] stateValues; protected Color[] stateColors; /** * Builds a chart to display the unconditional distribution of the * model's zeroth dependent variable over all independent variables. * * @param model the model from which the variables and * distribution are obtained */ public Chart(ContingencyTableModel model) { setModel(model); setStateColors(defaultColors); } /** * Builds a chart to display the unconditional distribution of the model's * zeroth dependent variable over the specified set of independent * variables. For example, to specify independent variables 0 and 2, pass * new int[] { 0, 2 } into the independentIndices * parameter. * * @param model the model from which the variables and * distribution are obtained * @param independentIndices array of independent variable indices */ public Chart(ContingencyTableModel model, int[] independentIndices) { setModel(model, independentIndices); setStateColors(defaultColors); } /** * Builds a chart to display the unconditional distribution of the * specified dependent variable over the specified set of independent * variables. * * @param model the model from which the variables and * distribution are obtained * @param independentIndices array of independent variable indices * @param dependentIndex dependent variable index */ public Chart(ContingencyTableModel model, int[] independentIndices, int dependentIndex) { setModel(model, independentIndices, dependentIndex); setStateColors(defaultColors); } /** * Builds a chart to display a conditional distribution of the specified * dependent variable over the specified set of independent variables. * The conditioning state is specified in the same way that any other * state is specified. * * @param model the model from which the variables and * distribution are obtained * @param independentIndices array of independent variable indices * @param dependentIndex dependent variable index * @param conditioningState conditioning state specification */ public Chart(ContingencyTableModel model, int[] independentIndices, int dependentIndex, int[] conditioningState) { setModel(model, independentIndices, dependentIndex, conditioningState); setStateColors(defaultColors); } public void setModel(ContingencyTableModel model) { int numIndependents = model.getNumIndependents(); int[] independentIndices = new int[numIndependents]; for (int i = 0; i < numIndependents; i++) { independentIndices[i] = i; } setModel(model, independentIndices, 0, null); } public void setModel(ContingencyTableModel model, int[] independentIndices) { setModel(model, independentIndices, 0, null); } public void setModel(ContingencyTableModel model, int[] independentIndices, int dependentIndex) { setModel(model, independentIndices, dependentIndex, null); } public void setModel(ContingencyTableModel model, int[] independentIndices, int dependentIndex, int[] conditioningState) { // Replace the old model with the new. MVDTableModel oldModel = this.model; if (oldModel != null) { oldModel.removeTableModelListener(this); } this.model = model; model.addTableModelListener(this); // Set the variable indices and conditioning state. this.independentIndices = independentIndices; this.dependentIndex = dependentIndex; this.conditioningState = conditioningState; // Set the title. setTitle(getDefaultTitle()); // Set the state information. this.states = model.states(independentIndices); this.stateNames = model.getStatesAsStrings(states); // Set the state values. if (dependentIndex == model.FREQUENCY_OFFSET) { // Very inefficient array copy. int[] freqDist = model.getFrequencyDistribution(states, conditioningState); this.stateValues = new double[freqDist.length]; for (int i = 0; i < freqDist.length; i++) { this.stateValues[i] = (double)freqDist[i]; } } else if (dependentIndex == model.ESTIMATE_OFFSET) { this.stateValues = model.getEstimateDistribution(states, conditioningState); } // Fire a property change event. firePropertyChange(MODEL_PROPERTY, oldModel, this.model); } public MVDTableModel getModel() { return model; } public int getNumIndependents() { return independentIndices.length; } public int[] getIndependentIndices() { return independentIndices; } public int getDependentIndex() { return dependentIndex; } public int[] getCondition() { return conditioningState; } public int getNumStates() { return states.length; } public String getStateName(int stateIndex) { return stateNames[stateIndex]; } public double getStateValue(int stateIndex) { return stateValues[stateIndex]; } public void setStateColors(Color[] stateColors) { Color[] oldStateColors = this.stateColors; this.stateColors = stateColors; firePropertyChange(COLORS_PROPERTY, oldStateColors, this.stateColors); } public Color getStateColor(int stateIndex) { return stateColors[stateIndex % stateColors.length]; } public void setTitle(String title) { String oldTitle = this.title; this.title = title; firePropertyChange(TITLE_PROPERTY, oldTitle, this.title); } public String getTitle() { return title; } public String getDefaultTitle() { String independents = getIndependentsAsString(); String dependent = getDependentAsString(); String condition = getConditionAsString(); StringBuffer buffer = null; // Treat frequencies specially. if (dependent.equals(ContingencyTableModel.FREQUENCY)) { buffer = new StringBuffer("Fr(" + independents); if (condition != "") { buffer.append(" | " + condition); } buffer.append(")"); } // Treat estimates specially. else if (dependent.equals(ContingencyTableModel.ESTIMATE)) { buffer = new StringBuffer("Pr^(" + independents); if (condition != "") { buffer.append(" | " + condition); } buffer.append(")"); } // Otherwise... else { buffer = new StringBuffer(dependent + " vs. " + independents); if (condition != "") { buffer.append(", given " + condition); } } // Return the buffer contents. return buffer.toString(); } // // Accessing the variables, conditions, and states as strings. // public String getIndependentsAsString() { return model.getIndependentsAsString(independentIndices); } public String getDependentAsString() { return model.getDependent(dependentIndex).getName(); } public String getConditionAsString() { return model.getConditionAsString(conditioningState); } public String getStateValueAsString(int stateIndex) { double value = getStateValue(stateIndex); if (model.getDependent(dependentIndex) instanceof IntegralVariable) { return String.valueOf((int)value); } else { return nf.format(value); } } // Handling events. public void tableChanged(TableModelEvent e) { if (model instanceof ContingencyTableModel) { ContingencyTableModel ctm = (ContingencyTableModel)model; if (dependentIndex == ctm.FREQUENCY_OFFSET) { // Very inefficient array copy. int[] freqDist = ctm.getFrequencyDistribution(states, conditioningState); stateValues = new double[freqDist.length]; for (int i = 0; i < freqDist.length; i++) { stateValues[i] = freqDist[i]; } } else if (dependentIndex == ctm.ESTIMATE_OFFSET) { stateValues = ctm.getEstimateDistribution(states, conditioningState); } } repaint(); } }