/**
  * Returns the minimum value which is not a farout.
  *
  * @param series the series (zero-based index).
  * @param item the item (zero-based index).
  * @return A <code>Number</code> representing the maximum non-farout value.
  */
 public Number getMinOutlier(int series, int item) {
   Number result = null;
   BoxAndWhiskerItem stats = (BoxAndWhiskerItem) this.items.get(item);
   if (stats != null) {
     result = stats.getMinOutlier();
   }
   return result;
 }
 /**
  * Returns the minimum outlier (non farout) value for an item.
  *
  * @param row the row index (zero-based).
  * @param column the column index (zero-based).
  * @return The minimum outlier.
  * @see #getItem(int, int)
  */
 public Number getMinOutlier(int row, int column) {
   Number result = null;
   BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(row, column);
   if (item != null) {
     result = item.getMinOutlier();
   }
   return result;
 }
 /**
  * Returns the minimum outlier (non farout) value for an item.
  *
  * @param rowKey the row key.
  * @param columnKey the column key.
  * @return The minimum outlier.
  * @see #getItem(int, int)
  */
 public Number getMinOutlier(Comparable rowKey, Comparable columnKey) {
   Number result = null;
   BoxAndWhiskerItem item = (BoxAndWhiskerItem) this.data.getObject(rowKey, columnKey);
   if (item != null) {
     result = item.getMinOutlier();
   }
   return result;
 }
  /**
   * Adds a list of values relating to one Box and Whisker entity to the table. The various median
   * values are calculated.
   *
   * @param item a box and whisker item (<code>null</code> not permitted).
   * @param rowKey the row key (<code>null</code> not permitted).
   * @param columnKey the column key (<code>null</code> not permitted).
   * @see #add(List, Comparable, Comparable)
   */
  public void add(BoxAndWhiskerItem item, Comparable rowKey, Comparable columnKey) {

    this.data.addObject(item, rowKey, columnKey);

    // update cached min and max values
    int r = this.data.getRowIndex(rowKey);
    int c = this.data.getColumnIndex(columnKey);
    if ((this.maximumRangeValueRow == r && this.maximumRangeValueColumn == c)
        || (this.minimumRangeValueRow == r && this.minimumRangeValueColumn == c)) {
      updateBounds();
    } else {

      double minval = Double.NaN;
      if (item.getMinOutlier() != null) {
        minval = item.getMinOutlier().doubleValue();
      }
      double maxval = Double.NaN;
      if (item.getMaxOutlier() != null) {
        maxval = item.getMaxOutlier().doubleValue();
      }

      if (Double.isNaN(this.maximumRangeValue)) {
        this.maximumRangeValue = maxval;
        this.maximumRangeValueRow = r;
        this.maximumRangeValueColumn = c;
      } else if (maxval > this.maximumRangeValue) {
        this.maximumRangeValue = maxval;
        this.maximumRangeValueRow = r;
        this.maximumRangeValueColumn = c;
      }

      if (Double.isNaN(this.minimumRangeValue)) {
        this.minimumRangeValue = minval;
        this.minimumRangeValueRow = r;
        this.minimumRangeValueColumn = c;
      } else if (minval < this.minimumRangeValue) {
        this.minimumRangeValue = minval;
        this.minimumRangeValueRow = r;
        this.minimumRangeValueColumn = c;
      }
    }

    fireDatasetChanged();
  }
 /** Resets the cached bounds, by iterating over the entire dataset to find the current bounds. */
 private void updateBounds() {
   this.minimumRangeValue = Double.NaN;
   this.minimumRangeValueRow = -1;
   this.minimumRangeValueColumn = -1;
   this.maximumRangeValue = Double.NaN;
   this.maximumRangeValueRow = -1;
   this.maximumRangeValueColumn = -1;
   int rowCount = getRowCount();
   int columnCount = getColumnCount();
   for (int r = 0; r < rowCount; r++) {
     for (int c = 0; c < columnCount; c++) {
       BoxAndWhiskerItem item = getItem(r, c);
       if (item != null) {
         Number min = item.getMinOutlier();
         if (min != null) {
           double minv = min.doubleValue();
           if (!Double.isNaN(minv)) {
             if (minv < this.minimumRangeValue || Double.isNaN(this.minimumRangeValue)) {
               this.minimumRangeValue = minv;
               this.minimumRangeValueRow = r;
               this.minimumRangeValueColumn = c;
             }
           }
         }
         Number max = item.getMaxOutlier();
         if (max != null) {
           double maxv = max.doubleValue();
           if (!Double.isNaN(maxv)) {
             if (maxv > this.maximumRangeValue || Double.isNaN(this.maximumRangeValue)) {
               this.maximumRangeValue = maxv;
               this.maximumRangeValueRow = r;
               this.maximumRangeValueColumn = c;
             }
           }
         }
       }
     }
   }
 }