001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.survival.kaplanmeier.figure; 022 023import org.biojava.nbio.survival.cox.*; 024 025import javax.imageio.ImageIO; 026import javax.swing.*; 027import java.awt.*; 028import java.awt.geom.AffineTransform; 029import java.awt.image.BufferedImage; 030import java.io.File; 031import java.io.FileWriter; 032import java.text.DecimalFormat; 033import java.util.ArrayList; 034import java.util.Collections; 035import java.util.LinkedHashMap; 036 037/** 038 * 039 * @author Scooter Willis <willishf at gmail dot com> 040 */ 041public class KaplanMeierFigure extends JPanel { 042 043 private static final long serialVersionUID = 1L; 044 045 ArrayList<String> title = new ArrayList<String>(); 046 /** 047 * 048 */ 049 private int top; 050 /** 051 * 052 */ 053 private int bottom; 054 /** 055 * 056 */ 057 private int left; 058 private int yaxisLabel = 20; 059 /** 060 * 061 */ 062 private int right; 063 int titleHeight; 064 int xAxisLabelHeight; 065 int labelWidth; 066 double minTime = 0.0; 067 double maxTime = 10.0; 068 double minPercentage = 0.0; 069 double maxPercentage = 1.0; 070 FontMetrics fm; 071 KMFigureInfo kmfi = new KMFigureInfo(); 072 LinkedHashMap<String, ArrayList<CensorStatus>> survivalData = new LinkedHashMap<String, ArrayList<CensorStatus>>(); 073 ArrayList<String> lineInfoList = new ArrayList<String>(); 074 SurvFitInfo sfi = new SurvFitInfo(); 075 private String fileName = ""; 076 private ArrayList<Double> xAxisTimeValues = new ArrayList<Double>(); 077 private ArrayList<Integer> xAxisTimeCoordinates = new ArrayList<Integer>(); 078 079 /** 080 * 081 */ 082 public KaplanMeierFigure() { 083 super(); 084 setSize(500, 400); 085 setBackground(Color.WHITE); 086 } 087 088 /** 089 * Get the name of the groups that are being plotted in the figure 090 * 091 * @return 092 */ 093 public ArrayList<String> getGroups() { 094 return new ArrayList<String>(survivalData.keySet()); 095 } 096 097 /** 098 * To get the median percentile for a particular group pass the value of 099 * .50. 100 * 101 * @param group 102 * @param percentile 103 * @return 104 */ 105 public Double getSurvivalTimePercentile(String group, double percentile) { 106 107 StrataInfo si = sfi.getStrataInfoHashMap().get(group); 108 ArrayList<Double> percentage = si.getSurv(); 109 Integer percentileIndex = null; 110 for (int i = 0; i < percentage.size(); i++) { 111 if (percentage.get(i) == percentile) { 112 if (i + 1 < percentage.size()) { 113 percentileIndex = i + 1; 114 } 115 break; 116 } else if (percentage.get(i) < percentile) { 117 percentileIndex = i; 118 break; 119 } 120 } 121 if (percentileIndex != null) { 122 return si.getTime().get(percentileIndex); 123 } else { 124 return null; 125 } 126 } 127 128 /** 129 * 130 * @param kmfi 131 */ 132 public void setKMFigureInfo(KMFigureInfo kmfi) { 133 this.kmfi = kmfi; 134 if (kmfi.width != null && kmfi.height != null) { 135 this.setSize(kmfi.width, kmfi.height); 136 } 137 } 138 139 public KMFigureInfo getKMFigureInfo() { 140 return kmfi; 141 } 142 143 /** 144 * 145 * @param lineInfoList 146 */ 147 public void setFigureLineInfo(ArrayList<String> lineInfoList) { 148 this.lineInfoList = lineInfoList; 149 this.repaint(); 150 } 151 152 /** 153 * 154 * @param title Title of figures 155 * @param ci 156 * @param strataVariable The column that based on value will do a figure 157 * line 158 * @param legendMap Map the value in the column to something readable 159 * @param useWeighted 160 * @throws Exception 161 */ 162 public void setCoxInfo(ArrayList<String> title, CoxInfo ci, String strataVariable, LinkedHashMap<String, String> legendMap, Boolean useWeighted) throws Exception { 163 LinkedHashMap<String, ArrayList<CensorStatus>> survivalData = new LinkedHashMap<String, ArrayList<CensorStatus>>(); 164 ArrayList<SurvivalInfo> siList = ci.getSurvivalInfoList(); 165 int n = 0; 166 int event = 0; 167 for (SurvivalInfo si : siList) { 168 String strata = si.getOriginalMetaData(strataVariable); 169 String legend = legendMap.get(strata); 170 if (legend == null) { 171 172 legend = strata; 173 } 174 ArrayList<CensorStatus> censorStatusList = survivalData.get(legend); 175 if (censorStatusList == null) { 176 censorStatusList = new ArrayList<CensorStatus>(); 177 survivalData.put(legend, censorStatusList); 178 } 179 CensorStatus cs = new CensorStatus(strata, si.getTime(), si.getStatus() + ""); 180 cs.weight = si.getWeight(); 181 censorStatusList.add(cs); 182 n++; 183 if (si.getStatus() == 1) { 184 event++; 185 } 186 } 187 188 setSurvivalData(title, survivalData, useWeighted); 189 CoxCoefficient cc = ci.getCoefficient(strataVariable); 190 //DecimalFormat df = new DecimalFormat("#.##"); 191 String line1 = "HR=" + fmt(cc.getHazardRatio(), 2, 0) + " (CI:" + fmt(cc.getHazardRatioLoCI(), 2, 0) + "-" + fmt(cc.getHazardRatioHiCI(), 2, 0) + ")"; 192 String line2 = "p=" + fmt(cc.getPvalue(), 3, 0); 193 // String line2 = "logrank P=" + fmt(ci.getScoreLogrankTestpvalue(), 3, 0); 194 String line3 = "n=" + n + " events=" + event; 195// System.out.println("setCoxInfo=" + cc.pvalue + " " + title); 196 197 198 ArrayList<String> lines = new ArrayList<String>(); 199 lines.add(line1); 200 lines.add(line2); 201 lines.add(line3); 202 setFigureLineInfo(lines); 203 } 204 205 /** 206 * 207 * @param d 208 * @param precision 209 * @param pad 210 * @return 211 */ 212 public static String fmt(Double d, int precision, int pad) { 213 String value = ""; 214 DecimalFormat dfe = new DecimalFormat("0.00E0"); 215 String dpad = "0."; 216 double p = 1.0; 217 for (int i = 0; i < (precision); i++) { 218 dpad = dpad + "0"; 219 p = p / 10.0; 220 } 221 DecimalFormat df = new DecimalFormat(dpad); 222 if (Math.abs(d) >= p) { 223 value = df.format(d); 224 } else { 225 value = dfe.format(d); 226 } 227 int length = value.length(); 228 int extra = pad - length; 229 if (extra > 0) { 230 for (int i = 0; i < extra; i++) { 231 value = " " + value; 232 } 233 } 234 return value; 235 } 236 237 /** 238 * 239 * @return 240 */ 241 public SurvFitInfo getSurvivalFitInfo() { 242 return sfi; 243 } 244 245 /** 246 * Allow setting of points in the figure where weighted correction has been 247 * done and percentage has already been calculated. 248 * 249 * @param title 250 * @param sfi 251 * @param userSetMaxTime 252 */ 253 public void setSurvivalData(ArrayList<String> title, SurvFitInfo sfi, Double userSetMaxTime) { 254 this.title = title; 255 LinkedHashMap<String, StrataInfo> strataInfoHashMap = sfi.getStrataInfoHashMap(); 256 Double mTime = null; 257 for (StrataInfo si : strataInfoHashMap.values()) { 258 for (double t : si.getTime()) { 259 if (mTime == null || t > mTime) { 260 mTime = t; 261 } 262 } 263 } 264 265 int evenCheck = Math.round(mTime.floatValue()); 266 if (evenCheck % 2 == 1) { 267 evenCheck = evenCheck + 1; 268 } 269 this.maxTime = evenCheck; 270 271 if (userSetMaxTime != null && userSetMaxTime > maxTime) { 272 this.maxTime = userSetMaxTime; 273 } 274 this.sfi = sfi; 275 if (sfi.getStrataInfoHashMap().size() == 1) { 276 return; 277 } 278 this.repaint(); 279 } 280 281 /** 282 * The data will set the max time which will result in off time points for 283 * tick marks 284 * 285 * @param title 286 * @param survivalData 287 * @param useWeighted 288 * @throws Exception 289 */ 290 public void setSurvivalData(ArrayList<String> title, LinkedHashMap<String, ArrayList<CensorStatus>> survivalData, Boolean useWeighted) throws Exception { 291 this.setSurvivalData(title, survivalData, null, useWeighted); 292 } 293 294 /** 295 * 296 * @param title 297 * @param survivalData 298 * @param userSetMaxTime 299 * @param useWeighted 300 * @throws Exception 301 */ 302 public void setSurvivalData(ArrayList<String> title, LinkedHashMap<String, ArrayList<CensorStatus>> survivalData, Double userSetMaxTime, Boolean useWeighted) throws Exception { 303 this.title = title; 304 this.survivalData = survivalData; 305 Double mTime = null; 306 ArrayList<String> labels = new ArrayList<String>(survivalData.keySet()); 307 Collections.sort(labels); 308 for (String legend : labels) { 309 ArrayList<CensorStatus> censorStatusList = survivalData.get(legend); 310 for (CensorStatus cs : censorStatusList) { 311 312 if (mTime == null || cs.time > mTime) { 313 mTime = cs.time; 314 } 315 } 316 } 317 318 int evenCheck = Math.round(mTime.floatValue()); 319 if (evenCheck % 2 == 1) { 320 evenCheck = evenCheck + 1; 321 } 322 this.maxTime = evenCheck; 323 324 if (userSetMaxTime != null && userSetMaxTime > maxTime) { 325 this.maxTime = userSetMaxTime; 326 } 327 328 //calculate percentages 329 SurvFitKM survFitKM = new SurvFitKM(); 330 sfi = survFitKM.process(survivalData, useWeighted); 331 this.repaint(); 332 } 333 334 /** 335 * Save data from survival curve to text file 336 * 337 * @param fileName 338 * @throws Exception 339 */ 340 public void saveSurvivalData(String fileName) throws Exception { 341 FileWriter fw = new FileWriter(fileName); 342 fw.write("index\tTIME\tSTATUS\tGROUP\r\n"); 343 int index = 0; 344 for (String group : survivalData.keySet()) { 345 ArrayList<CensorStatus> sd = survivalData.get(group); 346 for (CensorStatus cs : sd) { 347 String line = index + "\t" + cs.time + "\t" + cs.censored + "\t" + cs.group + "\r\n"; 348 index++; 349 fw.write(line); 350 } 351 } 352 fw.close(); 353 } 354 DecimalFormat df = new DecimalFormat("#.#"); 355 356 @Override 357 public void paintComponent(Graphics g) // draw graphics in the panel 358 { 359 int width = getWidth(); // width of window in pixels 360 int height = getHeight(); // height of window in pixels 361 setFigureDimensions(); 362 g.setColor(Color.white); 363 g.clearRect(0, 0, width, height); 364 365 super.paintComponent(g); // call superclass to make panel display correctly 366 367 drawLegend(g); 368 drawSurvivalCurves(g); 369 drawFigureLineInfo(g); 370 // Drawing code goes here 371 } 372 373 private void drawFigureLineInfo(Graphics g) { 374 Graphics2D g2 = (Graphics2D) g; 375 setRenderingHints(g2); 376 g2.setColor(Color.BLACK); 377 fm = getFontMetrics(getFont()); 378 int yoffset = fm.getHeight() * lineInfoList.size(); 379 380 int x = getTimeX(kmfi.figureLineInfoLowerPercentX * maxTime); 381 int y = getPercentageY(kmfi.figureLineInfoLowerPercentY) - yoffset; 382 383 for (String line : lineInfoList) { 384 g2.drawString(line, x, y); 385 y = y + fm.getHeight(); 386 } 387 388 } 389 390 private void drawSurvivalCurves(Graphics g) { 391 Graphics2D g2 = (Graphics2D) g; 392 setRenderingHints(g2); 393 g2.setStroke(kmfi.kmStroke); 394 395 396 int colorIndex = 0; 397 ArrayList<String> labels = new ArrayList<String>(sfi.getStrataInfoHashMap().keySet()); 398 Collections.sort(labels); 399 400 LinkedHashMap<String, StrataInfo> strataInfoHashMap = sfi.getStrataInfoHashMap(); 401 402 for (String legend : labels) { 403 StrataInfo si = strataInfoHashMap.get(legend); 404 g2.setColor(kmfi.legendColor[colorIndex]); 405 colorIndex++; 406 407 for (int i = 0; i < si.getSurv().size() - 1; i++) { 408 double p0time = si.getTime().get(i); 409 double p1time = si.getTime().get(i + 1); 410 double p0percentage = si.getSurv().get(i); 411 double p1percentage = si.getSurv().get(i + 1); 412 if (i == 0) { 413 g2.drawLine(getTimeX(0), getPercentageY(1), getTimeX(p0time), getPercentageY(1)); 414 g2.drawLine(getTimeX(p0time), getPercentageY(1), getTimeX(p0time), getPercentageY(p0percentage)); 415 } 416 g2.drawLine(getTimeX(p0time), getPercentageY(p0percentage), getTimeX(p1time), getPercentageY(p0percentage)); 417 418 g2.drawLine(getTimeX(p1time), getPercentageY(p0percentage), getTimeX(p1time), getPercentageY(p1percentage)); 419 // if (si.getStatus().get(i) == 0) { 420 if (i > 0 && si.getNcens().get(i) > 0) { 421 g2.drawLine(getTimeX(p0time), getPercentageY(p0percentage) - 4, getTimeX(p0time), getPercentageY(p0percentage) + 4); 422 g2.drawLine(getTimeX(p0time) - 4, getPercentageY(p0percentage), getTimeX(p0time) + 4, getPercentageY(p0percentage)); 423 } 424 } 425 426 427 } 428 429 String maxString = ""; 430 for (String legend : labels) { 431 if (legend.length() > maxString.length()) { 432 maxString = legend; 433 } 434 } 435 436 int offset = fm.stringWidth(maxString); 437 int x = getTimeX(kmfi.legendUpperPercentX * maxTime) - offset; 438 int y = getPercentageY(kmfi.legendUpperPercentY); 439 440 colorIndex = 0; 441 for (String legend : labels) { 442 g2.setColor(kmfi.legendColor[colorIndex]); 443 colorIndex++; 444 g2.drawLine(x - 20, y - (fm.getHeight() / 3), x - 5, y - (fm.getHeight() / 3)); 445 g2.drawString(legend, x, y); 446 y = y + fm.getHeight(); 447 } 448 449 450 } 451 452 /** 453 * Get the X coordinate based on a time value 454 * 455 * @param value 456 * @return 457 */ 458 private int getTimeX(double value) { 459 double d = left + (((right - left) * value) / (maxTime - minTime)); 460 return (int) d; 461 } 462 463 /** 464 * Get the Y coordinate based on percent value 0.0-1.0 465 * 466 * @param value 467 * @return 468 */ 469 private int getPercentageY(double value) { 470 value = 1.0 - value; 471 double d = top + (((bottom - top) * value) / (maxPercentage - minPercentage)); 472 return (int) d; 473 } 474 475 /** 476 * @return the fileName 477 */ 478 public String getFileName() { 479 return fileName; 480 } 481 482 /** 483 * @return the top 484 */ 485 public int getTop() { 486 return top; 487 } 488 489 /** 490 * @return the bottom 491 */ 492 public int getBottom() { 493 return bottom; 494 } 495 496 /** 497 * @return the left 498 */ 499 public int getLeft() { 500 return left; 501 } 502 503 /** 504 * @return the right 505 */ 506 public int getRight() { 507 return right; 508 } 509 510 /** 511 * @return the xAxisTimeValues 512 */ 513 public ArrayList<Double> getxAxisTimeValues() { 514 return xAxisTimeValues; 515 } 516 517 /** 518 * @return the xAxisTimeValues 519 */ 520 public ArrayList<Integer> getxAxisTimeCoordinates() { 521 return xAxisTimeCoordinates; 522 } 523 524 class PlotInfo { 525 526 double time; 527 double atRisk; 528 double censored; 529 double events; 530 double percentage; 531 532 @Override 533 public String toString() { 534 return time + "\t" + atRisk + "\t" + censored + "\t" + events + "\t" + (atRisk - events) + "\t" + percentage; 535 } 536 } 537 538 /** 539 * Do higher quality rendering options 540 * 541 * @param g 542 */ 543 private void setRenderingHints(Graphics2D g) { 544 RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 545 rh.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 546 rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); 547 rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 548 549 g.setRenderingHints(rh); 550 551 } 552 553 /** 554 * Setup the axis, labels etc 555 * 556 * @param g 557 */ 558 private void drawLegend(Graphics g) { 559 Graphics2D g2 = (Graphics2D) g; 560 setRenderingHints(g2); 561 g2.setColor(Color.BLACK); 562 Font font = g2.getFont(); 563 Font f = new Font(font.getFontName(), Font.BOLD, font.getSize()); 564 g2.setFont(f); 565 fm = getFontMetrics(f); 566 int fontHeight = fm.getHeight(); 567 for (int i = 0; i < title.size(); i++) { 568 if (fm.stringWidth(title.get(i)) > .8 * this.getWidth()) { 569 f = new Font(font.getFontName(), Font.BOLD, 10); 570 g2.setFont(f); 571 fm = getFontMetrics(f); 572 } 573 g2.drawString(title.get(i), (getSize().width - fm.stringWidth(title.get(i))) / 2, ((i + 1) * fontHeight)); 574 // g2.setFont(font); 575 } 576 // draw the maxPercentage and minPercentage values 577 String label = df.format(minPercentage); 578 g2.drawString(label, left - 5 - (fm.stringWidth(label)), bottom + titleHeight / 6); 579 g2.drawLine(left - 5, bottom, left, bottom); 580 double d = minPercentage + kmfi.yaxisPercentIncrement; 581 //double graphHeight = top - bottom; 582 583 while (d < maxPercentage) { 584 int yvalue = bottom - (int) (d * (bottom - top)); 585 label = df.format(d * 100); 586 g2.drawString(label, left - 5 - (fm.stringWidth(label)), yvalue + titleHeight / 6); // 587 588 g2.drawLine(left - 5, yvalue, left, yvalue); 589 d = d + kmfi.yaxisPercentIncrement; 590 } 591 592 label = df.format(maxPercentage * 100); 593 g2.drawString(label, left - 5 - (fm.stringWidth(label)), top + (titleHeight) / 6); 594 g2.drawLine(left - 5, top, left, top); 595 596 // Create a rotation transformation for the font. 597 AffineTransform fontAT = new AffineTransform(); 598 599 600 // Derive a new font using a rotatation transform 601 fontAT.rotate(270 * java.lang.Math.PI / 180); 602 Font theDerivedFont = f.deriveFont(fontAT); 603 604 // set the derived font in the Graphics2D context 605 g2.setFont(theDerivedFont); 606 607 // Render a string using the derived font 608 int yaxisHeight = fm.stringWidth(kmfi.yAxisLegend); 609 g2.drawString(kmfi.yAxisLegend, yaxisLabel, (bottom - (int) (.5 * (bottom - top))) + yaxisHeight / 2); 610 611 // put the original font back 612 g2.setFont(f); 613 614 615 616 double timeDistance = maxTime - minTime; 617 double timeIncrement = timeDistance * kmfi.xaxisPercentIncrement; 618 double timeInt = (int) Math.floor(timeIncrement); 619 if (timeInt < 1.0) { 620 timeInt = 1.0; 621 } 622 adjustedPercentIncrement = timeInt / timeDistance; 623 624 d = adjustedPercentIncrement; //kmfi.xaxisPercentIncrement; 625 xAxisTimeValues.clear(); 626 xAxisTimeCoordinates.clear(); 627 628 //if we don't have time values then use percentage to set time. Not perfect but allows different tics 629 if (kmfi.xAxisLabels.isEmpty()) { 630 xAxisTimeValues.add(minTime); 631 xAxisTimeCoordinates.add(left); 632 while (d <= 1.0) { 633 double xaxisTime = ((minTime * kmfi.timeScale) + d * ((maxTime - minTime) * kmfi.timeScale)); // 634 xAxisTimeValues.add(xaxisTime); 635 636 Integer coordinate = left + (int) (d * (right - left)); 637 xAxisTimeCoordinates.add(coordinate); 638 // System.out.println(d + " " + left + " " + right + " " + coordinate + " " + minTime + " " + maxTime); 639 d = d + adjustedPercentIncrement; //kmfi.xaxisPercentIncrement; 640 } 641 } else { 642 minTime = kmfi.xAxisLabels.get(0); 643 maxTime = kmfi.xAxisLabels.get(kmfi.xAxisLabels.size() - 1); 644 for (Double xaxisTime : kmfi.xAxisLabels) { 645 xAxisTimeValues.add(xaxisTime); 646 d = (xaxisTime - minTime) / (maxTime - minTime); 647 Integer coordinate = left + (int) (d * (right - left)); 648 xAxisTimeCoordinates.add(coordinate); 649 } 650 } 651 652 for (int i = 0; i < xAxisTimeValues.size(); i++) { 653 Double xaxisTime = xAxisTimeValues.get(i); 654 Integer xCoordinate = xAxisTimeCoordinates.get(i); 655 label = df.format(xaxisTime); 656 if (i == xAxisTimeValues.size() - 1) { 657 g2.drawString(label, xCoordinate - (fm.stringWidth(label)), bottom + fm.getHeight() + 5); 658 } else { 659 g2.drawString(label, xCoordinate - (fm.stringWidth(label) / 2), bottom + fm.getHeight() + 5); 660 } 661 g2.drawLine(xCoordinate, bottom, xCoordinate, bottom + 5); 662 } 663 664 // draw the vertical and horizontal lines 665 g2.setStroke(kmfi.axisStroke); 666 g2.drawLine(left, top, left, bottom); 667 g2.drawLine(left, bottom, right, bottom); 668 669 // draw xAxis legend 670 g2.drawString(kmfi.xAxisLegend, getSize().width / 2 - (fm.stringWidth(kmfi.xAxisLegend) / 2), bottom + 2 * fm.getHeight() + 10); 671 } 672 Double adjustedPercentIncrement = 0.0; 673 674 /** 675 * Get the percentage increment for the time axis 676 * 677 * @return 678 */ 679 public Double getTimeAxisIncrementPercentage() { 680 return adjustedPercentIncrement; 681 } 682 683 /** 684 * Reset the various bounds used to draw graph 685 */ 686 private void setFigureDimensions() { 687 fm = getFontMetrics(getFont()); 688 titleHeight = kmfi.titleHeight;//fm.getHeight(); 689 xAxisLabelHeight = titleHeight; 690 labelWidth = Math.max(fm.stringWidth(df.format(minPercentage)), 691 fm.stringWidth(df.format(maxPercentage))) + 5; 692 top = kmfi.padding + titleHeight; 693 bottom = this.getHeight() - kmfi.padding - xAxisLabelHeight; 694 left = kmfi.padding + labelWidth + yaxisLabel; 695 right = this.getWidth() - kmfi.padding; 696 697 } 698 699 /** 700 * Combine the KM and Num risk into one image 701 * 702 * @param fileName 703 */ 704 public void savePNGKMNumRisk(String fileName) { 705 if (fileName.startsWith("null") || fileName.startsWith("Null") || fileName.startsWith("NULL")) { 706 return; 707 } 708 this.fileName = fileName; 709 710 NumbersAtRiskPanel numbersAtRiskPanel = new NumbersAtRiskPanel(); 711 numbersAtRiskPanel.setKaplanMeierFigure(this); 712 numbersAtRiskPanel.setSize(this.getWidth(), numbersAtRiskPanel.getHeight()); 713 BufferedImage imageKM = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB); 714 Graphics2D graphics2D = imageKM.createGraphics(); 715 716 this.paint(graphics2D); 717 718 BufferedImage imageNumRisk = new BufferedImage(numbersAtRiskPanel.getWidth(), numbersAtRiskPanel.getHeight(), BufferedImage.TYPE_INT_RGB); 719 Graphics2D graphics2DNumRisk = imageNumRisk.createGraphics(); 720 numbersAtRiskPanel.paint(graphics2DNumRisk); 721 722 723 BufferedImage image = new BufferedImage(numbersAtRiskPanel.getWidth(), numbersAtRiskPanel.getHeight() + this.getHeight(), BufferedImage.TYPE_INT_RGB); 724 Graphics2D g = image.createGraphics(); 725 726 g.drawImage(imageKM, 0, 0, null); 727 g.drawImage(imageNumRisk, 0, this.getHeight(), null); 728 729 try { 730 ImageIO.write(image, "png", new File(fileName)); 731 } catch (Exception ex) { 732 ex.printStackTrace(); 733 } 734 735 } 736 737 /** 738 * 739 * @param fileName 740 */ 741 public void savePNG(String fileName) { 742 if (fileName.startsWith("null") || fileName.startsWith("Null") || fileName.startsWith("NULL")) { 743 return; 744 } 745 this.fileName = fileName; 746 BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB); 747 Graphics2D graphics2D = image.createGraphics(); 748 749 this.paint(graphics2D); 750 try { 751 ImageIO.write(image, "png", new File(fileName)); 752 } catch (Exception ex) { 753 ex.printStackTrace(); 754 } 755 756 } 757 758 /** 759 * @param args the command line arguments 760 */ 761 public static void main(String[] args) { 762 // TODO code application logic here 763 try { 764 765 KaplanMeierFigure kaplanMeierFigure = new KaplanMeierFigure(); 766 LinkedHashMap<String, ArrayList<CensorStatus>> survivalDataHashMap = new LinkedHashMap<String, ArrayList<CensorStatus>>(); 767 768// if (false) { //http://sph.bu.edu/otlt/MPH-Modules/BS/BS704_Survival/ 769// ArrayList<CensorStatus> graph1 = new ArrayList<CensorStatus>(); 770// graph1.add(new CensorStatus("A", 24.0, "0")); 771// graph1.add(new CensorStatus("A", 3.0, "1")); 772// graph1.add(new CensorStatus("A", 11.0, "0")); 773// graph1.add(new CensorStatus("A", 19.0, "0")); 774// graph1.add(new CensorStatus("A", 24.0, "0")); 775// graph1.add(new CensorStatus("A", 13.0, "0")); 776// 777// graph1.add(new CensorStatus("A", 14.0, "1")); 778// graph1.add(new CensorStatus("A", 2.0, "0")); 779// graph1.add(new CensorStatus("A", 18.0, "0")); 780// graph1.add(new CensorStatus("A", 17.0, "0")); 781// graph1.add(new CensorStatus("A", 24.0, "0")); 782// graph1.add(new CensorStatus("A", 21.0, "0")); 783// graph1.add(new CensorStatus("A", 12.0, "0")); 784// 785// graph1.add(new CensorStatus("A", 1.0, "1")); 786// graph1.add(new CensorStatus("A", 10.0, "0")); 787// graph1.add(new CensorStatus("A", 23.0, "1")); 788// graph1.add(new CensorStatus("A", 6.0, "0")); 789// graph1.add(new CensorStatus("A", 5.0, "1")); 790// graph1.add(new CensorStatus("A", 9.0, "0")); 791// graph1.add(new CensorStatus("A", 17.0, "1")); 792// 793// survivalDataHashMap.put("Label 1", graph1); 794// 795// 796// 797// } 798 799 800 if (true) { 801 802 803 804 ArrayList<CensorStatus> graph1 = new ArrayList<CensorStatus>(); 805 graph1.add(new CensorStatus("A", 1.0, "1")); 806 graph1.add(new CensorStatus("A", 1.0, "1")); 807 graph1.add(new CensorStatus("A", 1.0, "1")); 808 graph1.add(new CensorStatus("A", 2.0, "1")); 809 graph1.add(new CensorStatus("A", 2.0, "1")); 810 graph1.add(new CensorStatus("A", 3.0, "1")); 811 812 graph1.add(new CensorStatus("A", 4.0, "1")); 813 graph1.add(new CensorStatus("A", 4.0, "1")); 814 graph1.add(new CensorStatus("A", 4.0, "1")); 815 graph1.add(new CensorStatus("A", 4.0, "1")); 816 graph1.add(new CensorStatus("A", 4.0, "1")); 817 graph1.add(new CensorStatus("A", 4.0, "1")); 818 graph1.add(new CensorStatus("A", 4.0, "0")); 819 820 graph1.add(new CensorStatus("A", 5.0, "1")); 821 graph1.add(new CensorStatus("A", 5.0, "1")); 822 823 graph1.add(new CensorStatus("A", 8.0, "0")); 824 graph1.add(new CensorStatus("A", 8.0, "0")); 825 graph1.add(new CensorStatus("A", 8.0, "0")); 826 graph1.add(new CensorStatus("A", 8.0, "0")); 827 graph1.add(new CensorStatus("A", 8.0, "0")); 828 graph1.add(new CensorStatus("A", 8.0, "0")); 829 graph1.add(new CensorStatus("A", 8.0, "1")); 830 831 graph1.add(new CensorStatus("A", 9.0, "1")); 832 graph1.add(new CensorStatus("A", 9.0, "1")); 833 graph1.add(new CensorStatus("A", 9.0, "1")); 834 graph1.add(new CensorStatus("A", 9.0, "1")); 835 graph1.add(new CensorStatus("A", 9.0, "1")); 836 837 838 graph1.add(new CensorStatus("A", 13.0, "0")); 839 graph1.add(new CensorStatus("A", 13.0, "0")); 840 graph1.add(new CensorStatus("A", 13.0, "1")); 841 842 survivalDataHashMap.put("Label 1", graph1); 843 844 ArrayList<CensorStatus> graph2 = new ArrayList<CensorStatus>(); 845 graph2.add(new CensorStatus("A", 1.0, "1")); 846 graph2.add(new CensorStatus("A", 1.0, "1")); 847 graph2.add(new CensorStatus("A", 1.0, "0")); 848 graph2.add(new CensorStatus("A", 3.0, "0")); 849 graph2.add(new CensorStatus("A", 3.0, "1")); 850 graph2.add(new CensorStatus("A", 4.0, "1")); 851 852 graph2.add(new CensorStatus("A", 4.0, "1")); 853 graph2.add(new CensorStatus("A", 4.0, "1")); 854 graph2.add(new CensorStatus("A", 4.0, "1")); 855 graph2.add(new CensorStatus("A", 5.0, "1")); 856 graph2.add(new CensorStatus("A", 5.0, "0")); 857 graph2.add(new CensorStatus("A", 5.0, "0")); 858 graph2.add(new CensorStatus("A", 5.0, "0")); 859 860 graph2.add(new CensorStatus("A", 6.0, "1")); 861 graph2.add(new CensorStatus("A", 6.0, "0")); 862 863 graph2.add(new CensorStatus("A", 7.0, "0")); 864 graph2.add(new CensorStatus("A", 7.0, "0")); 865 graph2.add(new CensorStatus("A", 7.0, "0")); 866 graph2.add(new CensorStatus("A", 7.0, "0")); 867 graph2.add(new CensorStatus("A", 8.0, "1")); 868 graph2.add(new CensorStatus("A", 8.0, "1")); 869 graph2.add(new CensorStatus("A", 8.0, "1")); 870 871 graph2.add(new CensorStatus("A", 8.0, "1")); 872 graph2.add(new CensorStatus("A", 8.0, "1")); 873 graph2.add(new CensorStatus("A", 8.0, "0")); 874 graph2.add(new CensorStatus("A", 9.0, "0")); 875 graph2.add(new CensorStatus("A", 9.0, "1")); 876 877 878 graph2.add(new CensorStatus("A", 10.0, "0")); 879 graph2.add(new CensorStatus("A", 10.0, "0")); 880 graph2.add(new CensorStatus("A", 10.0, "0")); 881 882 survivalDataHashMap.put("Label 2", graph2); 883 } 884 885 ArrayList<String> figureInfo = new ArrayList<String>(); 886 //DecimalFormat dfe = new DecimalFormat("0.00E0"); 887 //DecimalFormat df = new DecimalFormat("0.00"); 888 889 890 891 JFrame application = new JFrame(); 892 application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 893 application.add(kaplanMeierFigure); 894 kaplanMeierFigure.setSize(500, 400); 895 896 application.setSize(500, 400); // window is 500 pixels wide, 400 high 897 application.setVisible(true); 898 899 ArrayList<String> titles = new ArrayList<String>(); 900 titles.add("Line 1"); 901 titles.add("Line 2"); 902 kaplanMeierFigure.setSurvivalData(titles, survivalDataHashMap, true); 903 904 // figureInfo.add("HR=2.1 95% CI(1.8-2.5)"); 905 // figureInfo.add("p-value=.001"); 906 kaplanMeierFigure.setFigureLineInfo(figureInfo); 907 908 kaplanMeierFigure.savePNGKMNumRisk("test.png"); 909 910 } catch (Exception e) { 911 e.printStackTrace(); 912 } 913 } 914}