1 50 51 package org.jfree.chart.plot; 52 53 import java.awt.Color ; 54 import java.awt.Font ; 55 import java.awt.Graphics2D ; 56 import java.awt.Paint ; 57 import java.awt.Rectangle ; 58 import java.awt.geom.Point2D ; 59 import java.awt.geom.Rectangle2D ; 60 import java.io.IOException ; 61 import java.io.ObjectInputStream ; 62 import java.io.ObjectOutputStream ; 63 import java.io.Serializable ; 64 import java.util.HashMap ; 65 import java.util.Iterator ; 66 import java.util.List ; 67 import java.util.Map ; 68 69 import org.jfree.chart.ChartRenderingInfo; 70 import org.jfree.chart.JFreeChart; 71 import org.jfree.chart.LegendItem; 72 import org.jfree.chart.LegendItemCollection; 73 import org.jfree.chart.event.PlotChangeEvent; 74 import org.jfree.chart.title.TextTitle; 75 import org.jfree.data.category.CategoryDataset; 76 import org.jfree.data.category.CategoryToPieDataset; 77 import org.jfree.data.general.DatasetChangeEvent; 78 import org.jfree.data.general.DatasetUtilities; 79 import org.jfree.data.general.PieDataset; 80 import org.jfree.io.SerialUtilities; 81 import org.jfree.ui.RectangleEdge; 82 import org.jfree.ui.RectangleInsets; 83 import org.jfree.util.ObjectUtilities; 84 import org.jfree.util.PaintUtilities; 85 import org.jfree.util.TableOrder; 86 87 91 public class MultiplePiePlot extends Plot implements Cloneable , Serializable { 92 93 94 private static final long serialVersionUID = -355377800470807389L; 95 96 97 private JFreeChart pieChart; 98 99 100 private CategoryDataset dataset; 101 102 103 private TableOrder dataExtractOrder; 104 105 106 private double limit = 0.0; 107 108 112 private Comparable aggregatedItemsKey; 113 114 118 private transient Paint aggregatedItemsPaint; 119 120 124 private transient Map sectionPaints; 125 126 129 public MultiplePiePlot() { 130 this(null); 131 } 132 133 138 public MultiplePiePlot(CategoryDataset dataset) { 139 super(); 140 this.dataset = dataset; 141 PiePlot piePlot = new PiePlot(null); 142 this.pieChart = new JFreeChart(piePlot); 143 this.pieChart.removeLegend(); 144 this.dataExtractOrder = TableOrder.BY_COLUMN; 145 this.pieChart.setBackgroundPaint(null); 146 TextTitle seriesTitle = new TextTitle("Series Title", 147 new Font ("SansSerif", Font.BOLD, 12)); 148 seriesTitle.setPosition(RectangleEdge.BOTTOM); 149 this.pieChart.setTitle(seriesTitle); 150 this.aggregatedItemsKey = "Other"; 151 this.aggregatedItemsPaint = Color.lightGray; 152 this.sectionPaints = new HashMap (); 153 } 154 155 160 public CategoryDataset getDataset() { 161 return this.dataset; 162 } 163 164 170 public void setDataset(CategoryDataset dataset) { 171 if (this.dataset != null) { 174 this.dataset.removeChangeListener(this); 175 } 176 177 this.dataset = dataset; 179 if (dataset != null) { 180 setDatasetGroup(dataset.getGroup()); 181 dataset.addChangeListener(this); 182 } 183 184 datasetChanged(new DatasetChangeEvent(this, dataset)); 186 } 187 188 193 public JFreeChart getPieChart() { 194 return this.pieChart; 195 } 196 197 202 public void setPieChart(JFreeChart pieChart) { 203 this.pieChart = pieChart; 204 notifyListeners(new PlotChangeEvent(this)); 205 } 206 207 212 public TableOrder getDataExtractOrder() { 213 return this.dataExtractOrder; 214 } 215 216 222 public void setDataExtractOrder(TableOrder order) { 223 if (order == null) { 224 throw new IllegalArgumentException ("Null 'order' argument"); 225 } 226 this.dataExtractOrder = order; 227 notifyListeners(new PlotChangeEvent(this)); 228 } 229 230 236 public double getLimit() { 237 return this.limit; 238 } 239 240 246 public void setLimit(double limit) { 247 this.limit = limit; 248 notifyListeners(new PlotChangeEvent(this)); 249 } 250 251 259 public Comparable getAggregatedItemsKey() { 260 return this.aggregatedItemsKey; 261 } 262 263 271 public void setAggregatedItemsKey(Comparable key) { 272 if (key == null) { 273 throw new IllegalArgumentException ("Null 'key' argument."); 274 } 275 this.aggregatedItemsKey = key; 276 notifyListeners(new PlotChangeEvent(this)); 277 } 278 279 287 public Paint getAggregatedItemsPaint() { 288 return this.aggregatedItemsPaint; 289 } 290 291 299 public void setAggregatedItemsPaint(Paint paint) { 300 if (paint == null) { 301 throw new IllegalArgumentException ("Null 'paint' argument."); 302 } 303 this.aggregatedItemsPaint = paint; 304 notifyListeners(new PlotChangeEvent(this)); 305 } 306 307 312 public String getPlotType() { 313 return "Multiple Pie Plot"; 314 } 316 317 327 public void draw(Graphics2D g2, 328 Rectangle2D area, 329 Point2D anchor, 330 PlotState parentState, 331 PlotRenderingInfo info) { 332 333 334 RectangleInsets insets = getInsets(); 336 insets.trim(area); 337 drawBackground(g2, area); 338 drawOutline(g2, area); 339 340 if (DatasetUtilities.isEmptyOrNull(this.dataset)) { 342 drawNoDataMessage(g2, area); 343 return; 344 } 345 346 int pieCount = 0; 347 if (this.dataExtractOrder == TableOrder.BY_ROW) { 348 pieCount = this.dataset.getRowCount(); 349 } 350 else { 351 pieCount = this.dataset.getColumnCount(); 352 } 353 354 int displayCols = (int) Math.ceil(Math.sqrt(pieCount)); 356 int displayRows 357 = (int) Math.ceil((double) pieCount / (double) displayCols); 358 359 if (displayCols > displayRows && area.getWidth() < area.getHeight()) { 361 int temp = displayCols; 362 displayCols = displayRows; 363 displayRows = temp; 364 } 365 366 prefetchSectionPaints(); 367 368 int x = (int) area.getX(); 369 int y = (int) area.getY(); 370 int width = ((int) area.getWidth()) / displayCols; 371 int height = ((int) area.getHeight()) / displayRows; 372 int row = 0; 373 int column = 0; 374 int diff = (displayRows * displayCols) - pieCount; 375 int xoffset = 0; 376 Rectangle rect = new Rectangle (); 377 378 for (int pieIndex = 0; pieIndex < pieCount; pieIndex++) { 379 rect.setBounds(x + xoffset + (width * column), y + (height * row), 380 width, height); 381 382 String title = null; 383 if (this.dataExtractOrder == TableOrder.BY_ROW) { 384 title = this.dataset.getRowKey(pieIndex).toString(); 385 } 386 else { 387 title = this.dataset.getColumnKey(pieIndex).toString(); 388 } 389 this.pieChart.setTitle(title); 390 391 PieDataset piedataset = null; 392 PieDataset dd = new CategoryToPieDataset(this.dataset, 393 this.dataExtractOrder, pieIndex); 394 if (this.limit > 0.0) { 395 piedataset = DatasetUtilities.createConsolidatedPieDataset( 396 dd, this.aggregatedItemsKey, this.limit); 397 } 398 else { 399 piedataset = dd; 400 } 401 PiePlot piePlot = (PiePlot) this.pieChart.getPlot(); 402 piePlot.setDataset(piedataset); 403 piePlot.setPieIndex(pieIndex); 404 405 for (int i = 0; i < piedataset.getItemCount(); i++) { 407 Comparable key = piedataset.getKey(i); 408 Paint p; 409 if (key.equals(this.aggregatedItemsKey)) { 410 p = this.aggregatedItemsPaint; 411 } 412 else { 413 p = (Paint ) this.sectionPaints.get(key); 414 } 415 piePlot.setSectionPaint(key, p); 416 } 417 418 ChartRenderingInfo subinfo = null; 419 if (info != null) { 420 subinfo = new ChartRenderingInfo(); 421 } 422 this.pieChart.draw(g2, rect, subinfo); 423 if (info != null) { 424 info.getOwner().getEntityCollection().addAll( 425 subinfo.getEntityCollection()); 426 info.addSubplotInfo(subinfo.getPlotInfo()); 427 } 428 429 ++column; 430 if (column == displayCols) { 431 column = 0; 432 ++row; 433 434 if (row == displayRows - 1 && diff != 0) { 435 xoffset = (diff * width) / 2; 436 } 437 } 438 } 439 440 } 441 442 448 private void prefetchSectionPaints() { 449 450 if (this.dataExtractOrder == TableOrder.BY_ROW) { 454 for (int c = 0; c < this.dataset.getColumnCount(); c++) { 456 Comparable key = this.dataset.getColumnKey(c); 457 Paint p = (Paint ) this.sectionPaints.get(key); 458 if (p == null) { 459 this.sectionPaints.put(key, 460 this.getDrawingSupplier().getNextPaint()); 461 } 462 } 463 } 464 else { 465 for (int r = 0; r < this.dataset.getRowCount(); r++) { 467 Comparable key = this.dataset.getRowKey(r); 468 Paint p = (Paint ) this.sectionPaints.get(key); 469 if (p == null) { 470 this.sectionPaints.put(key, 471 this.getDrawingSupplier().getNextPaint()); 472 } 473 } 474 } 475 476 } 477 478 483 public LegendItemCollection getLegendItems() { 484 485 LegendItemCollection result = new LegendItemCollection(); 486 487 if (this.dataset != null) { 488 List keys = null; 489 490 prefetchSectionPaints(); 491 if (this.dataExtractOrder == TableOrder.BY_ROW) { 492 keys = this.dataset.getColumnKeys(); 493 } 494 else if (this.dataExtractOrder == TableOrder.BY_COLUMN) { 495 keys = this.dataset.getRowKeys(); 496 } 497 498 if (keys != null) { 499 int section = 0; 500 Iterator iterator = keys.iterator(); 501 while (iterator.hasNext()) { 502 Comparable key = (Comparable ) iterator.next(); 503 String label = key.toString(); 504 String description = label; 505 Paint paint = (Paint ) this.sectionPaints.get(key); 506 LegendItem item = new LegendItem(label, description, 507 null, null, Plot.DEFAULT_LEGEND_ITEM_CIRCLE, 508 paint, Plot.DEFAULT_OUTLINE_STROKE, paint); 509 510 result.add(item); 511 section++; 512 } 513 } 514 if (this.limit > 0.0) { 515 result.add(new LegendItem(this.aggregatedItemsKey.toString(), 516 this.aggregatedItemsKey.toString(), null, null, 517 Plot.DEFAULT_LEGEND_ITEM_CIRCLE, 518 this.aggregatedItemsPaint, 519 Plot.DEFAULT_OUTLINE_STROKE, 520 this.aggregatedItemsPaint)); 521 } 522 } 523 return result; 524 } 525 526 535 public boolean equals(Object obj) { 536 if (obj == this) { 537 return true; 538 } 539 if (!(obj instanceof MultiplePiePlot)) { 540 return false; 541 } 542 MultiplePiePlot that = (MultiplePiePlot) obj; 543 if (this.dataExtractOrder != that.dataExtractOrder) { 544 return false; 545 } 546 if (this.limit != that.limit) { 547 return false; 548 } 549 if (!this.aggregatedItemsKey.equals(that.aggregatedItemsKey)) { 550 return false; 551 } 552 if (!PaintUtilities.equal(this.aggregatedItemsPaint, 553 that.aggregatedItemsPaint)) { 554 return false; 555 } 556 if (!ObjectUtilities.equal(this.pieChart, that.pieChart)) { 557 return false; 558 } 559 if (!super.equals(obj)) { 560 return false; 561 } 562 return true; 563 } 564 565 572 private void writeObject(ObjectOutputStream stream) throws IOException { 573 stream.defaultWriteObject(); 574 SerialUtilities.writePaint(this.aggregatedItemsPaint, stream); 575 } 576 577 585 private void readObject(ObjectInputStream stream) 586 throws IOException , ClassNotFoundException { 587 stream.defaultReadObject(); 588 this.aggregatedItemsPaint = SerialUtilities.readPaint(stream); 589 this.sectionPaints = new HashMap (); 590 } 591 592 593 } 594 | Popular Tags |