Source for org.jfree.chart.plot.CombinedRangeXYPlot

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, 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:  * CombinedRangeXYPlot.java
  29:  * ------------------------
  30:  * (C) Copyright 2001-2005, by Bill Kelemen and Contributors.
  31:  *
  32:  * Original Author:  Bill Kelemen;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *                   Anthony Boulestreau;
  35:  *                   David Basten;
  36:  *                   Kevin Frechette (for ISTI);
  37:  *                   Arnaud Lelievre;
  38:  *                   Nicolas Brodu;
  39:  *
  40:  * $Id: CombinedRangeXYPlot.java,v 1.10.2.1 2005/10/25 20:52:08 mungady Exp $
  41:  *
  42:  * Changes:
  43:  * --------
  44:  * 06-Dec-2001 : Version 1 (BK);
  45:  * 12-Dec-2001 : Removed unnecessary 'throws' clause from constructor (DG);
  46:  * 18-Dec-2001 : Added plotArea attribute and get/set methods (BK);
  47:  * 22-Dec-2001 : Fixed bug in chartChanged with multiple combinations of 
  48:  *               CombinedPlots (BK);
  49:  * 08-Jan-2002 : Moved to new package com.jrefinery.chart.combination (DG);
  50:  * 25-Feb-2002 : Updated import statements (DG);
  51:  * 28-Feb-2002 : Readded "this.plotArea = plotArea" that was deleted from 
  52:  *               draw() method (BK);
  53:  * 26-Mar-2002 : Added an empty zoom method (this method needs to be written 
  54:  *               so that combined plots will support zooming (DG);
  55:  * 29-Mar-2002 : Changed the method createCombinedAxis adding the creation of 
  56:  *               OverlaidSymbolicAxis and CombinedSymbolicAxis(AB);
  57:  * 23-Apr-2002 : Renamed CombinedPlot-->MultiXYPlot, and simplified the 
  58:  *               structure (DG);
  59:  * 23-May-2002 : Renamed (again) MultiXYPlot-->CombinedXYPlot (DG);
  60:  * 19-Jun-2002 : Added get/setGap() methods suggested by David Basten (DG);
  61:  * 25-Jun-2002 : Removed redundant imports (DG);
  62:  * 16-Jul-2002 : Draws shared axis after subplots (to fix missing gridlines),
  63:  *               added overrides of 'setSeriesPaint()' and 'setXYItemRenderer()'
  64:  *               that pass changes down to subplots (KF);
  65:  * 09-Oct-2002 : Added add(XYPlot) method (DG);
  66:  * 26-Mar-2003 : Implemented Serializable (DG);
  67:  * 16-May-2003 : Renamed CombinedXYPlot --> CombinedRangeXYPlot (DG);
  68:  * 26-Jun-2003 : Fixed bug 755547 (DG);
  69:  * 16-Jul-2003 : Removed getSubPlots() method (duplicate of getSubplots()) (DG);
  70:  * 08-Aug-2003 : Adjusted totalWeight in remove() method (DG);
  71:  * 21-Aug-2003 : Implemented Cloneable (DG);
  72:  * 08-Sep-2003 : Added internationalization via use of properties 
  73:  *               resourceBundle (RFE 690236) (AL); 
  74:  * 11-Sep-2003 : Fix cloning support (subplots) (NB);
  75:  * 15-Sep-2003 : Fixed error in cloning (DG);
  76:  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
  77:  * 17-Sep-2003 : Updated handling of 'clicks' (DG);
  78:  * 12-Nov-2004 : Implements the new Zoomable interface (DG);
  79:  * 25-Nov-2004 : Small update to clone() implementation (DG);
  80:  * 21-Feb-2005 : The getLegendItems() method now returns the fixed legend
  81:  *               items if set (DG);
  82:  * 05-May-2005 : Removed unused draw() method (DG);
  83:  *
  84:  */
  85: 
  86: package org.jfree.chart.plot;
  87: 
  88: import java.awt.Graphics2D;
  89: import java.awt.geom.Point2D;
  90: import java.awt.geom.Rectangle2D;
  91: import java.io.Serializable;
  92: import java.util.Collections;
  93: import java.util.Iterator;
  94: import java.util.List;
  95: 
  96: import org.jfree.chart.LegendItemCollection;
  97: import org.jfree.chart.axis.AxisSpace;
  98: import org.jfree.chart.axis.AxisState;
  99: import org.jfree.chart.axis.NumberAxis;
 100: import org.jfree.chart.axis.ValueAxis;
 101: import org.jfree.chart.event.PlotChangeEvent;
 102: import org.jfree.chart.event.PlotChangeListener;
 103: import org.jfree.chart.renderer.xy.XYItemRenderer;
 104: import org.jfree.data.Range;
 105: import org.jfree.ui.RectangleEdge;
 106: import org.jfree.ui.RectangleInsets;
 107: import org.jfree.util.ObjectUtilities;
 108: import org.jfree.util.PublicCloneable;
 109: 
 110: /**
 111:  * An extension of {@link XYPlot} that contains multiple subplots that share a 
 112:  * common range axis.
 113:  */
 114: public class CombinedRangeXYPlot extends XYPlot 
 115:                                  implements Zoomable,
 116:                                             Cloneable, PublicCloneable, 
 117:                                             Serializable,
 118:                                             PlotChangeListener {
 119: 
 120:     /** For serialization. */
 121:     private static final long serialVersionUID = -5177814085082031168L;
 122:     
 123:     /** Storage for the subplot references. */
 124:     private List subplots;
 125: 
 126:     /** Total weight of all charts. */
 127:     private int totalWeight = 0;
 128: 
 129:     /** The gap between subplots. */
 130:     private double gap = 5.0;
 131: 
 132:     /** Temporary storage for the subplot areas. */
 133:     private transient Rectangle2D[] subplotAreas;
 134: 
 135:     /**
 136:      * Default constructor.
 137:      */
 138:     public CombinedRangeXYPlot() {
 139:         this(new NumberAxis());
 140:     }
 141:     
 142:     /**
 143:      * Creates a new plot.
 144:      *
 145:      * @param rangeAxis  the shared axis.
 146:      */
 147:     public CombinedRangeXYPlot(ValueAxis rangeAxis) {
 148: 
 149:         super(null, // no data in the parent plot
 150:               null,
 151:               rangeAxis,
 152:               null);
 153: 
 154:         this.subplots = new java.util.ArrayList();
 155: 
 156:     }
 157: 
 158:     /**
 159:      * Returns a string describing the type of plot.
 160:      *
 161:      * @return The type of plot.
 162:      */
 163:     public String getPlotType() {
 164:         return localizationResources.getString("Combined_Range_XYPlot");
 165:     }
 166: 
 167:     /**
 168:      * Returns the space between subplots.
 169:      *
 170:      * @return The gap
 171:      */
 172:     public double getGap() {
 173:         return this.gap;
 174:     }
 175: 
 176:     /**
 177:      * Sets the amount of space between subplots.
 178:      *
 179:      * @param gap  the gap between subplots
 180:      */
 181:     public void setGap(double gap) {
 182:         this.gap = gap;
 183:     }
 184: 
 185:     /**
 186:      * Adds a subplot, with a default 'weight' of 1.
 187:      *
 188:      * @param subplot  the subplot.
 189:      */
 190:     public void add(XYPlot subplot) {
 191:         add(subplot, 1);
 192:     }
 193: 
 194:     /**
 195:      * Adds a subplot with a particular weight (greater than or equal to one).  
 196:      * The weight determines how much space is allocated to the subplot 
 197:      * relative to all the other subplots.
 198:      *
 199:      * @param subplot  the subplot.
 200:      * @param weight  the weight (must be 1 or greater).
 201:      */
 202:     public void add(XYPlot subplot, int weight) {
 203: 
 204:         // verify valid weight
 205:         if (weight <= 0) {
 206:             String msg = "The 'weight' must be positive.";
 207:             throw new IllegalArgumentException(msg);
 208:         }
 209: 
 210:         // store the plot and its weight
 211:         subplot.setParent(this);
 212:         subplot.setWeight(weight);
 213:         subplot.setInsets(new RectangleInsets(0.0, 0.0, 0.0, 0.0));
 214:         subplot.setRangeAxis(null);
 215:         subplot.addChangeListener(this);
 216:         this.subplots.add(subplot);
 217: 
 218:         // keep track of total weights
 219:         this.totalWeight += weight;
 220:         configureRangeAxes();
 221:         notifyListeners(new PlotChangeEvent(this));
 222: 
 223:     }
 224: 
 225:     /**
 226:      * Removes a subplot from the combined chart.
 227:      *
 228:      * @param subplot  the subplot (<code>null</code> not permitted).
 229:      */
 230:     public void remove(XYPlot subplot) {
 231:         if (subplot == null) {
 232:             throw new IllegalArgumentException(" Null 'subplot' argument.");   
 233:         }
 234:         int position = -1;
 235:         int size = this.subplots.size();
 236:         int i = 0;
 237:         while (position == -1 && i < size) {
 238:             if (this.subplots.get(i) == subplot) {
 239:                 position = i;
 240:             }
 241:             i++;
 242:         }
 243:         if (position != -1) {
 244:             subplot.setParent(null);
 245:             subplot.removeChangeListener(this);
 246:             this.totalWeight -= subplot.getWeight();
 247:             configureRangeAxes();
 248:             notifyListeners(new PlotChangeEvent(this));
 249:         }
 250:     }
 251: 
 252:     /**
 253:      * Returns a list of the subplots.
 254:      *
 255:      * @return The list (unmodifiable).
 256:      */
 257:     public List getSubplots() {
 258:         return Collections.unmodifiableList(this.subplots);
 259:     }
 260: 
 261:     /**
 262:      * Calculates the space required for the axes.
 263:      * 
 264:      * @param g2  the graphics device.
 265:      * @param plotArea  the plot area.
 266:      * 
 267:      * @return The space required for the axes.
 268:      */
 269:     protected AxisSpace calculateAxisSpace(Graphics2D g2, 
 270:                                            Rectangle2D plotArea) {
 271:         
 272:         AxisSpace space = new AxisSpace();
 273:         PlotOrientation orientation = getOrientation();
 274:         
 275:         // work out the space required by the domain axis...
 276:         AxisSpace fixed = getFixedRangeAxisSpace();
 277:         if (fixed != null) {
 278:             if (orientation == PlotOrientation.VERTICAL) {
 279:                 space.setLeft(fixed.getLeft());
 280:                 space.setRight(fixed.getRight());
 281:             }
 282:             else if (orientation == PlotOrientation.HORIZONTAL) {
 283:                 space.setTop(fixed.getTop());
 284:                 space.setBottom(fixed.getBottom());                
 285:             }
 286:         }
 287:         else {
 288:             ValueAxis valueAxis = getRangeAxis();
 289:             RectangleEdge valueEdge = Plot.resolveRangeAxisLocation(
 290:                 getRangeAxisLocation(), orientation
 291:             );
 292:             if (valueAxis != null) {
 293:                 space = valueAxis.reserveSpace(
 294:                     g2, this, plotArea, valueEdge, space
 295:                 );
 296:             }
 297:         }
 298:         
 299:         Rectangle2D adjustedPlotArea = space.shrink(plotArea, null);
 300:         // work out the maximum height or width of the non-shared axes...
 301:         int n = this.subplots.size();
 302: 
 303:         // calculate plotAreas of all sub-plots, maximum vertical/horizontal 
 304:         // axis width/height
 305:         this.subplotAreas = new Rectangle2D[n];
 306:         double x = adjustedPlotArea.getX();
 307:         double y = adjustedPlotArea.getY();
 308:         double usableSize = 0.0;
 309:         if (orientation == PlotOrientation.VERTICAL) {
 310:             usableSize = adjustedPlotArea.getWidth() - this.gap * (n - 1);
 311:         }
 312:         else if (orientation == PlotOrientation.HORIZONTAL) {
 313:             usableSize = adjustedPlotArea.getHeight() - this.gap * (n - 1);
 314:         }
 315: 
 316:         for (int i = 0; i < n; i++) {
 317:             XYPlot plot = (XYPlot) this.subplots.get(i);
 318: 
 319:             // calculate sub-plot area
 320:             if (orientation == PlotOrientation.VERTICAL) {
 321:                 double w = usableSize * plot.getWeight() / this.totalWeight;
 322:                 this.subplotAreas[i] = new Rectangle2D.Double(
 323:                     x, y, w, adjustedPlotArea.getHeight()
 324:                 );
 325:                 x = x + w + this.gap;
 326:             }
 327:             else if (orientation == PlotOrientation.HORIZONTAL) {
 328:                 double h = usableSize * plot.getWeight() / this.totalWeight;
 329:                 this.subplotAreas[i] = new Rectangle2D.Double(
 330:                     x, y, adjustedPlotArea.getWidth(), h
 331:                 );
 332:                 y = y + h + this.gap;
 333:             }
 334: 
 335:             AxisSpace subSpace = plot.calculateDomainAxisSpace(
 336:                 g2, this.subplotAreas[i], null
 337:             );
 338:             space.ensureAtLeast(subSpace);
 339: 
 340:         }
 341: 
 342:         return space;
 343:     }
 344:     
 345:     /**
 346:      * Draws the plot within the specified area on a graphics device.
 347:      * 
 348:      * @param g2  the graphics device.
 349:      * @param area  the plot area (in Java2D space).
 350:      * @param anchor  an anchor point in Java2D space (<code>null</code> 
 351:      *                permitted).
 352:      * @param parentState  the state from the parent plot, if there is one 
 353:      *                     (<code>null</code> permitted).
 354:      * @param info  collects chart drawing information (<code>null</code> 
 355:      *              permitted).
 356:      */
 357:     public void draw(Graphics2D g2,
 358:                      Rectangle2D area,
 359:                      Point2D anchor,
 360:                      PlotState parentState,
 361:                      PlotRenderingInfo info) {
 362:         
 363:         // set up info collection...
 364:         if (info != null) {
 365:             info.setPlotArea(area);
 366:         }
 367: 
 368:         // adjust the drawing area for plot insets (if any)...
 369:         RectangleInsets insets = getInsets();
 370:         insets.trim(area);
 371: 
 372:         AxisSpace space = calculateAxisSpace(g2, area);
 373:         Rectangle2D dataArea = space.shrink(area, null);
 374:         //this.axisOffset.trim(dataArea);
 375: 
 376:         // set the width and height of non-shared axis of all sub-plots
 377:         setFixedDomainAxisSpaceForSubplots(space);
 378: 
 379:         // draw the shared axis
 380:         ValueAxis axis = getRangeAxis();
 381:         RectangleEdge edge = getRangeAxisEdge();
 382:         double cursor = RectangleEdge.coordinate(dataArea, edge);
 383:         AxisState axisState = axis.draw(g2, cursor, area, dataArea, edge, info);
 384: 
 385:         if (parentState == null) {
 386:             parentState = new PlotState();
 387:         }
 388:         parentState.getSharedAxisStates().put(axis, axisState);
 389:         
 390:         // draw all the charts
 391:         for (int i = 0; i < this.subplots.size(); i++) {
 392:             XYPlot plot = (XYPlot) this.subplots.get(i);
 393:             PlotRenderingInfo subplotInfo = null;
 394:             if (info != null) {
 395:                 subplotInfo = new PlotRenderingInfo(info.getOwner());
 396:                 info.addSubplotInfo(subplotInfo);
 397:             }
 398:             plot.draw(
 399:                 g2, this.subplotAreas[i], anchor, parentState, subplotInfo
 400:             );
 401:         }
 402: 
 403:         if (info != null) {
 404:             info.setDataArea(dataArea);
 405:         }
 406: 
 407:     }
 408: 
 409:     /**
 410:      * Returns a collection of legend items for the plot.
 411:      *
 412:      * @return The legend items.
 413:      */
 414:     public LegendItemCollection getLegendItems() {
 415:         LegendItemCollection result = getFixedLegendItems();
 416:         if (result == null) {
 417:             result = new LegendItemCollection();
 418:         
 419:             if (this.subplots != null) {
 420:                 Iterator iterator = this.subplots.iterator();
 421:                 while (iterator.hasNext()) {
 422:                     XYPlot plot = (XYPlot) iterator.next();
 423:                     LegendItemCollection more = plot.getLegendItems();
 424:                     result.addAll(more);
 425:                 }
 426:             }
 427:         }
 428:         return result;
 429:     }
 430: 
 431:     /**
 432:      * Multiplies the range on the domain axis/axes by the specified factor.
 433:      *
 434:      * @param factor  the zoom factor.
 435:      * @param info  the plot rendering info.
 436:      * @param source  the source point.
 437:      */
 438:     public void zoomDomainAxes(double factor, PlotRenderingInfo info, 
 439:                                Point2D source) {
 440:         XYPlot subplot = findSubplot(info, source);
 441:         if (subplot != null) {
 442:             subplot.zoomDomainAxes(factor, info, source);
 443:         }
 444:     }
 445: 
 446:     /**
 447:      * Zooms in on the domain axes.
 448:      *
 449:      * @param lowerPercent  the lower bound.
 450:      * @param upperPercent  the upper bound.
 451:      * @param info  the plot rendering info.
 452:      * @param source  the source point.
 453:      */
 454:     public void zoomDomainAxes(double lowerPercent, double upperPercent, 
 455:                                PlotRenderingInfo info, Point2D source) {
 456:         XYPlot subplot = findSubplot(info, source);
 457:         if (subplot != null) {
 458:             subplot.zoomDomainAxes(lowerPercent, upperPercent, info, source);
 459:         }
 460:     }
 461: 
 462:     /**
 463:      * Returns the subplot (if any) that contains the (x, y) point (specified 
 464:      * in Java2D space).
 465:      * 
 466:      * @param info  the chart rendering info.
 467:      * @param source  the source point.
 468:      * 
 469:      * @return A subplot (possibly <code>null</code>).
 470:      */
 471:     public XYPlot findSubplot(PlotRenderingInfo info, Point2D source) {
 472:         XYPlot result = null;
 473:         int subplotIndex = info.getSubplotIndex(source);
 474:         if (subplotIndex >= 0) {
 475:             result =  (XYPlot) this.subplots.get(subplotIndex);
 476:         }
 477:         return result;
 478:     }
 479: 
 480:     /**
 481:      * Sets the item renderer FOR ALL SUBPLOTS.  Registered listeners are 
 482:      * notified that the plot has been modified.
 483:      * <P>
 484:      * Note: usually you will want to set the renderer independently for each 
 485:      * subplot, which is NOT what this method does.
 486:      *
 487:      * @param renderer the new renderer.
 488:      */
 489:     public void setRenderer(XYItemRenderer renderer) {
 490: 
 491:         super.setRenderer(renderer);  // not strictly necessary, since the 
 492:                                       // renderer set for the
 493:                                       // parent plot is not used
 494: 
 495:         Iterator iterator = this.subplots.iterator();
 496:         while (iterator.hasNext()) {
 497:             XYPlot plot = (XYPlot) iterator.next();
 498:             plot.setRenderer(renderer);
 499:         }
 500: 
 501:     }
 502: 
 503:     /**
 504:      * Sets the orientation for the plot (and all its subplots).
 505:      * 
 506:      * @param orientation  the orientation.
 507:      */
 508:     public void setOrientation(PlotOrientation orientation) {
 509: 
 510:         super.setOrientation(orientation);
 511: 
 512:         Iterator iterator = this.subplots.iterator();
 513:         while (iterator.hasNext()) {
 514:             XYPlot plot = (XYPlot) iterator.next();
 515:             plot.setOrientation(orientation);
 516:         }
 517: 
 518:     }
 519: 
 520:     /**
 521:      * Returns the range for the axis.  This is the combined range of all the 
 522:      * subplots.
 523:      *
 524:      * @param axis  the axis.
 525:      *
 526:      * @return The range.
 527:      */
 528:     public Range getDataRange(ValueAxis axis) {
 529: 
 530:         Range result = null;
 531:         if (this.subplots != null) {
 532:             Iterator iterator = this.subplots.iterator();
 533:             while (iterator.hasNext()) {
 534:                 XYPlot subplot = (XYPlot) iterator.next();
 535:                 result = Range.combine(result, subplot.getDataRange(axis));
 536:             }
 537:         }
 538:         return result;
 539: 
 540:     }
 541: 
 542:     /**
 543:      * Sets the space (width or height, depending on the orientation of the 
 544:      * plot) for the domain axis of each subplot.
 545:      *
 546:      * @param space  the space.
 547:      */
 548:     protected void setFixedDomainAxisSpaceForSubplots(AxisSpace space) {
 549: 
 550:         Iterator iterator = this.subplots.iterator();
 551:         while (iterator.hasNext()) {
 552:             XYPlot plot = (XYPlot) iterator.next();
 553:             plot.setFixedDomainAxisSpace(space);
 554:         }
 555: 
 556:     }
 557: 
 558:     /**
 559:      * Handles a 'click' on the plot by updating the anchor values...
 560:      *
 561:      * @param x  x-coordinate, where the click occured.
 562:      * @param y  y-coordinate, where the click occured.
 563:      * @param info  object containing information about the plot dimensions.
 564:      */
 565:     public void handleClick(int x, int y, PlotRenderingInfo info) {
 566: 
 567:         Rectangle2D dataArea = info.getDataArea();
 568:         if (dataArea.contains(x, y)) {
 569:             for (int i = 0; i < this.subplots.size(); i++) {
 570:                 XYPlot subplot = (XYPlot) this.subplots.get(i);
 571:                 PlotRenderingInfo subplotInfo = info.getSubplotInfo(i);
 572:                 subplot.handleClick(x, y, subplotInfo);
 573:             }
 574:         }
 575: 
 576:     }
 577: 
 578:     /**
 579:      * Receives a {@link PlotChangeEvent} and responds by notifying all 
 580:      * listeners.
 581:      * 
 582:      * @param event  the event.
 583:      */
 584:     public void plotChanged(PlotChangeEvent event) {
 585:         notifyListeners(event);
 586:     }
 587: 
 588:     /**
 589:      * Tests this plot for equality with another object.
 590:      *
 591:      * @param obj  the other object.
 592:      *
 593:      * @return <code>true</code> or <code>false</code>.
 594:      */
 595:     public boolean equals(Object obj) {
 596: 
 597:         if (obj == this) {
 598:             return true;
 599:         }
 600: 
 601:         if (!(obj instanceof CombinedRangeXYPlot)) {
 602:             return false;
 603:         }
 604:         if (!super.equals(obj)) {
 605:             return false;
 606:         }
 607:         CombinedRangeXYPlot that = (CombinedRangeXYPlot) obj;
 608:         if (!ObjectUtilities.equal(this.subplots, that.subplots)) {
 609:             return false;
 610:         }
 611:         if (this.totalWeight != that.totalWeight) {
 612:             return false;
 613:         }
 614:         if (this.gap != that.gap) {
 615:             return false;
 616:         }
 617:         return true;
 618:     }
 619:     
 620:     /**
 621:      * Returns a clone of the plot.
 622:      * 
 623:      * @return A clone.
 624:      * 
 625:      * @throws CloneNotSupportedException  this class will not throw this 
 626:      *         exception, but subclasses (if any) might.
 627:      */
 628:     public Object clone() throws CloneNotSupportedException {
 629:         
 630:         CombinedRangeXYPlot result = (CombinedRangeXYPlot) super.clone(); 
 631:         result.subplots = (List) ObjectUtilities.deepClone(this.subplots);
 632:         for (Iterator it = result.subplots.iterator(); it.hasNext();) {
 633:             Plot child = (Plot) it.next();
 634:             child.setParent(result);
 635:         }
 636:         
 637:         // after setting up all the subplots, the shared range axis may need 
 638:         // reconfiguring
 639:         ValueAxis rangeAxis = result.getRangeAxis();
 640:         if (rangeAxis != null) {
 641:             rangeAxis.configure();
 642:         }
 643:         
 644:         return result;
 645:     }
 646: 
 647: }