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.apache.commons.math.stat.descriptive.DescriptiveStatistics; 024import org.biojava.nbio.survival.cox.SurvivalInfo; 025import org.biojava.nbio.survival.cox.comparators.SurvivalInfoValueComparator; 026 027import javax.imageio.ImageIO; 028import javax.swing.*; 029import java.awt.*; 030import java.awt.image.BufferedImage; 031import java.io.File; 032import java.text.DecimalFormat; 033import java.util.ArrayList; 034import java.util.Collections; 035 036/** 037 * 038 * @author Scooter Willis <willishf at gmail dot com> 039 */ 040public class ExpressionFigure extends JPanel { 041 042 private static final long serialVersionUID = 1L; 043 044 ArrayList<String> title = new ArrayList<String>(); 045 /** 046 * 047 */ 048 public int top; 049 /** 050 * 051 */ 052 public int bottom; 053 /** 054 * 055 */ 056 public int left; 057 /** 058 * 059 */ 060 public int right; 061 int titleHeight; 062 int xAxisLabelHeight; 063 int labelWidth; 064 Double maxTime = null; 065 Double minX = 0.0; 066 Double maxX = 10.0; 067 Double minY = 0.0; 068 Double maxY = 1.0; 069 Double mean = 0.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 ArrayList<SurvivalInfo> siList = new ArrayList<SurvivalInfo>(); 075 String variable = ""; 076 private String fileName = ""; 077 078 /** 079 * 080 */ 081 public ExpressionFigure() { 082 super(); 083 setSize(500, 400); 084 setBackground(Color.WHITE); 085 } 086 087 /** 088 * The data used to draw the graph 089 * @return 090 */ 091 092 public ArrayList<SurvivalInfo> getSurvivalInfoList(){ 093 return siList; 094 } 095 096 /** 097 * 098 * @param kmfi 099 */ 100 public void setKMFigureInfo(KMFigureInfo kmfi) { 101 this.kmfi = kmfi; 102 if (kmfi.width != null && kmfi.height != null) { 103 this.setSize(kmfi.width, kmfi.height); 104 } 105 } 106 107 /** 108 * 109 * @param lineInfoList 110 */ 111 public void setFigureLineInfo(ArrayList<String> lineInfoList) { 112 this.lineInfoList = lineInfoList; 113 this.repaint(); 114 } 115 116 /** 117 * 118 * @param title 119 * @param _siList 120 * @param variable 121 */ 122 public void setSurvivalInfo(ArrayList<String> title, ArrayList<SurvivalInfo> _siList, String variable) { 123 this.siList = new ArrayList<SurvivalInfo>(); 124 this.title = title; 125 this.variable = variable; 126 127 minX = 0.0; 128 maxX = (double) _siList.size(); 129 minY = 0.0; 130 maxY = null; 131 DescriptiveStatistics ds = new DescriptiveStatistics(); 132 for (SurvivalInfo si : _siList) { 133 this.siList.add(si); 134 String v = si.getOriginalMetaData(variable); 135 Double value = Double.parseDouble(v); 136 ds.addValue(value); 137 if (maxTime == null || maxTime < si.getTime()) { 138 maxTime = si.getTime(); 139 } 140 141 } 142 SurvivalInfoValueComparator sivc = new SurvivalInfoValueComparator(variable); 143 Collections.sort(this.siList, sivc); 144 mean = ds.getMean(); 145 minY = ds.getMin(); 146 maxY = ds.getMax(); 147 minY = (double) Math.floor(minY); 148 maxY = (double) Math.ceil(maxY); 149 150 151 this.repaint(); 152 } 153 DecimalFormat df = new DecimalFormat("#.#"); 154 155 private void setRenderingHints(Graphics2D g) { 156 RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 157 rh.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 158 rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); 159 rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 160 161 g.setRenderingHints(rh); 162 163 } 164 165 @Override 166 public void paintComponent(Graphics g) // draw graphics in the panel 167 { 168 //int width = getWidth(); // width of window in pixels 169 //int height = getHeight(); // height of window in pixels 170 setFigureDimensions(); 171 super.paintComponent(g); // call superclass to make panel display correctly 172 Graphics2D g2 = (Graphics2D)g; 173 setRenderingHints(g2); 174 drawExpressionLevels(g); 175 drawFigureLineInfo(g); 176 drawLegend(g); 177 // Drawing code goes here 178 } 179 180 private void drawFigureLineInfo(Graphics g) { 181 g.setColor(Color.BLACK); 182 Font font = g.getFont(); 183 Font f = new Font(font.getFontName(), Font.BOLD, font.getSize()); 184 g.setFont(f); 185 fm = getFontMetrics(getFont()); 186 int yoffset = fm.getHeight() * lineInfoList.size(); 187 188 int x = getX(kmfi.figureLineInfoLowerPercentX * maxX); 189 int y = getY(kmfi.figureLineInfoLowerPercentY) - yoffset; 190 191 for (String line : lineInfoList) { 192 g.drawString(line, x, y); 193 y = y + fm.getHeight(); 194 } 195 196 } 197 198 private void drawExpressionLevels(Graphics g) { 199 Graphics2D g2 = (Graphics2D) g; 200 g2.setStroke(kmfi.kmStroke); 201 g2.setColor(Color.blue); 202 Double py = null; 203 for (int x = 0; x < siList.size(); x++) { 204 SurvivalInfo si = siList.get(x); 205 String v = si.getOriginalMetaData(variable); 206 Double y = Double.parseDouble(v); 207 if (si.getStatus() == 1) { 208 g2.setColor(Color.RED); 209 } else { 210 g2.setColor(Color.LIGHT_GRAY); 211 } 212 g2.drawLine(getX(x), getY((maxY - minY)), getX(x), getY(maxY - y)); 213 214 if (py == null) { 215 py = y; 216 } 217 if (mean >= py && mean <= y) { 218 g2.setColor(Color.green); 219 g2.drawLine(getX(x), getY(maxY - minY), getX(x), getY(maxY - y)); 220 g2.drawLine(getX(x - 1), getY(maxY - minY), getX(x - 1), getY(maxY - y)); 221 } 222 py = y; 223 224 // g2.setColor(Color.black); 225 // double yt = getYFromPercentage(1.0 - ((double)x)/((double)siList.size()) ); 226 // g2.drawOval(getX(x) - 2, ((int)yt) - 2, 4, 4); 227 } 228 229 } 230 231// private int getYFromPercentage(double percentage) { 232// double d = top + (((bottom - top) * percentage)); 233// return (int) d; 234// } 235 236 private int getX(double value) { 237 double d = left + (((right - left) * value) / (maxX - minX)); 238 return (int) d; 239 } 240 241 private int getY(double value) { 242 243 double d = top + (((bottom - top) * value) / (maxY - minY)); 244 return (int) d; 245 } 246 247 /** 248 * @return the fileName 249 */ 250 public String getFileName() { 251 return fileName; 252 } 253 254 private void drawLegend(Graphics g) { 255 Graphics2D g2 = (Graphics2D) g; 256 Font font = g2.getFont(); 257 258 font = new Font(font.getFontName(), Font.BOLD, font.getSize()); 259 g2.setFont(font); 260 fm = getFontMetrics(font); 261 int fontHeight = fm.getHeight(); 262 for (int i = 0; i < title.size(); i++) { 263 if (fm.stringWidth(title.get(i)) > .8 * this.getWidth()) { 264 265 Font f = new Font(font.getFontName(), Font.BOLD, 10); 266 g2.setFont(f); 267 fm = getFontMetrics(f); 268 } 269 g2.drawString(title.get(i), (getSize().width - fm.stringWidth(title.get(i))) / 2, ((i + 1) * fontHeight)); 270 g2.setFont(font); 271 } 272 // draw the maxY and minY values 273 g2.drawString(df.format(minY), left - fm.stringWidth(df.format(minY)) - 20, bottom + titleHeight / 6); 274 g2.drawLine(left - 5, bottom, left, bottom); 275 double ySize = maxY - minY; 276 double increment = kmfi.yaxisPercentIncrement * ySize; 277 increment = Math.ceil(increment); 278 // increment = increment * 10.0; 279 double d = minY + increment; 280 //double graphHeight = top - bottom; 281 String label = ""; 282 while (d < maxY) { 283 int yvalue = getY(maxY - d); 284 label = df.format(d); 285 g2.drawString(label, left - (fm.stringWidth(label)) - 20, yvalue + titleHeight / 6); // 286 287 g2.drawLine(left - 5, yvalue, left, yvalue); 288 d = d + (increment); 289 } 290 291 label = df.format(maxY); 292 g2.drawString(label, left - (fm.stringWidth(label)) - 20, top + (titleHeight) / 6); 293 g2.drawLine(left - 5, top, left, top); 294 295 double timeDistance = maxX - minX; 296 double timeIncrement = timeDistance * kmfi.xaxisPercentIncrement; 297 double timeInt = (int) timeIncrement; 298 if (timeInt < 1.0) { 299 timeInt = 1.0; 300 } 301 double adjustedPercentIncrement = timeInt / timeDistance; 302 303 d = adjustedPercentIncrement; //kmfi.xaxisPercentIncrement; 304 while (d <= 1.0) { 305 label = df.format((minX * kmfi.timeScale) + d * ((maxX - minX) * kmfi.timeScale)); // 306 if (d + adjustedPercentIncrement > 1.0) { //if this is the last one then adjust 307 g2.drawString(label, left + (int) (d * (right - left)) - (int) (.5 * fm.stringWidth(label)), bottom + fm.getHeight() + 5); 308 } else { 309 g2.drawString(label, left + (int) (d * (right - left)) - (fm.stringWidth(label) / 2), bottom + fm.getHeight() + 5); 310 } 311 g2.drawLine(left + (int) (d * (right - left)), bottom, left + (int) (d * (right - left)), bottom + 5); 312 d = d + adjustedPercentIncrement; //kmfi.xaxisPercentIncrement; 313 } 314 315 316 // draw the vertical and horizontal lines 317 g2.setStroke(kmfi.axisStroke); 318 g2.drawLine(left, top, left, bottom); 319 g2.drawLine(left, bottom, right, bottom); 320 } 321 322 private void setFigureDimensions() { 323 fm = getFontMetrics(getFont()); 324 titleHeight = kmfi.titleHeight;//fm.getHeight(); 325 xAxisLabelHeight = titleHeight; 326 labelWidth = Math.max(fm.stringWidth(df.format(minY)), 327 fm.stringWidth(df.format(maxY))) + 5; 328 top = kmfi.padding + titleHeight; 329 bottom = this.getHeight() - kmfi.padding - xAxisLabelHeight; 330 left = kmfi.padding + labelWidth; 331 right = this.getWidth() - kmfi.padding; 332 333 } 334 335 /** 336 * 337 * @param fileName 338 */ 339 public void savePNG(String fileName) { 340 if (fileName.startsWith("null")) { 341 return; 342 } 343 this.fileName = fileName; 344 BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB); 345 Graphics2D graphics2D = image.createGraphics(); 346 347 this.paint(graphics2D); 348 try { 349 ImageIO.write(image, "png", new File(fileName)); 350 } catch (Exception ex) { 351 ex.printStackTrace(); 352 } 353 354 } 355 356 /** 357 * @param args the command line arguments 358 */ 359 public static void main(String[] args) { 360 // TODO code application logic here 361 try { 362 363 ExpressionFigure expressionFigure = new ExpressionFigure(); 364 365 366 367 JFrame application = new JFrame(); 368 application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 369 application.add(expressionFigure); 370 expressionFigure.setSize(500, 400); 371 372 application.setSize(500, 400); // window is 500 pixels wide, 400 high 373 application.setVisible(true); 374 375 ArrayList<String> titles = new ArrayList<String>(); 376 titles.add("Line 1"); 377 titles.add("line 2"); 378 379 ArrayList<String> figureInfo = new ArrayList<String>(); 380 381 ArrayList<SurvivalInfo> survivalInfoList = new ArrayList<SurvivalInfo>(); 382 383 for (int i = 0; i < 600; i++) { 384 double r = Math.random(); 385 double v = r * 10000; 386 double t = Math.random() * 5.0; 387 r = Math.random(); 388 int e = 0; 389 if (r < .3) { 390 e = 1; 391 } 392 SurvivalInfo si = new SurvivalInfo(t, e); 393 si.addContinuousVariable("META_GENE", v); 394 survivalInfoList.add(si); 395 396 } 397 398 399 expressionFigure.setSurvivalInfo(titles, survivalInfoList, "META_GENE"); 400 401 expressionFigure.setFigureLineInfo(figureInfo); 402 403 expressionFigure.savePNG("/Users/Scooter/Downloads/test.png"); 404 405 } catch (Exception e) { 406 e.printStackTrace(); 407 } 408 } 409}