org.jfree.data.DefaultIntervalCategoryDataset.java Source code

Java tutorial

Introduction

Here is the source code for org.jfree.data.DefaultIntervalCategoryDataset.java

Source

/*
 * ===========================================================
 * JFreeChart : a free chart library for the Java(tm) platform
 * ===========================================================
 * (C) Copyright 2000-2004, by Object Refinery Limited and Contributors.
 * Project Info: http://www.jfree.org/jfreechart/index.html
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation;
 * either version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 * -----------------------------------
 * DefaultIntervalCategoryDataset.java
 * -----------------------------------
 * (C) Copyright 2002-2004, by Jeremy Bowman and Contributors.
 * Original Author: Jeremy Bowman;
 * Contributor(s): David Gilbert (for Object Refinery Limited);
 * $Id: DefaultIntervalCategoryDataset.java,v 1.1 2011-01-31 09:02:17 klukas Exp $
 * Changes
 * -------
 * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
 * 24-Oct-2002 : Amendments for changes made to the dataset interface (DG);
 */

package org.jfree.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;

/**
 * A convenience class that provides a default implementation of the {@link IntervalCategoryDataset} interface.
 * <p>
 * The standard constructor accepts data in a two dimensional array where the first dimension is the series, and the second dimension is the category.
 * 
 * @author Jeremy Bowman
 */
public class DefaultIntervalCategoryDataset extends AbstractSeriesDataset implements IntervalCategoryDataset {

    /** The series keys. */
    private Comparable[] seriesKeys;

    /** The category keys. */
    private Comparable[] categoryKeys;

    /** Storage for the start value data. */
    private Number[][] startData;

    /** Storage for the end value data. */
    private Number[][] endData;

    /**
     * Creates a new dataset.
     * 
     * @param starts
     *           the starting values for the intervals.
     * @param ends
     *           the ending values for the intervals.
     */
    public DefaultIntervalCategoryDataset(final double[][] starts, final double[][] ends) {

        this(DatasetUtilities.createNumberArray2D(starts), DatasetUtilities.createNumberArray2D(ends));

    }

    /**
     * Constructs a dataset and populates it with data from the array.
     * <p>
     * The arrays are indexed as data[series][category]. Series and category names are automatically generated - you can change them using the setSeriesName(...)
     * and setCategory(...) methods.
     * 
     * @param starts
     *           the start values data.
     * @param ends
     *           the end values data.
     */
    public DefaultIntervalCategoryDataset(final Number[][] starts, final Number[][] ends) {

        this(null, null, starts, ends);

    }

    /**
     * Constructs a DefaultIntervalCategoryDataset, populates it with data
     * from the arrays, and uses the supplied names for the series.
     * <p>
     * Category names are generated automatically ("Category 1", "Category 2", etc).
     * 
     * @param seriesNames
     *           the series names.
     * @param starts
     *           the start values data, indexed as data[series][category].
     * @param ends
     *           the end values data, indexed as data[series][category].
     */
    public DefaultIntervalCategoryDataset(final String[] seriesNames, final Number[][] starts,
            final Number[][] ends) {

        this(seriesNames, null, starts, ends);

    }

    /**
     * Constructs a DefaultIntervalCategoryDataset, populates it with data
     * from the arrays, and uses the supplied names for the series and the
     * supplied objects for the categories.
     * 
     * @param seriesKeys
     *           the series keys.
     * @param categoryKeys
     *           the categories.
     * @param starts
     *           the start values data, indexed as data[series][category].
     * @param ends
     *           the end values data, indexed as data[series][category].
     */
    public DefaultIntervalCategoryDataset(final Comparable[] seriesKeys, final Comparable[] categoryKeys,
            final Number[][] starts, final Number[][] ends) {

        this.startData = starts;
        this.endData = ends;

        if (starts != null && ends != null) {

            final String baseName = "org.jfree.data.resources.DataPackageResources";
            final ResourceBundle resources = ResourceBundle.getBundle(baseName);

            final int seriesCount = starts.length;
            if (seriesCount != ends.length) {
                final String errMsg = "DefaultIntervalCategoryDataset: the number "
                        + "of series in the start value dataset does "
                        + "not match the number of series in the end " + "value dataset.";
                throw new IllegalArgumentException(errMsg);
            }
            if (seriesCount > 0) {

                // set up the series names...
                if (seriesKeys != null) {

                    if (seriesKeys.length != seriesCount) {
                        throw new IllegalArgumentException(
                                "DefaultIntervalCategoryDataset: the number of series keys does "
                                        + "not match the number of series in the data.");
                    }

                    this.seriesKeys = seriesKeys;
                } else {
                    final String prefix = resources.getString("series.default-prefix") + " ";
                    this.seriesKeys = generateKeys(seriesCount, prefix);
                }

                // set up the category names...
                final int categoryCount = starts[0].length;
                if (categoryCount != ends[0].length) {
                    final String errMsg = "DefaultIntervalCategoryDataset: the "
                            + "number of categories in the start value " + "dataset does not match the number of "
                            + "categories in the end value dataset.";
                    throw new IllegalArgumentException(errMsg);
                }
                if (categoryKeys != null) {
                    if (categoryKeys.length != categoryCount) {
                        throw new IllegalArgumentException(
                                "DefaultIntervalCategoryDataset: the number of category keys does "
                                        + "not match the number of categories in the data.");
                    }
                    this.categoryKeys = categoryKeys;
                } else {
                    final String prefix = resources.getString("categories.default-prefix") + " ";
                    this.categoryKeys = generateKeys(categoryCount, prefix);
                }

            } else {
                this.seriesKeys = null;
                this.categoryKeys = null;
            }
        }

    }

    /**
     * Returns the number of series in the dataset (possibly zero).
     * 
     * @return The number of series in the dataset.
     */
    public int getSeriesCount() {

        int result = 0;
        if (this.startData != null) {
            result = this.startData.length;
        }
        return result;

    }

    /**
     * Returns the item count.
     * 
     * @return The item count.
     */
    public int getItemCount() {
        return this.categoryKeys.length;
    }

    /**
     * Returns a category key.
     * 
     * @param item
     *           the category index.
     * @return The category key.
     */
    public Comparable getCategory(final int item) {
        return this.categoryKeys[item];
    }

    /**
     * Returns an item.
     * 
     * @param category
     *           the category key.
     * @return The item index.
     */
    public int getItem(final Object category) {
        final List categories = getCategories();
        return categories.indexOf(category);
    }

    /**
     * Returns a series index.
     * 
     * @param series
     *           the series.
     * @return The series index.
     */
    public int getSeriesIndex(final Object series) {
        final List seriesKeys = getSeries();
        return seriesKeys.indexOf(series);
    }

    /**
     * Returns the name of the specified series.
     * 
     * @param series
     *           the index of the required series (zero-based).
     * @return the name of the specified series.
     */
    public Comparable getSeries(final int series) {

        // check argument...
        if ((series >= getSeriesCount()) || (series < 0)) {
            throw new IllegalArgumentException("DefaultCategoryDataset.getSeriesName(int): no such series.");
        }

        // return the value...
        return this.seriesKeys[series];

    }

    /**
     * Returns the name of the specified series.
     * 
     * @param series
     *           The index of the required series (zero-based).
     * @return the name of the specified series.
     */
    public String getSeriesName(final int series) {

        // check argument...
        if ((series >= getSeriesCount()) || (series < 0)) {

            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.getSeriesName(int): no such series.");
        }

        // return the value...
        return this.seriesKeys[series].toString();

    }

    /**
     * Sets the names of the series in the dataset.
     * 
     * @param seriesKeys
     *           the keys of the series in the dataset.
     */
    public void setSeriesKeys(final Comparable[] seriesKeys) {

        // check argument...
        if (seriesKeys == null) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setSeriesKeys(): null not permitted.");
        }

        if (seriesKeys.length != getSeriesCount()) {
            throw new IllegalArgumentException("DefaultIntervalCategoryDataset.setSeriesKeys(): "
                    + "the number of series keys does not match the data.");
        }

        // make the change...
        this.seriesKeys = seriesKeys;
        fireDatasetChanged();

    }

    /**
     * Returns the number of categories in the dataset.
     * <P>
     * This method is part of the CategoryDataset interface.
     * 
     * @return the number of categories in the dataset.
     */
    public int getCategoryCount() {

        int result = 0;

        if (this.startData != null) {
            if (getSeriesCount() > 0) {
                result = this.startData[0].length;
            }
        }

        return result;

    }

    /**
     * Returns a list of the series in the dataset.
     * <P>
     * Supports the CategoryDataset interface.
     * 
     * @return a list of the series in the dataset.
     */
    public List getSeries() {

        // the CategoryDataset interface expects a list of series, but
        // we've stored them in an array...
        if (this.seriesKeys == null) {
            return new java.util.ArrayList();
        } else {
            return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
        }

    }

    /**
     * Returns a list of the categories in the dataset.
     * <P>
     * Supports the CategoryDataset interface.
     * 
     * @return a list of the categories in the dataset.
     */
    public List getCategories() {
        return getColumnKeys();
    }

    /**
     * Returns a list of the categories in the dataset.
     * <P>
     * Supports the CategoryDataset interface.
     * 
     * @return a list of the categories in the dataset.
     */
    public List getColumnKeys() {

        // the CategoryDataset interface expects a list of categories, but
        // we've stored them in an array...
        if (this.categoryKeys == null) {
            return new ArrayList();
        } else {
            return Collections.unmodifiableList(Arrays.asList(this.categoryKeys));
        }

    }

    /**
     * Sets the categories for the dataset.
     * 
     * @param categoryKeys
     *           An array of objects representing the categories in the dataset.
     */
    public void setCategoryKeys(final Comparable[] categoryKeys) {

        // check arguments...
        if (categoryKeys == null) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setCategories(...): null not permitted.");
        }

        if (categoryKeys.length != this.startData[0].length) {
            throw new IllegalArgumentException("DefaultIntervalCategoryDataset.setCategoryKeys(...): "
                    + "the number of categories does not match the data.");
        }

        for (int i = 0; i < categoryKeys.length; i++) {
            if (categoryKeys[i] == null) {
                throw new IllegalArgumentException(
                        "DefaultIntervalCategoryDataset.setCategoryKeys(...): " + "null category not permitted.");
            }
        }

        // make the change...
        this.categoryKeys = categoryKeys;
        fireDatasetChanged();

    }

    /**
     * Returns the data value for one category in a series.
     * <P>
     * This method is part of the CategoryDataset interface. Not particularly meaningful for this class...returns the end value.
     * 
     * @param series
     *           The required series (zero based index).
     * @param category
     *           The required category.
     * @return The data value for one category in a series (null possible).
     */
    public Number getValue(final Comparable series, final Comparable category) {
        final int seriesIndex = getSeriesIndex(series);
        final int itemIndex = getItem(category);
        return getValue(seriesIndex, itemIndex);
    }

    /**
     * Returns the data value for one category in a series.
     * <P>
     * This method is part of the CategoryDataset interface. Not particularly meaningful for this class...returns the end value.
     * 
     * @param series
     *           The required series (zero based index).
     * @param category
     *           The required category.
     * @return The data value for one category in a series (null possible).
     */
    public Number getValue(final int series, final int category) {

        return getEndValue(series, category);

    }

    /**
     * Returns the start data value for one category in a series.
     * <P>
     * This method is part of the IntervalTableDataset interface.
     * 
     * @param series
     *           The required series.
     * @param category
     *           The required category.
     * @return The start data value for one category in a series (null possible).
     */
    public Number getStartValue(final Comparable series, final Comparable category) {
        final int seriesIndex = getSeriesIndex(series);
        final int itemIndex = getItem(category);
        return getStartValue(seriesIndex, itemIndex);
    }

    /**
     * Returns the start data value for one category in a series.
     * <P>
     * This method is part of the IntervalTableDataset interface.
     * 
     * @param series
     *           The required series (zero based index).
     * @param category
     *           The required category.
     * @return The start data value for one category in a series (null possible).
     */
    public Number getStartValue(final int series, final int category) {

        // check arguments...
        if ((series < 0) || (series >= getSeriesCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.getValue(...): " + "series index out of range.");
        }

        if ((category < 0) || (category >= getCategoryCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.getValue(...): " + "category index out of range.");
        }

        // fetch the value...
        return this.startData[series][category];

    }

    /**
     * Returns the end data value for one category in a series.
     * <P>
     * This method is part of the IntervalTableDataset interface.
     * 
     * @param series
     *           the required series.
     * @param category
     *           the required category.
     * @return the end data value for one category in a series (null possible).
     */
    public Number getEndValue(final Comparable series, final Comparable category) {
        final int seriesIndex = getSeriesIndex(series);
        final int itemIndex = getItem(category);
        return getEndValue(seriesIndex, itemIndex);
    }

    /**
     * Returns the end data value for one category in a series.
     * <P>
     * This method is part of the IntervalTableDataset interface.
     * 
     * @param series
     *           the required series (zero based index).
     * @param category
     *           the required category.
     * @return the end data value for one category in a series (null possible).
     */
    public Number getEndValue(final int series, final int category) {

        // check arguments...
        if ((series < 0) || (series >= getSeriesCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.getValue(...): " + "series index out of range.");
        }

        if ((category < 0) || (category >= getCategoryCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.getValue(...): " + "category index out of range.");
        }

        // fetch the value...
        return this.endData[series][category];

    }

    /**
     * Sets the start data value for one category in a series.
     * 
     * @param series
     *           The series (zero-based index).
     * @param category
     *           The category.
     * @param value
     *           The value.
     */
    public void setStartValue(final int series, final Object category, final Number value) {

        // does the series exist?
        if ((series < 0) || (series > getSeriesCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setValue: " + "series outside valid range.");
        }

        // is the category valid?
        final int categoryIndex = getCategoryIndex(category);
        if (categoryIndex < 0) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setValue: " + "unrecognised category.");
        }

        // update the data...
        this.startData[series][categoryIndex] = value;
        fireDatasetChanged();

    }

    /**
     * Sets the end data value for one category in a series.
     * 
     * @param series
     *           the series (zero-based index).
     * @param category
     *           the category.
     * @param value
     *           the value.
     */
    public void setEndValue(final int series, final Object category, final Number value) {

        // does the series exist?
        if ((series < 0) || (series > getSeriesCount())) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setValue: " + "series outside valid range.");
        }

        // is the category valid?
        final int categoryIndex = getCategoryIndex(category);
        if (categoryIndex < 0) {
            throw new IllegalArgumentException(
                    "DefaultIntervalCategoryDataset.setValue: " + "unrecognised category.");
        }

        // update the data...
        this.endData[series][categoryIndex] = value;
        fireDatasetChanged();

    }

    /**
     * Returns the index for the given category.
     * 
     * @param category
     *           the category.
     * @return the index.
     */
    private int getCategoryIndex(final Object category) {

        int result = -1;
        for (int i = 0; i < this.categoryKeys.length; i++) {
            if (category.equals(this.categoryKeys[i])) {
                result = i;
                break;
            }
        }
        return result;

    }

    /**
     * Generates an array of keys, by appending a space plus an integer
     * (starting with 1) to the supplied prefix string.
     * 
     * @param count
     *           the number of keys required.
     * @param prefix
     *           the name prefix.
     * @return an array of <i>prefixN</i> with N = { 1 .. count}.
     */
    private Comparable[] generateKeys(final int count, final String prefix) {

        final Comparable[] result = new Comparable[count];
        String name;
        for (int i = 0; i < count; i++) {
            name = prefix + (i + 1);
            result[i] = name;
        }
        return result;

    }

    /**
     * Returns a column key.
     * 
     * @param item
     *           the column index.
     * @return The column key.
     */
    public Comparable getColumnKey(final int item) {
        return this.categoryKeys[item];
    }

    /**
     * Returns a column index.
     * 
     * @param columnKey
     *           the column key.
     * @return The column index.
     */
    public int getColumnIndex(final Comparable columnKey) {
        final List categories = getCategories();
        return categories.indexOf(columnKey);
    }

    /**
     * Returns a row index.
     * 
     * @param rowKey
     *           the row key.
     * @return The row index.
     */
    public int getRowIndex(final Comparable rowKey) {
        final List seriesKeys = getSeries();
        return seriesKeys.indexOf(rowKey);
    }

    /**
     * Returns a list of the series in the dataset.
     * <P>
     * Supports the CategoryDataset interface.
     * 
     * @return a list of the series in the dataset.
     */
    public List getRowKeys() {

        // the CategoryDataset interface expects a list of series, but
        // we've stored them in an array...
        if (this.seriesKeys == null) {
            return new java.util.ArrayList();
        } else {
            return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
        }

    }

    /**
     * Returns the name of the specified series.
     * 
     * @param series
     *           the index of the required series (zero-based).
     * @return the name of the specified series.
     */
    public Comparable getRowKey(final int series) {

        // check argument...
        if ((series >= getSeriesCount()) || (series < 0)) {
            throw new IllegalArgumentException("DefaultCategoryDataset.getSeriesName(int): no such series.");
        }

        // return the value...
        return this.seriesKeys[series];

    }

    /**
     * Returns the number of categories in the dataset.
     * <P>
     * This method is part of the CategoryDataset interface.
     * 
     * @return the number of categories in the dataset.
     */
    public int getColumnCount() {

        int result = 0;

        if (this.startData != null) {
            if (getSeriesCount() > 0) {
                result = this.startData[0].length;
            }
        }

        return result;

    }

    /**
     * Returns the number of series in the dataset (possibly zero).
     * 
     * @return the number of series in the dataset.
     */
    public int getRowCount() {

        int result = 0;
        if (this.startData != null) {
            result = this.startData.length;
        }
        return result;

    }

}