1 56 57 package org.jfree.chart.plot; 58 59 import java.awt.AlphaComposite ; 60 import java.awt.BasicStroke ; 61 import java.awt.Color ; 62 import java.awt.Composite ; 63 import java.awt.Graphics2D ; 64 import java.awt.Paint ; 65 import java.awt.Shape ; 66 import java.awt.Stroke ; 67 import java.awt.geom.Line2D ; 68 import java.awt.geom.Point2D ; 69 import java.awt.geom.Rectangle2D ; 70 import java.io.IOException ; 71 import java.io.ObjectInputStream ; 72 import java.io.ObjectOutputStream ; 73 import java.io.Serializable ; 74 import java.util.Iterator ; 75 import java.util.List ; 76 import java.util.ResourceBundle ; 77 78 import org.jfree.chart.axis.AxisSpace; 79 import org.jfree.chart.axis.AxisState; 80 import org.jfree.chart.axis.ValueAxis; 81 import org.jfree.chart.axis.ValueTick; 82 import org.jfree.chart.event.PlotChangeEvent; 83 import org.jfree.data.Range; 84 import org.jfree.io.SerialUtilities; 85 import org.jfree.ui.RectangleEdge; 86 import org.jfree.ui.RectangleInsets; 87 import org.jfree.util.ArrayUtilities; 88 import org.jfree.util.ObjectUtilities; 89 90 93 public class FastScatterPlot extends Plot implements ValueAxisPlot, 94 Zoomable, 95 Cloneable , Serializable { 96 97 98 private static final long serialVersionUID = 7871545897358563521L; 99 100 101 public static final Stroke DEFAULT_GRIDLINE_STROKE = new BasicStroke (0.5f, 102 BasicStroke.CAP_BUTT, 103 BasicStroke.JOIN_BEVEL, 104 0.0f, 105 new float[] {2.0f, 2.0f}, 106 0.0f); 107 108 109 public static final Paint DEFAULT_GRIDLINE_PAINT = Color.lightGray; 110 111 112 private float[][] data; 113 114 115 private Range xDataRange; 116 117 118 private Range yDataRange; 119 120 121 private ValueAxis domainAxis; 122 123 124 private ValueAxis rangeAxis; 125 126 127 private transient Paint paint; 128 129 130 private boolean domainGridlinesVisible; 131 132 133 private transient Stroke domainGridlineStroke; 134 135 136 private transient Paint domainGridlinePaint; 137 138 139 private boolean rangeGridlinesVisible; 140 141 142 private transient Stroke rangeGridlineStroke; 143 144 145 private transient Paint rangeGridlinePaint; 146 147 148 protected static ResourceBundle localizationResources = 149 ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle"); 150 151 154 public FastScatterPlot() { 155 this(null, null, null); 156 } 157 158 167 public FastScatterPlot(float[][] data, 168 ValueAxis domainAxis, ValueAxis rangeAxis) { 169 170 super(); 171 172 this.data = data; 173 this.xDataRange = calculateXDataRange(data); 174 this.yDataRange = calculateYDataRange(data); 175 this.domainAxis = domainAxis; 176 if (domainAxis != null) { 177 domainAxis.setPlot(this); 178 domainAxis.addChangeListener(this); 179 } 180 181 this.rangeAxis = rangeAxis; 182 if (rangeAxis != null) { 183 rangeAxis.setPlot(this); 184 rangeAxis.addChangeListener(this); 185 } 186 187 this.paint = Color.red; 188 189 this.domainGridlinesVisible = true; 190 this.domainGridlinePaint = FastScatterPlot.DEFAULT_GRIDLINE_PAINT; 191 this.domainGridlineStroke = FastScatterPlot.DEFAULT_GRIDLINE_STROKE; 192 193 this.rangeGridlinesVisible = true; 194 this.rangeGridlinePaint = FastScatterPlot.DEFAULT_GRIDLINE_PAINT; 195 this.rangeGridlineStroke = FastScatterPlot.DEFAULT_GRIDLINE_STROKE; 196 197 } 198 199 204 public String getPlotType() { 205 return localizationResources.getString("Fast_Scatter_Plot"); 206 } 207 208 213 public PlotOrientation getOrientation() { 214 return PlotOrientation.VERTICAL; 215 } 216 217 224 public ValueAxis getDomainAxis() { 225 return this.domainAxis; 226 } 227 228 235 public ValueAxis getRangeAxis() { 236 return this.rangeAxis; 237 } 238 239 244 public Paint getPaint() { 245 return this.paint; 246 } 247 248 254 public void setPaint(Paint paint) { 255 if (paint == null) { 256 throw new IllegalArgumentException ("Null 'paint' argument."); 257 } 258 this.paint = paint; 259 notifyListeners(new PlotChangeEvent(this)); 260 } 261 262 268 public boolean isDomainGridlinesVisible() { 269 return this.domainGridlinesVisible; 270 } 271 272 279 public void setDomainGridlinesVisible(boolean visible) { 280 if (this.domainGridlinesVisible != visible) { 281 this.domainGridlinesVisible = visible; 282 notifyListeners(new PlotChangeEvent(this)); 283 } 284 } 285 286 292 public Stroke getDomainGridlineStroke() { 293 return this.domainGridlineStroke; 294 } 295 296 303 public void setDomainGridlineStroke(Stroke stroke) { 304 this.domainGridlineStroke = stroke; 305 notifyListeners(new PlotChangeEvent(this)); 306 } 307 308 314 public Paint getDomainGridlinePaint() { 315 return this.domainGridlinePaint; 316 } 317 318 325 public void setDomainGridlinePaint(Paint paint) { 326 this.domainGridlinePaint = paint; 327 notifyListeners(new PlotChangeEvent(this)); 328 } 329 330 336 public boolean isRangeGridlinesVisible() { 337 return this.rangeGridlinesVisible; 338 } 339 340 347 public void setRangeGridlinesVisible(boolean visible) { 348 if (this.rangeGridlinesVisible != visible) { 349 this.rangeGridlinesVisible = visible; 350 notifyListeners(new PlotChangeEvent(this)); 351 } 352 } 353 354 360 public Stroke getRangeGridlineStroke() { 361 return this.rangeGridlineStroke; 362 } 363 364 371 public void setRangeGridlineStroke(Stroke stroke) { 372 this.rangeGridlineStroke = stroke; 373 notifyListeners(new PlotChangeEvent(this)); 374 } 375 376 382 public Paint getRangeGridlinePaint() { 383 return this.rangeGridlinePaint; 384 } 385 386 393 public void setRangeGridlinePaint(Paint paint) { 394 this.rangeGridlinePaint = paint; 395 notifyListeners(new PlotChangeEvent(this)); 396 } 397 398 410 public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, 411 PlotState parentState, 412 PlotRenderingInfo info) { 413 414 if (info != null) { 416 info.setPlotArea(area); 417 } 418 419 RectangleInsets insets = getInsets(); 421 insets.trim(area); 422 423 AxisSpace space = new AxisSpace(); 424 space = this.domainAxis.reserveSpace( 425 g2, this, area, RectangleEdge.BOTTOM, space 426 ); 427 space = this.rangeAxis.reserveSpace( 428 g2, this, area, RectangleEdge.LEFT, space 429 ); 430 Rectangle2D dataArea = space.shrink(area, null); 431 432 if (info != null) { 433 info.setDataArea(dataArea); 434 } 435 436 drawBackground(g2, dataArea); 438 439 AxisState domainAxisState = null; 440 AxisState rangeAxisState = null; 441 if (this.domainAxis != null) { 442 domainAxisState = this.domainAxis.draw( 443 g2, dataArea.getMaxY(), area, dataArea, 444 RectangleEdge.BOTTOM, info 445 ); 446 } 447 if (this.rangeAxis != null) { 448 rangeAxisState = this.rangeAxis.draw( 449 g2, dataArea.getMinX(), area, dataArea, 450 RectangleEdge.LEFT, info 451 ); 452 } 453 drawDomainGridlines(g2, dataArea, domainAxisState.getTicks()); 454 drawRangeGridlines(g2, dataArea, rangeAxisState.getTicks()); 455 456 Shape originalClip = g2.getClip(); 457 Composite originalComposite = g2.getComposite(); 458 459 g2.clip(dataArea); 460 g2.setComposite( 461 AlphaComposite.getInstance( 462 AlphaComposite.SRC_OVER, getForegroundAlpha() 463 ) 464 ); 465 466 render(g2, dataArea, info, null); 467 468 g2.setClip(originalClip); 469 g2.setComposite(originalComposite); 470 drawOutline(g2, dataArea); 471 472 } 473 474 485 public void render(Graphics2D g2, Rectangle2D dataArea, 486 PlotRenderingInfo info, CrosshairState crosshairState) { 487 488 489 g2.setPaint(this.paint); 492 493 506 if (this.data != null) { 507 for (int i = 0; i < this.data[0].length; i++) { 508 float x = this.data[0][i]; 509 float y = this.data[1][i]; 510 511 int transX = (int) this.domainAxis.valueToJava2D( 514 x, dataArea, RectangleEdge.BOTTOM 515 ); 516 int transY = (int) this.rangeAxis.valueToJava2D( 517 y, dataArea, RectangleEdge.LEFT 518 ); 519 g2.fillRect(transX, transY, 1, 1); 520 } 521 } 522 526 } 527 528 535 protected void drawDomainGridlines(Graphics2D g2, Rectangle2D dataArea, 536 List ticks) { 537 538 if (isDomainGridlinesVisible()) { 540 Stroke gridStroke = getDomainGridlineStroke(); 541 Paint gridPaint = getDomainGridlinePaint(); 542 if ((gridStroke != null) && (gridPaint != null)) { 543 Iterator iterator = ticks.iterator(); 544 while (iterator.hasNext()) { 545 ValueTick tick = (ValueTick) iterator.next(); 546 double v = this.domainAxis.valueToJava2D( 547 tick.getValue(), dataArea, RectangleEdge.BOTTOM 548 ); 549 Line2D line = new Line2D.Double ( 550 v, dataArea.getMinY(), v, dataArea.getMaxY() 551 ); 552 g2.setPaint(gridPaint); 553 g2.setStroke(gridStroke); 554 g2.draw(line); 555 } 556 } 557 } 558 } 559 560 567 protected void drawRangeGridlines(Graphics2D g2, Rectangle2D dataArea, 568 List ticks) { 569 570 if (isRangeGridlinesVisible()) { 572 Stroke gridStroke = getRangeGridlineStroke(); 573 Paint gridPaint = getRangeGridlinePaint(); 574 if ((gridStroke != null) && (gridPaint != null)) { 575 Iterator iterator = ticks.iterator(); 576 while (iterator.hasNext()) { 577 ValueTick tick = (ValueTick) iterator.next(); 578 double v = this.rangeAxis.valueToJava2D( 579 tick.getValue(), dataArea, RectangleEdge.LEFT 580 ); 581 Line2D line = new Line2D.Double ( 582 dataArea.getMinX(), v, dataArea.getMaxX(), v 583 ); 584 g2.setPaint(gridPaint); 585 g2.setStroke(gridStroke); 586 g2.draw(line); 587 } 588 } 589 } 590 591 } 592 593 600 public Range getDataRange(ValueAxis axis) { 601 602 Range result = null; 603 if (axis == this.domainAxis) { 604 result = this.xDataRange; 605 } 606 else if (axis == this.rangeAxis) { 607 result = this.yDataRange; 608 } 609 return result; 610 } 611 612 619 private Range calculateXDataRange(float[][] data) { 620 621 Range result = null; 622 623 if (data != null) { 624 float lowest = Float.POSITIVE_INFINITY; 625 float highest = Float.NEGATIVE_INFINITY; 626 for (int i = 0; i < data[0].length; i++) { 627 float v = data[0][i]; 628 if (v < lowest) { 629 lowest = v; 630 } 631 if (v > highest) { 632 highest = v; 633 } 634 } 635 if (lowest <= highest) { 636 result = new Range(lowest, highest); 637 } 638 } 639 640 return result; 641 642 } 643 644 651 private Range calculateYDataRange(float[][] data) { 652 653 Range result = null; 654 655 if (data != null) { 656 float lowest = Float.POSITIVE_INFINITY; 657 float highest = Float.NEGATIVE_INFINITY; 658 for (int i = 0; i < data[0].length; i++) { 659 float v = data[1][i]; 660 if (v < lowest) { 661 lowest = v; 662 } 663 if (v > highest) { 664 highest = v; 665 } 666 } 667 if (lowest <= highest) { 668 result = new Range(lowest, highest); 669 } 670 } 671 return result; 672 673 } 674 675 682 public void zoomDomainAxes(double factor, PlotRenderingInfo info, 683 Point2D source) { 684 this.domainAxis.resizeRange(factor); 685 } 686 687 697 public void zoomDomainAxes(double lowerPercent, double upperPercent, 698 PlotRenderingInfo info, Point2D source) { 699 this.domainAxis.zoomRange(lowerPercent, upperPercent); 700 } 701 702 709 public void zoomRangeAxes(double factor, 710 PlotRenderingInfo info, Point2D source) { 711 this.rangeAxis.resizeRange(factor); 712 } 713 714 724 public void zoomRangeAxes(double lowerPercent, double upperPercent, 725 PlotRenderingInfo info, Point2D source) { 726 this.rangeAxis.zoomRange(lowerPercent, upperPercent); 727 } 728 729 734 public boolean isDomainZoomable() { 735 return true; 736 } 737 738 743 public boolean isRangeZoomable() { 744 return true; 745 } 746 747 754 public boolean equals(Object obj) { 755 756 if (obj == this) { 757 return true; 758 } 759 if (!super.equals(obj)) { 760 return false; 761 } 762 if (!(obj instanceof FastScatterPlot)) { 763 return false; 764 } 765 766 FastScatterPlot that = (FastScatterPlot) obj; 767 if (!ArrayUtilities.equal(this.data, that.data)) { 768 return false; 769 } 770 if (!ObjectUtilities.equal(this.domainAxis, that.domainAxis)) { 771 return false; 772 } 773 if (!ObjectUtilities.equal(this.rangeAxis, that.rangeAxis)) { 774 return false; 775 } 776 if (!ObjectUtilities.equal(this.paint, that.paint)) { 777 return false; 778 } 779 780 if (this.domainGridlinesVisible != that.domainGridlinesVisible) { 781 return false; 782 } 783 if (!ObjectUtilities.equal(this.domainGridlinePaint, 784 that.domainGridlinePaint)) { 785 return false; 786 } 787 if (!ObjectUtilities.equal(this.domainGridlineStroke, 788 that.domainGridlineStroke)) { 789 return false; 790 } 791 792 if (!this.rangeGridlinesVisible == that.rangeGridlinesVisible) { 793 return false; 794 } 795 if (!ObjectUtilities.equal(this.rangeGridlinePaint, 796 that.rangeGridlinePaint)) { 797 return false; 798 } 799 if (!ObjectUtilities.equal(this.rangeGridlineStroke, 800 that.rangeGridlineStroke)) { 801 return false; 802 } 803 804 return true; 805 } 806 807 815 public Object clone() throws CloneNotSupportedException { 816 817 FastScatterPlot clone = (FastScatterPlot) super.clone(); 818 819 if (this.data != null) { 820 clone.data = ArrayUtilities.clone(this.data); 821 } 822 823 if (this.domainAxis != null) { 824 clone.domainAxis = (ValueAxis) this.domainAxis.clone(); 825 clone.domainAxis.setPlot(clone); 826 clone.domainAxis.addChangeListener(clone); 827 } 828 829 if (this.rangeAxis != null) { 830 clone.rangeAxis = (ValueAxis) this.rangeAxis.clone(); 831 clone.rangeAxis.setPlot(clone); 832 clone.rangeAxis.addChangeListener(clone); 833 } 834 835 return clone; 836 837 } 838 839 846 private void writeObject(ObjectOutputStream stream) throws IOException { 847 stream.defaultWriteObject(); 848 SerialUtilities.writePaint(this.paint, stream); 849 SerialUtilities.writeStroke(this.domainGridlineStroke, stream); 850 SerialUtilities.writePaint(this.domainGridlinePaint, stream); 851 SerialUtilities.writeStroke(this.rangeGridlineStroke, stream); 852 SerialUtilities.writePaint(this.rangeGridlinePaint, stream); 853 } 854 855 863 private void readObject(ObjectInputStream stream) 864 throws IOException , ClassNotFoundException { 865 stream.defaultReadObject(); 866 867 this.paint = SerialUtilities.readPaint(stream); 868 this.domainGridlineStroke = SerialUtilities.readStroke(stream); 869 this.domainGridlinePaint = SerialUtilities.readPaint(stream); 870 871 this.rangeGridlineStroke = SerialUtilities.readStroke(stream); 872 this.rangeGridlinePaint = SerialUtilities.readPaint(stream); 873 874 if (this.domainAxis != null) { 875 this.domainAxis.addChangeListener(this); 876 } 877 878 if (this.rangeAxis != null) { 879 this.rangeAxis.addChangeListener(this); 880 } 881 } 882 883 } 884 | Popular Tags |