001/* 002 * $Source: $ 003 * $Name: $ 004 * $Revision: $ 005 * $Date: $ 006 * $Locker: $ 007 */ 008/* 009 * CategorizedStackedBarChart -- A class to create a categorized stacked bar chart. 010 * 011 * Written by Tom Gutwin - WebARTS Design. 012 * Copyright (C) 2007-2010 WebARTS Design, North Vancouver Canada 013 * http://www..webarts.bc.ca 014 * 015 * This program is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU General Public License as published by 017 * the Free Software Foundation; either version 2 of the License, or 018 * (at your option) any later version. 019 * 020 * This program is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU General Public License for more details. 024 * 025 * You should have received a copy of the GNU General Public License 026 * along with this program; if not, write to the Free Software 027 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 028 */ 029package ca.bc.webarts.tools; 030 031import java.awt.*; 032import java.awt.Color; 033import java.awt.Dimension; 034import java.awt.Font; 035import java.awt.GradientPaint; 036import java.awt.geom.Rectangle2D; 037import java.io.File; 038import java.io.FileReader; 039import java.io.FileNotFoundException; 040import java.io.FileOutputStream; 041import java.io.IOException; 042import java.io.OutputStream; 043import java.io.BufferedOutputStream; 044import java.io.OutputStreamWriter; 045import java.awt.Rectangle; 046import java.util.Vector; 047import java.io.Writer; 048 049import javax.swing.JPanel; 050 051import org.jfree.chart.ChartFactory; 052import org.jfree.chart.ChartUtilities; 053import org.jfree.chart.ChartPanel; 054import org.jfree.chart.JFreeChart; 055import org.jfree.chart.LegendItem; 056import org.jfree.chart.LegendItemCollection; 057import org.jfree.chart.axis.SubCategoryAxis; 058import org.jfree.chart.plot.CategoryPlot; 059import org.jfree.chart.plot.Plot; 060import org.jfree.chart.plot.PlotOrientation; 061import org.jfree.chart.plot.CategoryMarker; 062import org.jfree.chart.plot.IntervalMarker; 063import org.jfree.chart.labels.*; 064import org.jfree.chart.renderer.category.GroupedStackedBarRenderer; 065//import org.jfree.data.io.CSV; 066import org.jfree.data.KeyToGroupMap; 067import org.jfree.data.category.CategoryDataset; 068import org.jfree.data.category.DefaultCategoryDataset; 069import org.jfree.chart.renderer.category.BarRenderer; 070import org.jfree.ui.ApplicationFrame; 071import org.jfree.ui.GradientPaintTransformType; 072import org.jfree.ui.RefineryUtilities; 073import org.jfree.ui.StandardGradientPaintTransformer; 074import org.jfree.ui.TextAnchor; 075 076import com.itextpdf.text.Document; 077import com.itextpdf.text.DocumentException; 078//import com.itextpdf.text.Font; 079import com.itextpdf.text.FontFactory; 080import com.itextpdf.text.Header; 081//import com.itextpdf.text.Rectangle; 082import com.itextpdf.text.Paragraph; 083import com.itextpdf.text.pdf.DefaultFontMapper; 084import com.itextpdf.text.pdf.FontMapper; 085import com.itextpdf.text.pdf.PdfContentByte; 086import com.itextpdf.text.pdf.PdfTemplate; 087import com.itextpdf.text.pdf.PdfWriter; 088 089 090import au.com.bytecode.opencsv.CSVReader; 091//import au.com.bytecode.opencsv.CSVWriter; 092import jxl.*; 093 094 095import ca.bc.webarts.widgets.Util; 096 097/** 098 * A class that reads a csv file of data and creates a bar chart - Categoirzed, grouped Stacked Bars. 099 * It also saves the rendered chart as a png and svg file so you can use it elsewhere.<br /> 100 * <a href="file:///C:/DOCUME~1/tgutwin/Desktop/BCHydroReliabilityAndGrowthSpend.svg"> 101 * <img src="file:///C:/DOCUME~1/tgutwin/Desktop/BCHydroReliabilityAndGrowthSpend.png" width="240" height="160"/> 102 * </a> 103 * <br /><br /> 104 * The data in the csv has to be in the following format:<br /> 105 * <pre> 106 * // Sample data for a Categorized Bar chart with sub-grouped stacked bars. 107 * // the first real line is to define the group titles 108 * Fiscal Year,Accounting Category,Project Driver Dollars 109 * F2005,SI Sustain,Reliability,12.20 110 * F2005,SI Sustain,Vegetation Management,25.5 111 * F2005,SI Sustain,Asset Replacement,34 112 * F2005,SI Sustain,Wires Maintenance,25.6 113 * F2005,Growth,System,8.4 114 * F2006,SI Sustain,Reliability,13.40 115 * F2006,SI Sustain,Vegetation Management,23.40 116 * F2006,SI Sustain,Asset Replacement,33.00 117 * F2006,SI Sustain,Wires Maintenance,26.90 118 * F2006,Growth,System,21.20 119 * F2007,SI Sustain,Reliability,14.51 120 * F2007,SI Sustain,Vegetation Management,22.20 121 * F2007,SI Sustain,Asset Replacement,38.10 122 * F2007,SI Sustain,Wires Maintenance,26.80 123 * F2007,Growth,System,31.70 124 * F2008,SI Sustain,Reliability,14.51 125 * F2008,SI Sustain,Vegetation Management,23.00 126 * F2008,SI Sustain,Asset Replacement,38.20 127 * F2008,SI Sustain,Wires Maintenance,31.30 128 * F2008,Growth,System,52.50 129 * </pre> 130 * Tom Gutwin 131 */ 132public class CategorizedStackedBarChart extends ApplicationFrame 133{ 134 public static final short FILETYPE_UNKNOWN=0; 135 public static final short FILETYPE_XLS=1; 136 public static final short FILETYPE_CSV=2; 137 public static final short FILETYPE_SQL=3; 138 139 private String categoryName = "Category"; 140 private Vector categories = new Vector(); 141 private String groupName = "Group"; 142 private Vector groups = new Vector(); 143 private String stackedDataName = "StackedData"; 144 private Vector stackedGroup = new Vector(); 145 private GroupedStackedBarRenderer groupedstackedbarrenderer 146 = new GroupedStackedBarRenderer(); 147 private KeyToGroupMap keytogroupmap_ = new KeyToGroupMap(); 148 private JFreeChart jfreechart_ = null; 149 private int chartdX = 1200; 150 private int chartdY = 800; 151 /* The class value for the percent of category space to use for a margin around the category. 152 It is a decimal double value representing the percentage to use (for example, 0.05 is five percent).*/ 153 private double categoryMargin_ = 0.25; 154 155 private String chartTitle = "Categorized Stacked Bar Chart"; 156 public Color[] chartColours = new Color[20]; 157 public GradientPaint[] gradientpaint = new GradientPaint[chartColours.length]; 158 public Color chartBackgroundFromColor = new Color(200,205,255); 159 public Color chartBackgroundToColor = new Color(160,240,255); 160 public Font itemLabelFont = new Font("SansSerif",Font.PLAIN,7); 161 private boolean showLabels = true; 162 private boolean showToolTips = true; 163 164 /** 165 * Constructor for the CategorizedStackedBarChart object. This constructor 166 * does not do anything exept instantiate so some of the methods can be used. 167 * 168 */ 169 public CategorizedStackedBarChart() 170 { 171 super(""); 172 } 173 174 175 /** 176 * Constructor for the CategorizedStackedBarChart object. This constructor 177 * does not do anything exept instantiate so some of the methods can be used. 178 * 179 */ 180 public CategorizedStackedBarChart(String chartTitle) 181 { 182 super(chartTitle); 183 this.chartTitle = chartTitle; 184 //init colours 185 initColours(); 186 } 187 188 189 /** 190 * Constructor for the CategorizedStackedBarChart object 191 * 192 * @param chartTitle is the title to place at the top of the chart, it also uses this for the exported filenames 193 * @param csvFilename is the name of the csv file to read the data from 194 */ 195 public CategorizedStackedBarChart(String chartTitle, String filename) 196 { 197 super(chartTitle); 198 this.chartTitle = chartTitle; 199 //init colours 200 initColours(); 201 202 JPanel jpanel = null; 203 204 switch (getFileType(filename)) 205 { 206 case FILETYPE_XLS: 207 jpanel = createChartPanel(createDatasetFromXLS(filename)); 208 break; 209 210 case FILETYPE_CSV: 211 jpanel = createChartPanel(createDatasetFromCSVFile(filename)); 212 break; 213 214 case FILETYPE_SQL: 215 jpanel = createChartPanel(createDatasetFromSQL(filename)); 216 break; 217 218 default: 219 220 } 221 222 if (jpanel!=null) 223 { 224 jpanel.setPreferredSize(new Dimension(chartdX, chartdY)); 225 setContentPane(jpanel); 226 } 227 } 228 229 230 public static short getFileType(String filename) 231 { 232 short retVal = FILETYPE_UNKNOWN; 233 if (filename.length() >=3) 234 { 235 String ext = filename.substring(filename.length()-3).toLowerCase(); 236 //System.out.println("Input file is type:"+ext); 237 if (ext.equals("xls")) { retVal = FILETYPE_XLS;} 238 else if (ext.equals("sql")) {retVal = FILETYPE_SQL;} 239 else if (ext.equals("csv")) { retVal = FILETYPE_CSV;} 240 } 241 return retVal; 242 } 243 244 245 private void initColours() 246 { 247 chartColours[0] = new Color(34, 34, 255); 248 chartColours[1] = new Color(34, 255, 34); 249 chartColours[2] = new Color(255, 34, 34); 250 chartColours[3] = new Color(255, 255, 34); 251 chartColours[4] = new Color(255, 100, 34); 252 chartColours[5] = new Color(0, 100, 150); 253 chartColours[6] = new Color(235, 235, 235); 254 chartColours[7] = new Color(255, 10, 255); 255 chartColours[8] = new Color(100, 40, 100); 256 chartColours[9] = new Color(70, 255, 255); 257 chartColours[10] = new Color(155, 10, 255); 258 chartColours[11] = new Color(25, 125, 0); 259 chartColours[12] = new Color(255, 34, 134); 260 chartColours[13] = new Color(180, 180, 255); 261 chartColours[14] = new Color(180, 60, 0); 262 chartColours[15] = new Color(134, 150, 150); 263 chartColours[16] = new Color(225, 225, 225); 264 chartColours[17] = new Color(0, 255, 255); 265 chartColours[18] = new Color(140, 140, 140); 266 chartColours[19] = new Color(50, 50, 50); 267 for (int i=0; i<chartColours.length && chartColours[i] != null; i++) 268 gradientpaint[i] = new GradientPaint(0.0F, 0.0F, chartColours[i], 269 0.0F, 0.0F, chartColours[i].darker().darker().darker()); 270 } 271 272 273 /** 274 * The main program for the CategorizedStackedBarChart class 275 * 276 * @param args The command line arguments (1st is the csvFilename, the rest make up a Chart Title) 277 */ 278 public static void main(String[] args) 279 { 280 if (args.length >0 && getFileType(args[0])!=FILETYPE_UNKNOWN) 281 { 282 CategorizedStackedBarChart chart = null; 283 String titleParms = "Categorized Stacked Bar Chart"; 284 if (args.length >1 ) 285 { 286 titleParms = ""; 287 for (int i=1; i < args.length; i++) 288 titleParms += args[i] + " "; 289 titleParms = titleParms.trim(); 290 } 291 chart = new CategorizedStackedBarChart(titleParms, args[0]); 292 chart.pack(); 293 RefineryUtilities.centerFrameOnScreen(chart); 294 chart.setVisible(true); 295 chart.saveChartToSvg(new File(Util.spacesToCapsInString(titleParms)+".svg")); 296 chart.saveChartToPng(new File(Util.spacesToCapsInString(titleParms)+".png")); 297 chart.saveChartToPdf(new File(Util.spacesToCapsInString(titleParms)+".pdf")); 298 } 299 else 300 { 301 System.out.println("Don't be a dufus... give me a csv, sqlFilename or xls filename to use."); 302 } 303 } 304 305 306 public JFreeChart getChart() { return jfreechart_;} 307 308 309 /** 310 * Description of the Method 311 * 312 * @return Description of the Return Value 313 */ 314 public JPanel createChartPanel(CategoryDataset ds) 315 { 316 jfreechart_ = createCategoryStackedBarChart(ds); 317 return new ChartPanel(jfreechart_); 318 } 319 320 321 /** 322 * Queries a db and converts the results into a Dataset that can be used in 323 * a Grouped Stacked Bar Chart. 324 * 325 * @return The SQL results as a CategoryDataset 326 */ 327 private CategoryDataset createDatasetFromSQL(String sqlFilename) 328 { 329 DefaultCategoryDataset cd = new DefaultCategoryDataset(); 330 331 try 332 { 333 } 334 catch( Exception ex) 335 { 336 } 337 return cd; 338 } 339 340 341 /** 342 * takes an xls file in the proper format into a Dataset useable by the charter. 343 * 344 * @return Description of the Return Value 345 */ 346 public CategoryDataset createDatasetFromXLS(String xlsFilename) 347 { 348 DefaultCategoryDataset cd = new DefaultCategoryDataset(); 349 350 /* These are to read data from an excel data file */ 351 Workbook workbook = null; 352 Sheet configSheet = null; 353 Sheet dataSheet = null; 354 355 try 356 { 357 /* Get the Excel Config file init */ 358 System.out.println("Opening Excel Workbook:"+xlsFilename ); 359 File f = new File(xlsFilename); 360 if (f.exists() && f.canRead()) 361 { 362 workbook = Workbook.getWorkbook(f); 363 dataSheet = workbook.getSheet(0); // keep the data on the 1st sheet 364 String categoryName = ""; 365 String groupName = ""; 366 String stackName = ""; 367 double value = 0.0; 368 boolean done = false; 369 boolean nextGroup = false; 370 String cellStr = ""; 371 int valCol = 3; 372 keytogroupmap_ = null; 373 374 for (int row = 3; !done; row++) 375 { 376 nextGroup = false; 377 System.out.print((row-2)+") "); 378 try 379 { 380 // getCell is (Column, row) 381 cellStr = dataSheet.getCell(0,row+1).getContents().trim(); 382 if (cellStr !=null && !cellStr.equals("")) nextGroup = true; //this is a total row so skip it 383 cellStr = dataSheet.getCell(0,row).getContents().trim(); 384 if (cellStr !=null && !cellStr.equals("")) categoryName = cellStr; 385 //System.out.print(" (cellStr="+cellStr+") "); 386 System.out.print(categoryName+", "); 387 cellStr = dataSheet.getCell(1,row+1).getContents().trim(); 388 if (cellStr !=null && !cellStr.equals("")) nextGroup = true; //this is a total row so skip it 389 cellStr = dataSheet.getCell(1,row).getContents().trim(); 390 if (cellStr !=null && !cellStr.equals("")) groupName = cellStr; 391 //System.out.print(" (cellStr="+cellStr+") "); 392 System.out.print(groupName+", "); 393 cellStr = dataSheet.getCell(2,row).getContents().trim(); 394 if (cellStr !=null && !cellStr.equals("")) stackName = cellStr; 395 //System.out.print(" (cellStr="+cellStr+") "); 396 System.out.print(stackName+", "); 397 398 399 if (!nextGroup) 400 { 401 // Find the last value column 402 valCol = 3; 403 try 404 { 405 while (dataSheet.getCell(valCol+1,row)!=null && 406 dataSheet.getCell(valCol+1,row).getContents()!=null && 407 !dataSheet.getCell(valCol+1,row).getContents().trim().equals("")) 408 valCol++; 409 } 410 catch (java.lang.ArrayIndexOutOfBoundsException vEx) 411 { 412 413 } 414 value = ((NumberCell)dataSheet.getCell(valCol,row)).getValue(); 415 System.out.print(value); 416 417 if (keytogroupmap_ == null) keytogroupmap_ = new KeyToGroupMap(groupName); 418 if (!categories.contains(categoryName)) categories.add(categoryName); 419 if (!groups.contains(groupName)) groups.add(groupName); 420 if (!stackedGroup.contains(stackName)) stackedGroup.add(stackName); 421 cd.addValue(value, stackName + " ("+groupName+")", categoryName); 422 keytogroupmap_.mapKeyToGroup(stackName + " ("+groupName+")", groupName); 423 424 try 425 { 426 if (dataSheet.getCell(valCol,row+1) == null || 427 dataSheet.getCell(valCol,row+1).getContents() == null || 428 dataSheet.getCell(valCol,row+1).getContents().equals("NA") || 429 dataSheet.getCell(valCol,row+1).getContents().equals("") ) 430 done = true; 431 } 432 catch (java.lang.ArrayIndexOutOfBoundsException vEx) 433 { 434 System.out.println("\nWe Seem to be done at Row:"+row+" Col:"+valCol); 435 done = true; 436 } 437 } 438 System.out.println(); 439 } 440 catch (java.lang.ArrayIndexOutOfBoundsException vEx) 441 { 442 nextGroup = true; done = true; 443 } 444 445 } 446 groupedstackedbarrenderer.setSeriesToGroupMap(keytogroupmap_); 447 } 448 else 449 System.out.println("What The F%#@, Cannot Read File "+xlsFilename); 450 } 451 catch (FileNotFoundException fnfEx) 452 { 453 System.out.println("File Not Found "+xlsFilename); 454 fnfEx.printStackTrace(); 455 } 456 catch (IOException ioEx) 457 { 458 System.out.println("Could Not read input EXCEL File: "+xlsFilename); 459 ioEx.printStackTrace(); 460 } 461 catch (jxl.read.biff.BiffException biffEx) 462 { 463 System.out.println("Could Not read input EXCEL File: "+xlsFilename); 464 biffEx.printStackTrace(); 465 } 466 catch( Exception ex) 467 { 468 ex.printStackTrace(); 469 } 470 return cd; 471 } 472 473 474 /** 475 * Description of the Method 476 * 477 * @return Description of the Return Value 478 */ 479 public CategoryDataset createDatasetFromCSVFile(String csvFilename) 480 { 481 DefaultCategoryDataset cd = new DefaultCategoryDataset(); 482 483 try 484 { 485 CSVReader reader = new CSVReader(new FileReader(csvFilename)); 486 String [] nextLine; 487 int rows = 0; 488 while ((nextLine = reader.readNext()) != null) 489 { 490 if (nextLine.length>1 && !nextLine[0].startsWith("//")) 491 { 492 if (rows==1) //this is to setup an initial group 493 { 494 keytogroupmap_ = new KeyToGroupMap(nextLine[1]); 495 } 496 if (rows==0) 497 { 498 categoryName = nextLine[0]; 499 groupName = nextLine[1]; 500 stackedDataName = nextLine[2]; 501 } 502 else 503 { 504 // nextLine[] is an array of values from the line 505 System.out.print(rows+") "); 506 for (int i=0;i< nextLine.length; i++){System.out.print(nextLine[i]+", ");} 507 System.out.println(""); 508 509 if (!categories.contains(nextLine[0])) categories.add(nextLine[0]); 510 if (!groups.contains(nextLine[1])) groups.add(nextLine[1]); 511 if (!stackedGroup.contains(nextLine[2])) stackedGroup.add(nextLine[2]); 512 // add to dataset Value , Group , Category 513 cd.addValue(Double.parseDouble(nextLine[3]), nextLine[2] + " ("+nextLine[1]+")", nextLine[0]); 514 //cd.addValue(Double.parseDouble(nextLine[3]), nextLine[2], nextLine[0]); 515 // Assigns which data gets into which categorygroup. 516 // One group represents One Stack on the barchart 517 //stackedGroup.add(nextLine[2]); 518 keytogroupmap_.mapKeyToGroup(nextLine[2] + " ("+nextLine[1]+")", nextLine[1]); 519 //keytogroupmap_.mapKeyToGroup(nextLine[2], nextLine[1]); 520 } 521 rows++; 522 } 523 } 524 groupedstackedbarrenderer.setSeriesToGroupMap(keytogroupmap_); 525 } 526 catch (FileNotFoundException fnfEx) 527 { 528 System.out.println("File Not Found "+csvFilename); 529 fnfEx.printStackTrace(); 530 } 531 catch (IOException ioEx) 532 { 533 System.out.println("Cannot read from CSV file "+csvFilename); 534 ioEx.printStackTrace(); 535 } 536 537 return cd; 538 } 539 540 541 /** 542 * Create the dataset from delimited String. 543 * 544 * @return Description of the Return Value 545 */ 546 public CategoryDataset createDatasetFromCSV(String csv) 547 { 548 DefaultCategoryDataset cd = new DefaultCategoryDataset(); 549 550 try 551 { 552 CSVReader reader = new CSVReader(new java.io.StringReader(csv)); 553 String [] nextLine; 554 int rows = 0; 555 while ((nextLine = reader.readNext()) != null) 556 { 557 if (nextLine.length>1 && !nextLine[0].startsWith("//")) 558 { 559 if (rows==1) //this is to setup an initial group 560 { 561 keytogroupmap_ = new KeyToGroupMap(nextLine[1]); 562 } 563 if (rows==0) 564 { 565 categoryName = nextLine[0]; 566 groupName = nextLine[1]; 567 stackedDataName = nextLine[2]; 568 } 569 else 570 { 571 // nextLine[] is an array of values from the line 572 System.out.print(rows+") "); 573 for (int i=0;i< nextLine.length; i++){System.out.print(nextLine[i]+", ");} 574 System.out.println(""); 575 576 if (!categories.contains(nextLine[0])) categories.add(nextLine[0]); 577 if (!groups.contains(nextLine[1])) groups.add(nextLine[1]); 578 if (!stackedGroup.contains(nextLine[2])) stackedGroup.add(nextLine[2]); 579 // add to dataset Value , Group , Category 580 cd.addValue(Double.parseDouble(nextLine[3]), nextLine[2] + " ("+nextLine[1]+")", nextLine[0]); 581 //cd.addValue(Double.parseDouble(nextLine[3]), nextLine[2], nextLine[0]); 582 // Assigns which data gets into which categorygroup. 583 // One group represents One Stack on the barchart 584 //stackedGroup.add(nextLine[2]); 585 keytogroupmap_.mapKeyToGroup(nextLine[2] + " ("+nextLine[1]+")", nextLine[1]); 586 //keytogroupmap_.mapKeyToGroup(nextLine[2], nextLine[1]); 587 } 588 rows++; 589 } 590 } 591 groupedstackedbarrenderer.setSeriesToGroupMap(keytogroupmap_); 592 } 593 catch (IOException ioEx) 594 { 595 System.out.println("Cannot read from CSV "+csv); 596 ioEx.printStackTrace(); 597 } 598 599 return cd; 600 } 601 602 603 /** 604 * This method does all the work for getting the chart plot set up. 605 * It sets the labels, axis, colours, margins and whatnot. It uses the class chartTtile. 606 * 607 * @param categorydataset the dataset to use in the chart 608 * @return The category grouped stacked bar chart. 609 */ 610 public JFreeChart createCategoryStackedBarChart(CategoryDataset categorydataset) 611 { 612 return createCategoryStackedBarChart(this.chartTitle, categorydataset); 613 } 614 615 616 /** 617 * This method does all the work for getting the chart plot set up. It sets the labels, axis, colours, margins and whatnot. 618 * 619 * @param chartTitle a new title to put at the top of the chart 620 * @param categorydataset the dataset to use in the chart 621 * @return The category grouped stacked bar chart. 622 */ 623 public JFreeChart createCategoryStackedBarChart(String chartTitle, 624 CategoryDataset categorydataset) 625 { 626 return createCategoryStackedBarChart(chartTitle, null, categorydataset); 627 } 628 629 630 /** 631 * This method does all the work for getting the chart plot set up. It sets the labels, axis, colours, margins and whatnot. 632 * 633 * @param chartTitle a new title to put at the top of the chart 634 * @param chartSubTitle a new subtitle below the title 635 * @param categorydataset the dataset to use in the chart 636 * @return The category grouped stacked bar chart. 637 */ 638 public JFreeChart createCategoryStackedBarChart(String chartTitle, String subTitle, 639 CategoryDataset categorydataset) 640 { 641 jfreechart_ = ChartFactory.createStackedBarChart(chartTitle, 642 categoryName, stackedDataName, 643 categorydataset, 644 PlotOrientation.VERTICAL, 645 true, true, false); 646 647 if (subTitle !=null && !subTitle.equals("")) 648 { 649 org.jfree.chart.title.TextTitle textSubTitle = new org.jfree.chart.title.TextTitle(subTitle); 650 jfreechart_.addSubtitle(textSubTitle); 651 } 652 653 CategoryPlot categoryplot = (CategoryPlot) jfreechart_.getPlot(); 654 655 // setup axis label 656 SubCategoryAxis subcategoryaxis 657 = new SubCategoryAxis(groupName+" / "+categoryName); 658 659 // set the margin between the Categories (% of space ) 660 subcategoryaxis.setCategoryMargin(categoryMargin_); 661 662 // sub categorize the groups 663 for (int j=0; j<groups.size(); j++) 664 { 665 subcategoryaxis.addSubCategory((String)groups.get(j)); 666 subcategoryaxis.setTickLabelFont((String)groups.get(j), itemLabelFont); 667 } 668 669 subcategoryaxis.setMaximumCategoryLabelWidthRatio(1/groups.size()); 670 subcategoryaxis.setCategoryMargin(0.15); 671 subcategoryaxis.setMaximumCategoryLabelLines(3); 672 673 // Set the axis to the subcategorized axis already defined above 674 categoryplot.setDomainAxis(subcategoryaxis); 675 676 // Category series labels 677 groupedstackedbarrenderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator()); 678 groupedstackedbarrenderer.setItemLabelsVisible(showLabels); 679 groupedstackedbarrenderer.setItemLabelFont(itemLabelFont); 680 //groupedstackedbarrenderer.setItemMargin(0.30); 681 ItemLabelPosition p = new ItemLabelPosition( 682 ItemLabelAnchor.CENTER, TextAnchor.CENTER, TextAnchor.CENTER, 0.0 683 ); 684 groupedstackedbarrenderer.setPositiveItemLabelPosition(p); 685 categoryplot.setRenderer(groupedstackedbarrenderer); 686 687 // Assign the Floatover tooltips 688 StandardCategoryToolTipGenerator toolTipGen = new StandardCategoryToolTipGenerator(); 689 groupedstackedbarrenderer.setToolTipGenerator(toolTipGen); 690 //groupedstackedbarrenderer.setDisplayToolTips(showToolTips); 691 692 // Group the entries in the Legend 693 categoryplot.setFixedLegendItems(createLegendItems()); 694 695 // Assign gradient colours to the bars 696 BarRenderer barrenderer = (BarRenderer) categoryplot.getRenderer(); 697 barrenderer.setDrawBarOutline(false); 698 barrenderer.setMaximumBarWidth(0.2); 699 // set the margin between the sub-groups with in each category (% of space ) 700 barrenderer.setItemMargin(0.02); 701 702 // Set up the backFrame colour 703 jfreechart_.setBackgroundPaint(new GradientPaint( 704 0, 705 0, 706 chartBackgroundFromColor, 707 chartdX, 708 chartdY, 709 chartBackgroundToColor)); 710 711 // Assign the colours to the stacked groups. 712 // each stacked group gets its own colour 713 for (int j = 0; j < groups.size(); j++) 714 for (int i=0; i<stackedGroup.size() && chartColours[i] != null; i++) 715 barrenderer.setSeriesPaint((j*stackedGroup.size()) + i, gradientpaint[i]); 716 717 return jfreechart_; 718 } 719 720 721 /** Gets the current jfreechart plot (null if not already initialized). **/ 722 public CategoryPlot getPlot() 723 { 724 CategoryPlot categoryplot = null; 725 if (jfreechart_ !=null) 726 { 727 categoryplot = (CategoryPlot) jfreechart_.getPlot(); 728 } 729 return categoryplot; 730 } 731 732 733 /** 734 * Adds a marker for the Domain category. 735 * 736 * @param catMarginPercent The main category spacing in percent (where 0.10 is ten percent). 737 */ 738 public void setDomainMarker(String categoryKey) 739 { 740 if (jfreechart_ !=null) 741 { 742 CategoryPlot categoryplot = this.getPlot(); 743 if (categoryplot !=null) 744 { 745 /* 746 groupedstackedbarrenderer.getSeriesToGroupMap(keytogroupmap_); 747 final CategoryMarker marker = new CategoryMarker(categoryKey); 748 marker.setLabel("Projects Year"); 749 marker.setLabelFont(new Font("SansSerif", Font.ITALIC, 11)); 750 marker.setLabelAnchor(org.jfree.ui.RectangleAnchor.LEFT); 751 marker.setLabelTextAnchor(TextAnchor.CENTER_LEFT); 752 marker.setPaint(new Color(222, 222, 255, 128)); 753 */ 754 } 755 } 756 } 757 758 759 /** 760 * Changes the spacing between the categories. 761 * 762 * @param catMarginPercent The main category spacing in percent (where 0.10 is ten percent). 763 */ 764 public void setCategoryMargins(double catMarginPercent) 765 { 766 if (jfreechart_ !=null) 767 { 768 CategoryPlot categoryplot = this.getPlot(); 769 if (categoryplot !=null) 770 { 771 BarRenderer barrenderer = (BarRenderer) categoryplot.getRenderer(); 772 barrenderer.setItemMargin(catMarginPercent); 773 774 //SubCategoryAxis subcategoryaxis = (SubCategoryAxis) barrenderer.getDomainAxis(categoryplot,0); 775 //subcategoryaxis.setCategoryMargin(subCatMarginPercent); 776 } 777 } 778 } 779 780 781 /** 782 * Changes the spacing between the sub categories. 783 * 784 * @param subCatMarginPercent The sub-category spacing in percent (where 0.10 is ten percent). 785 */ 786 public void setSubCategoryMargins(double subCatMarginPercent ) 787 { 788 if (jfreechart_ !=null) 789 { 790 CategoryPlot categoryplot = (CategoryPlot) jfreechart_.getPlot(); 791 if (categoryplot !=null) 792 { 793 // setup axis label 794 SubCategoryAxis subcategoryaxis 795 = new SubCategoryAxis(groupName+" / "+categoryName); 796 797 // set the margin between the Categories (% of space ) 798 subcategoryaxis.setCategoryMargin(categoryMargin_); 799 800 // sub categorize the groups 801 for (int j=0; j<groups.size(); j++) 802 { 803 subcategoryaxis.addSubCategory((String)groups.get(j)); 804 subcategoryaxis.setTickLabelFont((String)groups.get(j), itemLabelFont); 805 } 806 807 subcategoryaxis.setMaximumCategoryLabelWidthRatio(1/groups.size()); 808 subcategoryaxis.setCategoryMargin(subCatMarginPercent); 809 subcategoryaxis.setMaximumCategoryLabelLines(3); 810 811 // Set the axis to the subcategorized axis already defined above 812 categoryplot.setDomainAxis(subcategoryaxis); 813 814 } 815 } 816 } 817 818 819 /** 820 * Adds/or changes the subtitle. 821 * 822 * @param subtitleParm - The new subtitle 823 */ 824 public void addSubtitle(String subtitleParm ) 825 { 826 if (subtitleParm !=null && !subtitleParm.equals("")) 827 { 828 org.jfree.chart.title.TextTitle textSubTitle = new org.jfree.chart.title.TextTitle(subtitleParm); 829 jfreechart_.addSubtitle(textSubTitle); 830 } 831 } 832 833 834 /** 835 * Sets up the words in the grouped legend. 836 * 837 * @return Description of the Return Value 838 */ 839 private LegendItemCollection createLegendItems() 840 { 841 LegendItemCollection legenditemcollection = new LegendItemCollection(); 842 LegendItem legenditem = null; 843 try 844 { 845 for (int j=0; j<stackedGroup.size(); j++) 846 { 847 legenditem = new LegendItem((String)stackedGroup.get(j), "-", null, null, 848 Plot.DEFAULT_LEGEND_ITEM_BOX, 849 chartColours[j]); 850 legenditemcollection.add(legenditem); 851 } 852 } 853 catch (Exception ex) 854 { 855 System.out.println(" Error Setting Legend Colours "); 856 } 857 return legenditemcollection; 858 } 859 860 861 /** saves the passed chart to a svg file in the current models yearly dir.**/ 862 public void saveChartToSvg(JFreeChart chart, File svgFile) 863 { 864 if (svgFile != null) 865 try 866 { 867 // Get a DOMImplementation and create an XML document 868 org.w3c.dom.DOMImplementation domImpl = 869 org.apache.batik.dom.GenericDOMImplementation.getDOMImplementation(); 870 org.w3c.dom.Document document = domImpl.createDocument(null, "svg", null); 871 872 // Create an instance of the SVG Generator 873 org.apache.batik.svggen.SVGGraphics2D svgGenerator = 874 new org.apache.batik.svggen.SVGGraphics2D(document); 875 876 // draw the chart in the SVG generator 877 chart.draw(svgGenerator, new java.awt.Rectangle(chartdX, chartdY)); 878 879 // Write svg file 880 OutputStream outputStream = new FileOutputStream(svgFile); 881 Writer out = new OutputStreamWriter(outputStream, "UTF-8"); 882 svgGenerator.stream(out, true /* use css */); 883 outputStream.flush(); 884 outputStream.close(); 885 } 886 catch (IOException ioEx) 887 { 888 System.out.println("Error Saving "+svgFile.toString()); 889 } 890 891 } 892 893 894 /** saves the passed chart to a svg file in the current models yearly dir.**/ 895 public void saveChartToSvg(File svgFile) 896 { 897 saveChartToSvg(jfreechart_, svgFile); 898 } 899 900 901 /** 902 * Saves the passed chart to a png file in the specified file. 903 * NOTE: This method spawns a seperate thread for this process. 904 * 905 * @param savedFile is the resulting file to save into 906 **/ 907 public void saveChartToPng(File savedFile) 908 { 909 if (savedFile != null) 910 saveChartToPng( jfreechart_, savedFile); 911 } 912 913 914 /** 915 * Saves the passed chart to a png file in the specified file. 916 * NOTE: This method spawns a seperate thread for this process. 917 * 918 * @param chart is the chart to render to a file 919 * @param savedFile is the resulting file to save into 920 **/ 921 public void saveChartToPng(JFreeChart chart, File savedFile) 922 { 923 if (savedFile != null) 924 { 925 /* 926 // Run in separate thread. 927 Thread fileSaveThread = 928 new Thread() 929 { 930 public void run() 931 { 932 */ 933 try 934 { 935 ChartUtilities.saveChartAsPNG(savedFile, chart, chartdX, chartdY); 936 } 937 catch (IOException ioEx) 938 { 939 System.out.println("Error Saving "+savedFile.toString()); 940 } 941 /* 942 } 943 }; 944 fileSaveThread.start(); 945 */ 946 } 947 } 948 949 /** 950 * Writes a chart to an output stream in PDF format. 951 * 952 * @param out the output stream. 953 * @param chart the chart. 954 * @param width the chart width. 955 * @param height the chart height. 956 * @param title duh 957 * @exception IOException Description of the Exception 958 */ 959 public static void exportChartAsPDF(OutputStream out, 960 JFreeChart chart, 961 int width,int height, String title) 962 { 963 exportChartAsPDF(out, chart, width, height, new DefaultFontMapper(),title); 964 } 965 966 967 /** 968 * Writes a chart to an output stream in PDF format. 969 * 970 * @param out the output stream. 971 * @param chart the chart. 972 * @param width the chart width. 973 * @param height the chart height. 974 * @exception IOException Description of the Exception 975 */ 976 public static void exportChartAsPDF(OutputStream out, 977 JFreeChart chart, int width,int height) 978 { 979 exportChartAsPDF(out, chart, width, height, new DefaultFontMapper(),""); 980 } 981 982 983 /** 984 * Writes a chart to an output stream in PDF format. 985 * 986 * @param out the output stream. 987 * @param chart the chart. 988 * @param width the chart width. 989 * @param height the chart height. 990 * @param mapper Description of the Parameter 991 * @exception IOException Description of the Exception 992 */ 993 public static void exportChartAsPDF(OutputStream out, 994 JFreeChart chart, int width, 995 int height, 996 FontMapper mapper) 997 { 998 exportChartAsPDF(out, chart, width, height, mapper,""); 999 } 1000 1001 1002 /** 1003 * Writes a chart to an output stream in PDF format. 1004 * 1005 * 1006 1007 * @param out the output stream. 1008 * @param chart the chart. 1009 * @param width the chart width. 1010 * @param height the chart height. 1011 * @param mapper Description of the Parameter 1012 * @param title is the title to assign to the pdf 1013 * @exception IOException Description of the Exception 1014 */ 1015 public static void exportChartAsPDF(final OutputStream out, 1016 final JFreeChart chart, final int width, final int height, 1017 final FontMapper mapper, 1018 final String title) 1019 { 1020 if (out != null) 1021 { 1022 /* 1023 // Run in separate thread. 1024 Thread fileSaveThread = 1025 new Thread() 1026 { 1027 public void run() 1028 { 1029 */ 1030 try 1031 { 1032 com.itextpdf.text.Rectangle pagesize = new com.itextpdf.text.Rectangle(width, height); 1033 Document document = new Document(pagesize, 50, 50, 50, 50); 1034 PdfWriter writer = PdfWriter.getInstance(document, out); 1035 document.open(); 1036 1037 PdfContentByte cb = writer.getDirectContent(); 1038 PdfTemplate tp = cb.createTemplate(width, height); 1039 Graphics2D g2 = tp.createGraphics(width, height, mapper); 1040 Rectangle2D r2D = new Rectangle2D.Double(0, 0, width, height); 1041 chart.draw(g2, r2D); 1042 g2.dispose(); 1043 cb.addTemplate(tp, 0, 0); 1044 document.close(); 1045 } 1046 catch (DocumentException de) 1047 { 1048 System.out.println("Error Saving PDF Stream"+out.toString()); 1049 System.err.println(de.getMessage()); 1050 } 1051 catch (Exception ioEx) 1052 { 1053 System.out.println("Error Saving PDF Stream"+out.toString()); 1054 System.err.println(ioEx.getMessage()); 1055 } 1056 /* 1057 } // run 1058 }; // Thread 1059 fileSaveThread.start(); 1060 */ 1061 } 1062 } 1063 1064 1065 /** saves the passed chart to a pdf file in the current models yearly dir. 1066 * NOTE: This method spawns a seperate thread for this process. 1067 * 1068 **/ 1069 public void saveChartToPdf(File pdfFile) 1070 { 1071 saveChartToPdf(jfreechart_, pdfFile); 1072 } 1073 1074 1075 /** saves the passed chart to a pdf file in the current models yearly dir. 1076 * NOTE: This method spawns a seperate thread for this process. 1077 * 1078 **/ 1079 public void saveChartToPdf(String fileName) 1080 { 1081 File pdfFile = new File(fileName); 1082 saveChartToPdf(jfreechart_, pdfFile); 1083 } 1084 1085 1086 /** saves the passed chart to a pdf file in the current models yearly dir. 1087 * NOTE: This method spawns a seperate thread for this process. 1088 * 1089 **/ 1090 public void saveChartToPdf(JFreeChart chart, String fileName) 1091 { 1092 File pdfFile = new File(fileName); 1093 saveChartToPdf(chart, pdfFile); 1094 } 1095 1096 1097 /** saves the passed chart to a pdf file in the current models yearly dir. 1098 * NOTE: This method spawns a seperate thread for this process. 1099 * 1100 **/ 1101 public void saveChartToPdf(JFreeChart chart, File pdfFile) 1102 { 1103 //File pdfFile = new File(fileName); 1104 1105 if (pdfFile != null) 1106 { 1107 try 1108 { 1109 OutputStream out = new BufferedOutputStream(new FileOutputStream(pdfFile)); 1110 exportChartAsPDF(out, chart, chartdX, chartdY, new DefaultFontMapper()); 1111 out.close(); 1112 } 1113 catch (FileNotFoundException fnfEx) 1114 { 1115 System.out.println("Error Saving PDF "+pdfFile.getName()); 1116 System.err.println(fnfEx.getMessage()); 1117 } 1118 catch (IOException ioEx) 1119 { 1120 System.out.println("Error Saving PDF "+pdfFile.getName()); 1121 System.err.println(ioEx.getMessage()); 1122 } 1123 } 1124 } 1125} 1126