Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » category » [javadoc | source]
    1   /* ===========================================================
    2    * JFreeChart : a free chart library for the Java(tm) platform
    3    * ===========================================================
    4    *
    5    * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
    6    *
    7    * Project Info:  http://www.jfree.org/jfreechart/index.html
    8    *
    9    * This library is free software; you can redistribute it and/or modify it
   10    * under the terms of the GNU Lesser General Public License as published by
   11    * the Free Software Foundation; either version 2.1 of the License, or
   12    * (at your option) any later version.
   13    *
   14    * This library is distributed in the hope that it will be useful, but
   15    * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   16    * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   17    * License for more details.
   18    *
   19    * You should have received a copy of the GNU Lesser General Public
   20    * License along with this library; if not, write to the Free Software
   21    * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   22    * USA.
   23    *
   24    * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
   25    * in the United States and other countries.]
   26    *
   27    * ---------------------------
   28    * StatisticalBarRenderer.java
   29    * ---------------------------
   30    * (C) Copyright 2002-2008, by Pascal Collet and Contributors.
   31    *
   32    * Original Author:  Pascal Collet;
   33    * Contributor(s):   David Gilbert (for Object Refinery Limited);
   34    *                   Christian W. Zuckschwerdt;
   35    *
   36    * Changes
   37    * -------
   38    * 21-Aug-2002 : Version 1, contributed by Pascal Collet (DG);
   39    * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
   40    * 24-Oct-2002 : Changes to dataset interface (DG);
   41    * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
   42    * 05-Feb-2003 : Updates for new DefaultStatisticalCategoryDataset (DG);
   43    * 25-Mar-2003 : Implemented Serializable (DG);
   44    * 30-Jul-2003 : Modified entity constructor (CZ);
   45    * 06-Oct-2003 : Corrected typo in exception message (DG);
   46    * 05-Nov-2004 : Modified drawItem() signature (DG);
   47    * 15-Jun-2005 : Added errorIndicatorPaint attribute (DG);
   48    * ------------- JFREECHART 1.0.x ---------------------------------------------
   49    * 19-May-2006 : Added support for tooltips and URLs (DG);
   50    * 12-Jul-2006 : Added support for item labels (DG);
   51    * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
   52    * 28-Aug-2007 : Fixed NullPointerException - see bug 1779941 (DG);
   53    * 14-Nov-2007 : Added errorIndicatorStroke, and fixed bugs with drawBarOutline
   54    *               and gradientPaintTransformer attributes being ignored (DG);
   55    *
   56    */
   57   
   58   package org.jfree.chart.renderer.category;
   59   
   60   import java.awt.BasicStroke;
   61   import java.awt.Color;
   62   import java.awt.GradientPaint;
   63   import java.awt.Graphics2D;
   64   import java.awt.Paint;
   65   import java.awt.Stroke;
   66   import java.awt.geom.Line2D;
   67   import java.awt.geom.Rectangle2D;
   68   import java.io.IOException;
   69   import java.io.ObjectInputStream;
   70   import java.io.ObjectOutputStream;
   71   import java.io.Serializable;
   72   
   73   import org.jfree.chart.axis.CategoryAxis;
   74   import org.jfree.chart.axis.ValueAxis;
   75   import org.jfree.chart.entity.EntityCollection;
   76   import org.jfree.chart.event.RendererChangeEvent;
   77   import org.jfree.chart.labels.CategoryItemLabelGenerator;
   78   import org.jfree.chart.plot.CategoryPlot;
   79   import org.jfree.chart.plot.PlotOrientation;
   80   import org.jfree.data.category.CategoryDataset;
   81   import org.jfree.data.statistics.StatisticalCategoryDataset;
   82   import org.jfree.io.SerialUtilities;
   83   import org.jfree.ui.GradientPaintTransformer;
   84   import org.jfree.ui.RectangleEdge;
   85   import org.jfree.util.ObjectUtilities;
   86   import org.jfree.util.PaintUtilities;
   87   import org.jfree.util.PublicCloneable;
   88   
   89   /**
   90    * A renderer that handles the drawing a bar plot where
   91    * each bar has a mean value and a standard deviation line.
   92    */
   93   public class StatisticalBarRenderer extends BarRenderer
   94           implements CategoryItemRenderer, Cloneable, PublicCloneable,
   95                      Serializable {
   96   
   97       /** For serialization. */
   98       private static final long serialVersionUID = -4986038395414039117L;
   99   
  100       /** The paint used to show the error indicator. */
  101       private transient Paint errorIndicatorPaint;
  102   
  103       /**
  104        * The stroke used to draw the error indicators.
  105        *
  106        * @since 1.0.8
  107        */
  108       private transient Stroke errorIndicatorStroke;
  109   
  110       /**
  111        * Default constructor.
  112        */
  113       public StatisticalBarRenderer() {
  114           super();
  115           this.errorIndicatorPaint = Color.gray;
  116           this.errorIndicatorStroke = new BasicStroke(1.0f);
  117       }
  118   
  119       /**
  120        * Returns the paint used for the error indicators.
  121        *
  122        * @return The paint used for the error indicators (possibly
  123        *         <code>null</code>).
  124        *
  125        * @see #setErrorIndicatorPaint(Paint)
  126        */
  127       public Paint getErrorIndicatorPaint() {
  128           return this.errorIndicatorPaint;
  129       }
  130   
  131       /**
  132        * Sets the paint used for the error indicators (if <code>null</code>,
  133        * the item outline paint is used instead) and sends a
  134        * {@link RendererChangeEvent} to all registered listeners.
  135        *
  136        * @param paint  the paint (<code>null</code> permitted).
  137        *
  138        * @see #getErrorIndicatorPaint()
  139        */
  140       public void setErrorIndicatorPaint(Paint paint) {
  141           this.errorIndicatorPaint = paint;
  142           fireChangeEvent();
  143       }
  144   
  145       /**
  146        * Returns the stroke used to draw the error indicators.  If this is
  147        * <code>null</code>, the renderer will use the item outline stroke).
  148        *
  149        * @return The stroke (possibly <code>null</code>).
  150        *
  151        * @see #setErrorIndicatorStroke(Stroke)
  152        *
  153        * @since 1.0.8
  154        */
  155       public Stroke getErrorIndicatorStroke() {
  156           return this.errorIndicatorStroke;
  157       }
  158   
  159       /**
  160        * Sets the stroke used to draw the error indicators, and sends a
  161        * {@link RendererChangeEvent} to all registered listeners.  If you set
  162        * this to <code>null</code>, the renderer will use the item outline
  163        * stroke.
  164        *
  165        * @param stroke  the stroke (<code>null</code> permitted).
  166        *
  167        * @see #getErrorIndicatorStroke()
  168        *
  169        * @since 1.0.8
  170        */
  171       public void setErrorIndicatorStroke(Stroke stroke) {
  172           this.errorIndicatorStroke = stroke;
  173           fireChangeEvent();
  174       }
  175   
  176       /**
  177        * Draws the bar with its standard deviation line range for a single
  178        * (series, category) data item.
  179        *
  180        * @param g2  the graphics device.
  181        * @param state  the renderer state.
  182        * @param dataArea  the data area.
  183        * @param plot  the plot.
  184        * @param domainAxis  the domain axis.
  185        * @param rangeAxis  the range axis.
  186        * @param data  the data.
  187        * @param row  the row index (zero-based).
  188        * @param column  the column index (zero-based).
  189        * @param pass  the pass index.
  190        */
  191       public void drawItem(Graphics2D g2,
  192                            CategoryItemRendererState state,
  193                            Rectangle2D dataArea,
  194                            CategoryPlot plot,
  195                            CategoryAxis domainAxis,
  196                            ValueAxis rangeAxis,
  197                            CategoryDataset data,
  198                            int row,
  199                            int column,
  200                            int pass) {
  201   
  202           // defensive check
  203           if (!(data instanceof StatisticalCategoryDataset)) {
  204               throw new IllegalArgumentException(
  205                   "Requires StatisticalCategoryDataset.");
  206           }
  207           StatisticalCategoryDataset statData = (StatisticalCategoryDataset) data;
  208   
  209           PlotOrientation orientation = plot.getOrientation();
  210           if (orientation == PlotOrientation.HORIZONTAL) {
  211               drawHorizontalItem(g2, state, dataArea, plot, domainAxis,
  212                       rangeAxis, statData, row, column);
  213           }
  214           else if (orientation == PlotOrientation.VERTICAL) {
  215               drawVerticalItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
  216                       statData, row, column);
  217           }
  218       }
  219   
  220       /**
  221        * Draws an item for a plot with a horizontal orientation.
  222        *
  223        * @param g2  the graphics device.
  224        * @param state  the renderer state.
  225        * @param dataArea  the data area.
  226        * @param plot  the plot.
  227        * @param domainAxis  the domain axis.
  228        * @param rangeAxis  the range axis.
  229        * @param dataset  the data.
  230        * @param row  the row index (zero-based).
  231        * @param column  the column index (zero-based).
  232        */
  233       protected void drawHorizontalItem(Graphics2D g2,
  234                                         CategoryItemRendererState state,
  235                                         Rectangle2D dataArea,
  236                                         CategoryPlot plot,
  237                                         CategoryAxis domainAxis,
  238                                         ValueAxis rangeAxis,
  239                                         StatisticalCategoryDataset dataset,
  240                                         int row,
  241                                         int column) {
  242   
  243           RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
  244   
  245           // BAR Y
  246           double rectY = domainAxis.getCategoryStart(column, getColumnCount(),
  247                   dataArea, xAxisLocation);
  248   
  249           int seriesCount = getRowCount();
  250           int categoryCount = getColumnCount();
  251           if (seriesCount > 1) {
  252               double seriesGap = dataArea.getHeight() * getItemMargin()
  253                                  / (categoryCount * (seriesCount - 1));
  254               rectY = rectY + row * (state.getBarWidth() + seriesGap);
  255           }
  256           else {
  257               rectY = rectY + row * state.getBarWidth();
  258           }
  259   
  260           // BAR X
  261           Number meanValue = dataset.getMeanValue(row, column);
  262           if (meanValue == null) {
  263               return;
  264           }
  265           double value = meanValue.doubleValue();
  266           double base = 0.0;
  267           double lclip = getLowerClip();
  268           double uclip = getUpperClip();
  269   
  270           if (uclip <= 0.0) {  // cases 1, 2, 3 and 4
  271               if (value >= uclip) {
  272                   return; // bar is not visible
  273               }
  274               base = uclip;
  275               if (value <= lclip) {
  276                   value = lclip;
  277               }
  278           }
  279           else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
  280               if (value >= uclip) {
  281                   value = uclip;
  282               }
  283               else {
  284                   if (value <= lclip) {
  285                       value = lclip;
  286                   }
  287               }
  288           }
  289           else { // cases 9, 10, 11 and 12
  290               if (value <= lclip) {
  291                   return; // bar is not visible
  292               }
  293               base = getLowerClip();
  294               if (value >= uclip) {
  295                  value = uclip;
  296               }
  297           }
  298   
  299           RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
  300           double transY1 = rangeAxis.valueToJava2D(base, dataArea, yAxisLocation);
  301           double transY2 = rangeAxis.valueToJava2D(value, dataArea,
  302                   yAxisLocation);
  303           double rectX = Math.min(transY2, transY1);
  304   
  305           double rectHeight = state.getBarWidth();
  306           double rectWidth = Math.abs(transY2 - transY1);
  307   
  308           Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
  309                   rectHeight);
  310           Paint itemPaint = getItemPaint(row, column);
  311           GradientPaintTransformer t = getGradientPaintTransformer();
  312           if (t != null && itemPaint instanceof GradientPaint) {
  313               itemPaint = t.transform((GradientPaint) itemPaint, bar);
  314           }
  315           g2.setPaint(itemPaint);
  316           g2.fill(bar);
  317   
  318           // draw the outline...
  319           if (isDrawBarOutline()
  320                   && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
  321               Stroke stroke = getItemOutlineStroke(row, column);
  322               Paint paint = getItemOutlinePaint(row, column);
  323               if (stroke != null && paint != null) {
  324                   g2.setStroke(stroke);
  325                   g2.setPaint(paint);
  326                   g2.draw(bar);
  327               }
  328           }
  329   
  330           // standard deviation lines
  331           Number n = dataset.getStdDevValue(row, column);
  332           if (n != null) {
  333               double valueDelta = n.doubleValue();
  334               double highVal = rangeAxis.valueToJava2D(meanValue.doubleValue()
  335                       + valueDelta, dataArea, yAxisLocation);
  336               double lowVal = rangeAxis.valueToJava2D(meanValue.doubleValue()
  337                       - valueDelta, dataArea, yAxisLocation);
  338   
  339               if (this.errorIndicatorPaint != null) {
  340                   g2.setPaint(this.errorIndicatorPaint);
  341               }
  342               else {
  343                   g2.setPaint(getItemOutlinePaint(row, column));
  344               }
  345               if (this.errorIndicatorStroke != null) {
  346                   g2.setStroke(this.errorIndicatorStroke);
  347               }
  348               else {
  349                   g2.setStroke(getItemOutlineStroke(row, column));
  350               }
  351               Line2D line = null;
  352               line = new Line2D.Double(lowVal, rectY + rectHeight / 2.0d,
  353                                        highVal, rectY + rectHeight / 2.0d);
  354               g2.draw(line);
  355               line = new Line2D.Double(highVal, rectY + rectHeight * 0.25,
  356                                        highVal, rectY + rectHeight * 0.75);
  357               g2.draw(line);
  358               line = new Line2D.Double(lowVal, rectY + rectHeight * 0.25,
  359                                        lowVal, rectY + rectHeight * 0.75);
  360               g2.draw(line);
  361           }
  362   
  363           CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
  364                   column);
  365           if (generator != null && isItemLabelVisible(row, column)) {
  366               drawItemLabel(g2, dataset, row, column, plot, generator, bar,
  367                       (value < 0.0));
  368           }
  369   
  370           // add an item entity, if this information is being collected
  371           EntityCollection entities = state.getEntityCollection();
  372           if (entities != null) {
  373               addItemEntity(entities, dataset, row, column, bar);
  374           }
  375   
  376       }
  377   
  378       /**
  379        * Draws an item for a plot with a vertical orientation.
  380        *
  381        * @param g2  the graphics device.
  382        * @param state  the renderer state.
  383        * @param dataArea  the data area.
  384        * @param plot  the plot.
  385        * @param domainAxis  the domain axis.
  386        * @param rangeAxis  the range axis.
  387        * @param dataset  the data.
  388        * @param row  the row index (zero-based).
  389        * @param column  the column index (zero-based).
  390        */
  391       protected void drawVerticalItem(Graphics2D g2,
  392                                       CategoryItemRendererState state,
  393                                       Rectangle2D dataArea,
  394                                       CategoryPlot plot,
  395                                       CategoryAxis domainAxis,
  396                                       ValueAxis rangeAxis,
  397                                       StatisticalCategoryDataset dataset,
  398                                       int row,
  399                                       int column) {
  400   
  401           RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
  402   
  403           // BAR X
  404           double rectX = domainAxis.getCategoryStart(column, getColumnCount(),
  405                   dataArea, xAxisLocation);
  406   
  407           int seriesCount = getRowCount();
  408           int categoryCount = getColumnCount();
  409           if (seriesCount > 1) {
  410               double seriesGap = dataArea.getWidth() * getItemMargin()
  411                                  / (categoryCount * (seriesCount - 1));
  412               rectX = rectX + row * (state.getBarWidth() + seriesGap);
  413           }
  414           else {
  415               rectX = rectX + row * state.getBarWidth();
  416           }
  417   
  418           // BAR Y
  419           Number meanValue = dataset.getMeanValue(row, column);
  420           if (meanValue == null) {
  421               return;
  422           }
  423   
  424           double value = meanValue.doubleValue();
  425           double base = 0.0;
  426           double lclip = getLowerClip();
  427           double uclip = getUpperClip();
  428   
  429           if (uclip <= 0.0) {  // cases 1, 2, 3 and 4
  430               if (value >= uclip) {
  431                   return; // bar is not visible
  432               }
  433               base = uclip;
  434               if (value <= lclip) {
  435                   value = lclip;
  436               }
  437           }
  438           else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
  439               if (value >= uclip) {
  440                   value = uclip;
  441               }
  442               else {
  443                   if (value <= lclip) {
  444                       value = lclip;
  445                   }
  446               }
  447           }
  448           else { // cases 9, 10, 11 and 12
  449               if (value <= lclip) {
  450                   return; // bar is not visible
  451               }
  452               base = getLowerClip();
  453               if (value >= uclip) {
  454                  value = uclip;
  455               }
  456           }
  457   
  458           RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
  459           double transY1 = rangeAxis.valueToJava2D(base, dataArea, yAxisLocation);
  460           double transY2 = rangeAxis.valueToJava2D(value, dataArea,
  461                   yAxisLocation);
  462           double rectY = Math.min(transY2, transY1);
  463   
  464           double rectWidth = state.getBarWidth();
  465           double rectHeight = Math.abs(transY2 - transY1);
  466   
  467           Rectangle2D bar = new Rectangle2D.Double(rectX, rectY, rectWidth,
  468                   rectHeight);
  469           Paint itemPaint = getItemPaint(row, column);
  470           GradientPaintTransformer t = getGradientPaintTransformer();
  471           if (t != null && itemPaint instanceof GradientPaint) {
  472               itemPaint = t.transform((GradientPaint) itemPaint, bar);
  473           }
  474           g2.setPaint(itemPaint);
  475           g2.fill(bar);
  476           // draw the outline...
  477           if (isDrawBarOutline()
  478                   && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
  479               Stroke stroke = getItemOutlineStroke(row, column);
  480               Paint paint = getItemOutlinePaint(row, column);
  481               if (stroke != null && paint != null) {
  482                   g2.setStroke(stroke);
  483                   g2.setPaint(paint);
  484                   g2.draw(bar);
  485               }
  486           }
  487   
  488           // standard deviation lines
  489           Number n = dataset.getStdDevValue(row, column);
  490           if (n != null) {
  491               double valueDelta = n.doubleValue();
  492               double highVal = rangeAxis.valueToJava2D(meanValue.doubleValue()
  493                       + valueDelta, dataArea, yAxisLocation);
  494               double lowVal = rangeAxis.valueToJava2D(meanValue.doubleValue()
  495                       - valueDelta, dataArea, yAxisLocation);
  496   
  497               if (this.errorIndicatorPaint != null) {
  498                   g2.setPaint(this.errorIndicatorPaint);
  499               }
  500               else {
  501                   g2.setPaint(getItemOutlinePaint(row, column));
  502               }
  503               if (this.errorIndicatorStroke != null) {
  504                   g2.setStroke(this.errorIndicatorStroke);
  505               }
  506               else {
  507                   g2.setStroke(getItemOutlineStroke(row, column));
  508               }
  509   
  510               Line2D line = null;
  511               line = new Line2D.Double(rectX + rectWidth / 2.0d, lowVal,
  512                                        rectX + rectWidth / 2.0d, highVal);
  513               g2.draw(line);
  514               line = new Line2D.Double(rectX + rectWidth / 2.0d - 5.0d, highVal,
  515                                        rectX + rectWidth / 2.0d + 5.0d, highVal);
  516               g2.draw(line);
  517               line = new Line2D.Double(rectX + rectWidth / 2.0d - 5.0d, lowVal,
  518                                        rectX + rectWidth / 2.0d + 5.0d, lowVal);
  519               g2.draw(line);
  520           }
  521   
  522           CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
  523                   column);
  524           if (generator != null && isItemLabelVisible(row, column)) {
  525               drawItemLabel(g2, dataset, row, column, plot, generator, bar,
  526                       (value < 0.0));
  527           }
  528   
  529           // add an item entity, if this information is being collected
  530           EntityCollection entities = state.getEntityCollection();
  531           if (entities != null) {
  532               addItemEntity(entities, dataset, row, column, bar);
  533           }
  534       }
  535   
  536       /**
  537        * Tests this renderer for equality with an arbitrary object.
  538        *
  539        * @param obj  the object (<code>null</code> permitted).
  540        *
  541        * @return A boolean.
  542        */
  543       public boolean equals(Object obj) {
  544           if (obj == this) {
  545               return true;
  546           }
  547           if (!(obj instanceof StatisticalBarRenderer)) {
  548               return false;
  549           }
  550           StatisticalBarRenderer that = (StatisticalBarRenderer) obj;
  551           if (!PaintUtilities.equal(this.errorIndicatorPaint,
  552                   that.errorIndicatorPaint)) {
  553               return false;
  554           }
  555           if (!ObjectUtilities.equal(this.errorIndicatorStroke,
  556                   that.errorIndicatorStroke)) {
  557               return false;
  558           }
  559           return super.equals(obj);
  560       }
  561   
  562       /**
  563        * Provides serialization support.
  564        *
  565        * @param stream  the output stream.
  566        *
  567        * @throws IOException  if there is an I/O error.
  568        */
  569       private void writeObject(ObjectOutputStream stream) throws IOException {
  570           stream.defaultWriteObject();
  571           SerialUtilities.writePaint(this.errorIndicatorPaint, stream);
  572           SerialUtilities.writeStroke(this.errorIndicatorStroke, stream);
  573       }
  574   
  575       /**
  576        * Provides serialization support.
  577        *
  578        * @param stream  the input stream.
  579        *
  580        * @throws IOException  if there is an I/O error.
  581        * @throws ClassNotFoundException  if there is a classpath problem.
  582        */
  583       private void readObject(ObjectInputStream stream)
  584           throws IOException, ClassNotFoundException {
  585           stream.defaultReadObject();
  586           this.errorIndicatorPaint = SerialUtilities.readPaint(stream);
  587           this.errorIndicatorStroke = SerialUtilities.readStroke(stream);
  588       }
  589   
  590   }

Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » category » [javadoc | source]