    001/* ===========================================================
    002 * Orson Charts : a 3D chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C)opyright 2013-2022, by David Gilbert.  All rights reserved.
    006 *
    007 * https://github.com/jfree/orson-charts
    008 *
    009 * This program is free software: you can redistribute it and/or modify
    010 * it under the terms of the GNU General Public License as published by
    011 * the Free Software Foundation, either version 3 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This program is distributed in the hope that it will be useful,
    015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    017 * GNU General Public License for more details.
    018 *
    019 * You should have received a copy of the GNU General Public License
    020 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    021 *
    022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    023 * Other names may be trademarks of their respective owners.]
    024 *
    025 * If you do not wish to be bound by the terms of the GPL, an alternative
    026 * commercial license can be purchased.  For details, please see visit the
    027 * Orson Charts home page:
    028 *
    029 * http://www.object-refinery.com/orsoncharts/index.html
    030 *
    031 */
    032
    033package org.jfree.chart3d;
    034
    035import org.jfree.chart3d.axis.CategoryAxis3D;
    036import org.jfree.chart3d.axis.LabelOrientation;
    037import org.jfree.chart3d.axis.NumberAxis3D;
    038import org.jfree.chart3d.axis.StandardCategoryAxis3D;
    039import org.jfree.chart3d.axis.ValueAxis3D;
    040import org.jfree.chart3d.data.PieDataset3D;
    041import org.jfree.chart3d.data.Range;
    042import org.jfree.chart3d.data.category.CategoryDataset3D;
    043import org.jfree.chart3d.data.function.Function3D;
    044import org.jfree.chart3d.data.xyz.XYZDataset;
    045import org.jfree.chart3d.data.xyz.XYZSeriesCollection;
    046import org.jfree.chart3d.internal.Args;
    047import org.jfree.chart3d.legend.ColorScaleLegendBuilder;
    048import org.jfree.chart3d.plot.CategoryPlot3D;
    049import org.jfree.chart3d.plot.PiePlot3D;
    050import org.jfree.chart3d.plot.XYZPlot;
    051import org.jfree.chart3d.renderer.category.AreaRenderer3D;
    052import org.jfree.chart3d.renderer.category.BarRenderer3D;
    053import org.jfree.chart3d.renderer.category.CategoryRenderer3D;
    054import org.jfree.chart3d.renderer.category.LineRenderer3D;
    055import org.jfree.chart3d.renderer.category.StackedBarRenderer3D;
    056import org.jfree.chart3d.renderer.xyz.BarXYZRenderer;
    057import org.jfree.chart3d.renderer.xyz.LineXYZRenderer;
    058import org.jfree.chart3d.renderer.xyz.ScatterXYZRenderer;
    059import org.jfree.chart3d.renderer.xyz.SurfaceRenderer;
    060import org.jfree.chart3d.renderer.xyz.XYZRenderer;
    061import org.jfree.chart3d.style.ChartStyle;
    062import org.jfree.chart3d.style.StandardChartStyle;
    063
    064/**
    065 * Utility methods for constructing common chart types.  Charts can be
    066 * assembled piece-wise, but usually it is simpler to use the methods in this
    067 * class then customise the resulting chart as necessary.
    068 */
    069public class Chart3DFactory {
    070
    071    /**
    072     * Private constructor prevents instantiation which is unnecessary.
    073     */
    074    private Chart3DFactory() {
    075        // no need to instantiate this ever
    076    }
    077
    078    /** The chart style that will be used when creating a new chart. */
    079    static ChartStyle defaultStyle = new StandardChartStyle();
    080
    081    /**
    082     * Returns a new instance of the default chart style (so that, by default,
    083     * all charts will have an independent style instance).
    084     *
    085     * @return The default chart style (never {@code null}).
    086     *
    087     * @since 1.2
    088     */
    089    public static ChartStyle getDefaultChartStyle() {
    090        return defaultStyle.clone();
    091    }
    092
    093    /**
    094     * Sets the style that will be used when creating new charts.
    095     *
    096     * @param style  the style ({@code null} not permitted).
    097     *
    098     * @since 1.2
    099     */
    100    public static void setDefaultChartStyle(ChartStyle style) {
    101        Args.nullNotPermitted(style, "style");
    102        defaultStyle = style.clone();
    103    }
    104
    105    /**
    106     * Creates and returns a pie chart based on the supplied dataset.  The
    107     * chart returned by this method will be constructed using a
    108     * {@link PiePlot3D} instance (so it is safe to cast the result of
    109     * {@code chart.getPlot()}).
    110     * <br><br>
    111     * For reference, here is a sample pie chart:
    112     * <div>
    113     * <img src="../../../../doc-files/PieChart3DDemo1.svg"
    114     * alt="PieChart3DDemo1.svg" width="500" height="359">
    115     * </div>
    116     *
    117     * @param title  the chart title ({@code null} permitted).
    118     * @param subtitle  the chart subtitle ({@code null} permitted).
    119     * @param dataset  the dataset ({@code null} not permitted).
    120     *
    121     * @return A pie chart (never {@code null}).
    122     */
    123    public static Chart3D createPieChart(String title, String subtitle,
    124            PieDataset3D<? extends Comparable> dataset) {
    125        PiePlot3D plot = new PiePlot3D(dataset);
    126        return new Chart3D(title, subtitle, plot);
    127    }
    128
    129    /**
    130     * Creates and returns a bar chart based on the supplied dataset. The chart
    131     * returned by this method will be constructed with a
    132     * {@link CategoryPlot3D} using a {@link BarRenderer3D} (so it is
    133     * safe to cast the plot and/or renderer to customise attributes that are
    134     * specific to those subclasses).
    135     * <br><br>
    136     * For reference, here is a sample bar chart:
    137     * <div>
    138     * <img src="../../../../doc-files/BarChart3DDemo1.svg"
    139     * alt="BarChart3DDemo1.svg" width="500" height="359">
    140     * </div>
    141     *
    142     * @param title  the chart title ({@code null} permitted).
    143     * @param subtitle  the chart subtitle ({@code null} permitted).
    144     * @param dataset  the dataset ({@code null} not permitted).
    145     * @param rowAxisLabel  the row axis label ({@code null} permitted).
    146     * @param columnAxisLabel  the column axis label ({@code null}
    147     *     permitted).
    148     * @param valueAxisLabel  the value axis label ({@code null} permitted).
    149     *
    150     * @return A bar chart (never {@code null}).
    151     */
    152    public static Chart3D createBarChart(String title, String subtitle,
    153            CategoryDataset3D dataset, String rowAxisLabel,
    154            String columnAxisLabel, String valueAxisLabel) {
    155        StandardCategoryAxis3D rowAxis
    156                = new StandardCategoryAxis3D(rowAxisLabel);
    157        rowAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    158        CategoryAxis3D columnAxis = new StandardCategoryAxis3D(columnAxisLabel);
    159        NumberAxis3D valueAxis = new NumberAxis3D(valueAxisLabel,
    160                new Range(0.0, 1.0));
    161        valueAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    162        CategoryRenderer3D renderer = new BarRenderer3D();
    163        CategoryPlot3D plot = new CategoryPlot3D(dataset, renderer,
    164                rowAxis, columnAxis, valueAxis);
    165        return new Chart3D(title, subtitle, plot);
    166    }
    167
    168    /**
    169     * Creates and returns a stacked bar chart based on the supplied dataset.
    170     * The chart returned by this method will be constructed with a
    171     * {@link CategoryPlot3D} using a {@link StackedBarRenderer3D} (so it is
    172     * safe to cast the plot and/or renderer to customise attributes that
    173     * are specific to those subclasses).
    174     * <br><br>
    175     * For reference, here is a sample stacked bar chart:
    176     * <div>
    177     * <img src="../../../../doc-files/StackedBarChart3DDemo1.svg"
    178     * alt="StackedBarChart3DDemo1.svg" width="500" height="359">
    179     * </div>
    180     *
    181     * @param title  the chart title ({@code null} permitted).
    182     * @param subtitle  the chart subtitle ({@code null} permitted).
    183     * @param dataset  the dataset ({@code null} not permitted).
    184     * @param rowAxisLabel  the row axis label ({@code null} permitted).
    185     * @param columnAxisLabel  the column axis label ({@code null} permitted).
    186     * @param valueAxisLabel  the value axis label ({@code null} permitted).
    187     *
    188     * @return A stacked bar chart (never {@code null}).
    189     */
    190    public static Chart3D createStackedBarChart(String title, String subtitle,
    191            CategoryDataset3D dataset, String rowAxisLabel,
    192            String columnAxisLabel, String valueAxisLabel) {
    193        StandardCategoryAxis3D rowAxis
    194                = new StandardCategoryAxis3D(rowAxisLabel);
    195        rowAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    196        CategoryAxis3D columnAxis = new StandardCategoryAxis3D(columnAxisLabel);
    197        NumberAxis3D valueAxis = new NumberAxis3D(valueAxisLabel,
    198                new Range(0.0, 1.0));
    199        valueAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    200        CategoryRenderer3D renderer = new StackedBarRenderer3D();
    201        CategoryPlot3D plot = new CategoryPlot3D(dataset, renderer, rowAxis,
    202                columnAxis, valueAxis);
    203        return new Chart3D(title, subtitle, plot);
    204    }
    205
    206    /**
    207     * Creates and returns an area chart based on the supplied dataset.  The
    208     * chart returned by this method will be constructed with a
    209     * {@link CategoryPlot3D} using an {@link AreaRenderer3D} (so it is safe
    210     * to cast the plot and/or renderer to customise attributes that are
    211     * specific to those subclasses).
    212     * <br><br>
    213     * For reference, here is a sample area chart:
    214     * <div>
    215     * <img src="../../../../doc-files/AreaChart3DDemo1.svg"
    216     * alt="AreaChart3DDemo1.svg" width="500" height="359">
    217     * </div>
    218     *
    219     * @param title  the chart title ({@code null} permitted).
    220     * @param subtitle  the chart subtitle ({@code null} permitted).
    221     * @param dataset  the dataset ({@code null} not permitted).
    222     * @param rowAxisLabel  the row axis label ({@code null} permitted).
    223     * @param columnAxisLabel  the column axis label ({@code null} permitted).
    224     * @param valueAxisLabel  the value axis label ({@code null} permitted).
    225     *
    226     * @return An area chart (never {@code null}).
    227     */
    228    public static Chart3D createAreaChart(String title, String subtitle,
    229            CategoryDataset3D dataset, String rowAxisLabel,
    230            String columnAxisLabel, String valueAxisLabel) {
    231        StandardCategoryAxis3D rowAxis
    232                = new StandardCategoryAxis3D(rowAxisLabel);
    233        rowAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    234        StandardCategoryAxis3D columnAxis = new StandardCategoryAxis3D(
    235                columnAxisLabel);
    236        columnAxis.setFirstCategoryHalfWidth(true);
    237        columnAxis.setLastCategoryHalfWidth(true);
    238        NumberAxis3D valueAxis = new NumberAxis3D(valueAxisLabel,
    239                new Range(0.0, 1.0));
    240        valueAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    241        CategoryRenderer3D renderer = new AreaRenderer3D();
    242        CategoryPlot3D plot = new CategoryPlot3D(dataset, renderer, rowAxis,
    243                columnAxis, valueAxis);
    244        return new Chart3D(title, subtitle, plot);
    245    }
    246
    247    /**
    248     * Creates and returns a line chart based on the supplied dataset.  The
    249     * chart returned by this method will be constructed with a
    250     * {@link CategoryPlot3D} using a {@link LineRenderer3D} (so it is safe
    251     * to cast the plot and/or renderer to customise attributes that are
    252     * specific to those subclasses).
    253     * <br><br>
    254     * For reference, here is a sample line chart:
    255     * <div>
    256     * <img src="../../../../doc-files/LineChart3DDemo1.svg"
    257     * alt="LineChart3DDemo1.svg" width="500" height="359">
    258     * </div>
    259     *
    260     * @param title  the chart title ({@code null} permitted).
    261     * @param subtitle  the chart subtitle ({@code null} permitted).
    262     * @param dataset  the dataset ({@code null} not permitted).
    263     * @param rowAxisLabel  the row axis label ({@code null} permitted).
    264     * @param columnAxisLabel  the column axis label ({@code null} permitted).
    265     * @param valueAxisLabel  the value axis label ({@code null} permitted).
    266     *
    267     * @return A line chart (never {@code null}).
    268     */
    269    public static Chart3D createLineChart(String title, String subtitle,
    270            CategoryDataset3D dataset, String rowAxisLabel,
    271            String columnAxisLabel, String valueAxisLabel) {
    272        StandardCategoryAxis3D rowAxis
    273                = new StandardCategoryAxis3D(rowAxisLabel);
    274        rowAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    275        StandardCategoryAxis3D columnAxis
    276                = new StandardCategoryAxis3D(columnAxisLabel);
    277        columnAxis.setFirstCategoryHalfWidth(true);
    278        columnAxis.setLastCategoryHalfWidth(true);
    279        NumberAxis3D valueAxis = new NumberAxis3D(valueAxisLabel,
    280                new Range(0.0, 1.0));
    281        valueAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    282        CategoryRenderer3D renderer = new LineRenderer3D();
    283        CategoryPlot3D plot = new CategoryPlot3D(dataset, renderer, rowAxis,
    284                columnAxis, valueAxis);
    285        return new Chart3D(title, subtitle, plot);
    286    }
    287
    288    /**
    289     * Creates and returns a scatter plot based on the supplied dataset
    290     * (containing one or more series of {@code (x, y, z)} values).  The
    291     * chart returned by this method will be constructed with an
    292     * {@link XYZPlot} using a {@link ScatterXYZRenderer}  (so it is safe
    293     * to cast the plot and/or renderer to customise attributes that are
    294     * specific to those subclasses).
    295     * <br><br>
    296     * For reference, here is a sample scatter chart:
    297     * <div>
    298     * <img src="../../../../doc-files/ScatterPlot3DDemo1.svg"
    299     * alt="ScatterPlot3DDemo1.svg" width="564" height="351">
    300     * </div>
    301     *
    302     * @param title  the chart title ({@code null} permitted).
    303     * @param subtitle  the chart subtitle ({@code null} permitted).
    304     * @param dataset  the dataset ({@code null} not permitted).
    305     * @param xAxisLabel  the x-axis label ({@code null} permitted).
    306     * @param yAxisLabel  the y-axis label ({@code null} permitted).
    307     * @param zAxisLabel  the z-axis label ({@code null} permitted).
    308     *
    309     * @return The chart.
    310     */
    311    public static Chart3D createScatterChart(String title, String subtitle,
    312            XYZDataset dataset, String xAxisLabel, String yAxisLabel,
    313            String zAxisLabel) {
    314        NumberAxis3D xAxis = new NumberAxis3D(xAxisLabel);
    315        NumberAxis3D yAxis = new NumberAxis3D(yAxisLabel);
    316        yAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    317        NumberAxis3D zAxis = new NumberAxis3D(zAxisLabel);
    318        XYZRenderer renderer = new ScatterXYZRenderer();
    319        XYZPlot plot = new XYZPlot(dataset, renderer, xAxis, yAxis, zAxis);
    320        return new Chart3D(title, subtitle, plot);
    321    }
    322
    323    /**
    324     * Creates a surface chart for the specified function.
    325     * <br><br>
    326     * For reference, here is a sample surface chart:
    327     * <div>
    328     * <img src="../../../../doc-files/SurfaceRendererDemo2.svg"
    329     * alt="SurfaceRendererDemo2.svg" width="562" height="408">
    330     * </div>
    331     *
    332     * @param title  the chart title ({@code null} permitted).
    333     * @param subtitle  the chart subtitle ({@code null} permitted).
    334     * @param function  the function ({@code null} not permitted).
    335     * @param xAxisLabel  the x-axis label ({@code null} permitted).
    336     * @param yAxisLabel  the y-axis label ({@code null} permitted).
    337     * @param zAxisLabel  the z-axis label ({@code null} permitted).
    338     *
    339     * @return The chart.
    340     *
    341     * @since 1.1
    342     */
    343    public static Chart3D createSurfaceChart(String title, String subtitle,
    344            Function3D function, String xAxisLabel, String yAxisLabel,
    345            String zAxisLabel) {
    346        NumberAxis3D xAxis = new NumberAxis3D(xAxisLabel);
    347        NumberAxis3D yAxis = new NumberAxis3D(yAxisLabel);
    348        yAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    349        NumberAxis3D zAxis = new NumberAxis3D(zAxisLabel);
    350        XYZRenderer renderer = new SurfaceRenderer(function);
    351        // we pass an empty dataset because the plot must have a non-null
    352        // dataset, but the renderer never looks at it...
    353        XYZPlot plot = new XYZPlot(new XYZSeriesCollection(), renderer, xAxis,
    354                yAxis, zAxis);
    355
    356        Chart3D chart = new Chart3D(title, subtitle, plot);
    357        chart.setLegendBuilder(new ColorScaleLegendBuilder());
    358        return chart;
    359    }
    360
    361    /**
    362     * Creates and returns a bar chart based on the supplied dataset (this is
    363     * for special cases, most general cases will be covered by the
    364     * {@link #createBarChart(String, String, CategoryDataset3D, String, String, String) }
    365     * method). The chart returned by this method will be constructed with an
    366     * {@link XYZPlot} using a {@link BarXYZRenderer}  (so it is safe
    367     * to cast the plot and/or renderer to customise attributes that are
    368     * specific to those subclasses).
    369     * <br><br>
    370     * For reference, here is a sample XYZ bar chart:
    371     * <div>
    372     * <img src="../../../../doc-files/XYZBarChart3DDemo1.svg"
    373     * alt="XYZBarChart3DDemo1.svg" width="500" height="359">
    374     * </div>
    375     *
    376     * @param title  the chart title ({@code null} permitted).
    377     * @param subtitle  the chart subtitle ({@code null} permitted).
    378     * @param dataset  the dataset ({@code null} not permitted).
    379     * @param xAxisLabel  the x-axis label ({@code null} permitted).
    380     * @param yAxisLabel  the y-axis label ({@code null} permitted).
    381     * @param zAxisLabel  the z-axis label ({@code null} permitted).
    382     *
    383     * @return The chart.
    384     */
    385    public static Chart3D createXYZBarChart(String title, String subtitle,
    386            XYZDataset dataset, String xAxisLabel, String yAxisLabel,
    387            String zAxisLabel) {
    388        ValueAxis3D xAxis = new NumberAxis3D(xAxisLabel);
    389        NumberAxis3D yAxis = new NumberAxis3D(yAxisLabel);
    390        yAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    391        ValueAxis3D zAxis = new NumberAxis3D(zAxisLabel);
    392        XYZRenderer renderer = new BarXYZRenderer();
    393        XYZPlot plot = new XYZPlot(dataset, renderer, xAxis, yAxis, zAxis);
    394        return new Chart3D(title, subtitle, plot);
    395    }
    396
    397    /**
    398     * Creates and returns a line chart based on the supplied dataset. The
    399     * chart returned by this method will be constructed with an
    400     * {@link XYZPlot} using a {@link LineXYZRenderer}  (so it is safe
    401     * to cast the plot and/or renderer to customise attributes that are
    402     * specific to those subclasses).
    403     *
    404     * @param title  the chart title ({@code null} permitted).
    405     * @param subtitle  the chart subtitle ({@code null} permitted).
    406     * @param dataset  the dataset ({@code null} not permitted).
    407     * @param xAxisLabel  the x-axis label ({@code null} permitted).
    408     * @param yAxisLabel  the y-axis label ({@code null} permitted).
    409     * @param zAxisLabel  the z-axis label ({@code null} permitted).
    410     *
    411     * @return The chart.
    412     *
    413     * @since 1.5
    414     */
    415    public static Chart3D createXYZLineChart(String title, String subtitle,
    416            XYZDataset dataset, String xAxisLabel, String yAxisLabel,
    417            String zAxisLabel) {
    418        ValueAxis3D xAxis = new NumberAxis3D(xAxisLabel);
    419        NumberAxis3D yAxis = new NumberAxis3D(yAxisLabel);
    420        yAxis.setTickLabelOrientation(LabelOrientation.PERPENDICULAR);
    421        ValueAxis3D zAxis = new NumberAxis3D(zAxisLabel);
    422        XYZRenderer renderer = new LineXYZRenderer();
    423        XYZPlot plot = new XYZPlot(dataset, renderer, xAxis, yAxis, zAxis);
    424        return new Chart3D(title, subtitle, plot);
    425    }
    426}