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}