001    /**
002     * Copyright (c) 2011, SIB. All rights reserved.
003     * 
004     * SIB (Swiss Institute of Bioinformatics) - http://www.isb-sib.ch Host -
005     * https://sourceforge.net/projects/javaprotlib/
006     * 
007     * Redistribution and use in source and binary forms, with or without
008     * modification, are permitted provided that the following conditions are met:
009     * Redistributions of source code must retain the above copyright notice, this
010     * list of conditions and the following disclaimer. Redistributions in binary
011     * form must reproduce the above copyright notice, this list of conditions and
012     * the following disclaimer in the documentation and/or other materials provided
013     * with the distribution. Neither the name of the SIB/GENEBIO nor the names of
014     * its contributors may be used to endorse or promote products derived from this
015     * software without specific prior written permission.
016     * 
017     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020     * ARE DISCLAIMED. IN NO EVENT SHALL SIB/GENEBIO BE LIABLE FOR ANY DIRECT,
021     * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
024     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027     */
028    package org.expasy.jpl.commons.collection.render;
029    
030    
031    import java.awt.Dimension;
032    import java.awt.Paint;
033    import java.awt.image.BufferedImage;
034    import java.io.File;
035    import java.io.IOException;
036    import java.util.ArrayList;
037    import java.util.List;
038    import org.expasy.jpl.commons.base.render.ChartRenderer;
039    import org.expasy.jpl.commons.base.render.ImageFormat;
040    import org.expasy.jpl.commons.collection.Interval;
041    import org.jfree.chart.ChartRenderingInfo;
042    import org.jfree.chart.ChartUtilities;
043    import org.jfree.chart.JFreeChart;
044    import org.jfree.chart.annotations.XYTextAnnotation;
045    import org.jfree.chart.axis.AxisLocation;
046    import org.jfree.chart.axis.NumberAxis;
047    import org.jfree.chart.plot.DatasetRenderingOrder;
048    import org.jfree.chart.plot.XYPlot;
049    import org.jfree.chart.renderer.xy.XYItemRenderer;
050    import org.jfree.data.xy.XYSeries;
051    import org.jfree.data.xy.XYSeriesCollection;
052    import org.jfree.ui.RectangleInsets;
053    
054    
055    public abstract class Abstract2DChartRenderer<T> implements ChartRenderer {
056            
057            public static final ImageFormat DEFAULT_IMAGE_FORMAT = ImageFormat.PNG;
058            public static final Dimension DEFAULT_DIMENSION = new Dimension(600, 400);
059            
060            /** dimension of rendered image */
061            private Dimension dimension;
062            
063            /** image format */
064            
065            private ImageFormat format;
066            
067            private XYPlot plot;
068            protected XYSeriesCollection dataset;
069            
070            /** render the graph */
071            private XYItemRenderer renderer;
072            
073            /** rendering info for interactive graphs **/
074            private ChartRenderingInfo renderingInfo;
075            
076            /** possible categories */
077            private List<XYSeries> categories;
078            
079            private XYSeries nextSeries;
080            
081            /** text annotations */
082            private List<XYTextAnnotation> annots;
083            
084            /** the x-axis interval */
085            protected Interval xAxisInterval;
086            
087            protected Abstract2DChartRenderer(XYItemRenderer renderer) {
088                    this(renderer, DEFAULT_IMAGE_FORMAT, DEFAULT_DIMENSION);
089            }
090            
091            protected Abstract2DChartRenderer(XYItemRenderer renderer,
092                ImageFormat format, Dimension dim) {
093                    this.format = format;
094                    this.dimension = dim;
095                    init(renderer, getXLegend(), getYLegend());
096            }
097            
098            public void addCategory(XYSeries series) {
099                    categories.add(series);
100            }
101            
102            /**
103             * Set plot background color.
104             * 
105             * @param color the background color.
106             */
107            public void setBackgroundColor(Paint color) {
108                    plot.setBackgroundPaint(color);
109            }
110            
111            public void setChartColor(int chartIndex, Paint color) {
112                    renderer.setSeriesPaint(chartIndex, color);
113            }
114            
115            public Paint getChartColor(int chartIndex) {
116                    return renderer.getSeriesPaint(chartIndex);
117            }
118            
119            /**
120             * Set image dimension.
121             * 
122             * @param dim the image dimension.
123             */
124            public void setDimension(Dimension dim) {
125                    this.dimension = dim;
126            }
127            
128            public void setXAxisInterval(double from, double to) {
129                    xAxisInterval = new Interval.Builder(from, to).build();
130            }
131            
132            public void setXAxisDefaultInterval() {
133                    xAxisInterval = null;
134            }
135            
136            /**
137             * Set image format.
138             * 
139             * @param format the image format (png or jpeg).
140             */
141            public void setImageFormat(ImageFormat format) {
142                    this.format = format;
143            }
144            
145            /**
146             * Get image format.
147             * 
148             * @return format the image format (png or jpeg).
149             */
150            public ImageFormat getImageFormat() {
151                    return format;
152            }
153            
154            private void init(XYItemRenderer renderer, String xLegend, String yLegend) {
155                    plot = new XYPlot();
156                    
157                    NumberAxis domainAxis = new NumberAxis(xLegend);
158                    domainAxis.setAutoRangeIncludesZero(false);
159                    
160                    NumberAxis rangeAxis = new NumberAxis(yLegend);
161                    rangeAxis.setAutoRangeIncludesZero(false);
162                    
163                    plot.setDomainAxis(domainAxis);
164                    plot.setRangeAxis(rangeAxis);
165                    plot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
166                    plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
167                    plot.setDatasetRenderingOrder(DatasetRenderingOrder.REVERSE);
168                    
169                    this.renderer = renderer;
170                    plot.setRenderer(renderer);
171                    
172                    renderingInfo = new ChartRenderingInfo();
173                    dataset = initDataset();
174                    
175                    categories = new ArrayList<XYSeries>();
176                    
177                    annots = new ArrayList<XYTextAnnotation>();
178            }
179            
180            public abstract XYSeriesCollection initDataset();
181            
182            public abstract String getXLegend();
183            
184            public abstract String getYLegend();
185            
186            /**
187             * Set the legend for the m/z axis.
188             * 
189             * @param legend the x-axis legend.
190             */
191            public void setXAxisLegend(String legend) {
192                    plot.setDomainAxis(new NumberAxis(legend));
193            }
194            
195            /**
196             * Set the legend for the intensity axis.
197             * 
198             * @param legend the y-axis legend.
199             */
200            public void setYAxisLegend(String legend) {
201                    plot.setRangeAxis(new NumberAxis(legend));
202                    
203            }
204            
205            /**
206             * Empty data set.
207             */
208            public void clearDataSet() {
209                    dataset.removeAllSeries();
210                    plot.clearAnnotations();
211            }
212            
213            /**
214             * Add T-object data set
215             * 
216             * @param data the data set.
217             * @param seriesCanals the map of series.
218             * @param annots the plot annotations.
219             */
220            public abstract void populateData(T data);
221            
222            public void addDataInSeries(int i, double x, double y) {
223                    categories.get(i).add(x, y);
224            }
225            
226            public void addToCurrentDataSeries(double x, double y) {
227                    nextSeries.add(x, y);
228            }
229            
230            public void addAnnotInDefaultSeries(XYTextAnnotation textAnnot) {
231                    annots.add(textAnnot);
232            }
233            
234            public void addDataSet(T data, String seriesName) {
235                    nextSeries = new XYSeries(seriesName);
236                    
237                    populateData(data);
238                    
239                    dataset.addSeries(nextSeries);
240            }
241            
242            public void addMultiDataSet(T data) {
243                    clearDataSet();
244                    populateData(data);
245                    
246                    if (annots.size() > 0) {
247                            for (XYTextAnnotation annot : annots) {
248                                    plot.addAnnotation(annot);
249                            }
250                    }
251                    
252                    for (XYSeries catego : categories) {
253                            dataset.addSeries(catego);
254                    }
255            }
256            
257            /**
258             * @return a new chart that wrap data set.
259             */
260            private JFreeChart flushIntoChart() {
261                    plot.setDataset(dataset);
262                    
263                    if (annots.size() > 0) {
264                            for (XYTextAnnotation annot : annots) {
265                                    plot.addAnnotation(annot);
266                            }
267                    }
268                    annots.clear();
269                    
270                    return new JFreeChart(plot);
271            }
272            
273            /**
274             * Retrieve rendering info (for interactive graphs).
275             * 
276             * @return the rendering information associated to the chart.
277             */
278            public ChartRenderingInfo getRenderingInfo() {
279                    return renderingInfo;
280            }
281            
282            /**
283             * Create an image (prerequisite: data sets have already been entered via
284             * {@code addDataSet} method).
285             * 
286             * @return a new buffered image.
287             */
288            public BufferedImage render() {
289                    JFreeChart chart = flushIntoChart();
290                    return chart.createBufferedImage((int) dimension.getWidth(),
291                        (int) dimension.getHeight(), renderingInfo);
292            }
293            
294            /**
295             * Export a chart (prerequisite: data sets have already been entered via
296             * {@code addDataSet} method).
297             * 
298             * @param filename the image file name without extension (defined in {@code
299             *        ImageFormat}).
300             */
301            public void exportChart(String filename) {
302                    JFreeChart chart = flushIntoChart();
303                    
304                    try {
305                            switch (format) {
306                            case JPG:
307                                    ChartUtilities.saveChartAsJPEG(new File(filename + ".jpg"),
308                                        chart, (int) dimension.getWidth(), (int) dimension
309                                            .getHeight());
310                                    break;
311                            case PNG:
312                                    ChartUtilities.saveChartAsPNG(new File(filename + ".png"),
313                                        chart, (int) dimension.getWidth(), (int) dimension
314                                            .getHeight());
315                            }
316                    } catch (IOException e) {
317                            System.err.println(e.getMessage()
318                                + ": Problem occurred while creating chart.");
319                    }
320            }
321    }