1 42 43 package org.jfree.experimental.chart.axis; 44 45 import java.awt.Graphics2D ; 46 import java.awt.geom.Rectangle2D ; 47 import java.text.NumberFormat ; 48 import java.util.ArrayList ; 49 import java.util.List ; 50 51 import org.jfree.chart.axis.AxisState; 52 import org.jfree.chart.axis.LogarithmicAxis; 53 import org.jfree.chart.axis.NumberAxis; 54 import org.jfree.chart.axis.NumberTick; 55 import org.jfree.chart.axis.NumberTickUnit; 56 import org.jfree.chart.axis.ValueAxis; 57 import org.jfree.chart.event.AxisChangeEvent; 58 import org.jfree.chart.plot.Plot; 59 import org.jfree.chart.plot.PlotRenderingInfo; 60 import org.jfree.chart.plot.ValueAxisPlot; 61 import org.jfree.data.Range; 62 import org.jfree.ui.RectangleEdge; 63 import org.jfree.ui.TextAnchor; 64 65 73 74 79 public class LogAxis extends ValueAxis { 80 81 82 public static final double DEFAULT_LOWER_BOUND = 0.01; 83 84 85 private double base = 10.0; 86 87 88 private double baseLog = Math.log(10.0); 89 90 91 private double smallestValue = 1E-100; 92 93 94 private NumberTickUnit tickUnit; 95 96 97 private NumberFormat numberFormatOverride; 98 99 100 private int minorTickCount; 101 102 105 public LogAxis() { 106 this(null); 107 } 108 109 114 public LogAxis(String label) { 115 super(label, NumberAxis.createIntegerTickUnits()); 116 this.tickUnit = new NumberTickUnit(1.0); 117 this.minorTickCount = 10; 118 this.setTickMarksVisible(false); 119 } 120 121 126 public double getBase() { 127 return this.base; 128 } 129 130 136 public void setBase(double base) { 137 if (base <= 1.0) { 138 throw new IllegalArgumentException ("Requires 'base' > 1.0."); 139 } 140 this.base = base; 141 this.baseLog = Math.log(base); 142 notifyListeners(new AxisChangeEvent(this)); 143 } 144 145 150 public double getSmallestValue() { 151 return this.smallestValue; 152 } 153 154 159 public void setSmallestValue(double value) { 160 if (value <= 0.0) { 161 throw new IllegalArgumentException ("Requires 'value' > 0.0."); 162 } 163 this.smallestValue = value; 164 } 165 166 171 public NumberTickUnit getTickUnit() { 172 return this.tickUnit; 173 } 174 175 184 public void setTickUnit(NumberTickUnit unit) { 185 setTickUnit(unit, true, true); 187 } 188 189 200 public void setTickUnit(NumberTickUnit unit, boolean notify, 201 boolean turnOffAutoSelect) { 202 203 if (unit == null) { 204 throw new IllegalArgumentException ("Null 'unit' argument."); 205 } 206 this.tickUnit = unit; 207 if (turnOffAutoSelect) { 208 setAutoTickUnitSelection(false, false); 209 } 210 if (notify) { 211 notifyListeners(new AxisChangeEvent(this)); 212 } 213 214 } 215 216 222 public NumberFormat getNumberFormatOverride() { 223 return this.numberFormatOverride; 224 } 225 226 232 public void setNumberFormatOverride(NumberFormat formatter) { 233 this.numberFormatOverride = formatter; 234 notifyListeners(new AxisChangeEvent(this)); 235 } 236 237 242 public int getMinorTickCount() { 243 return this.minorTickCount; 244 } 245 246 251 public void setMinorTickCount(int count) { 252 if (count <= 0) { 253 throw new IllegalArgumentException ("Requires 'count' > 0."); 254 } 255 this.minorTickCount = count; 256 notifyListeners(new AxisChangeEvent(this)); 257 } 258 259 268 public double calculateLog(double value) { 269 return Math.log(value) / this.baseLog; 270 } 271 272 279 public double calculateValue(double log) { 280 return Math.pow(this.base, log); 281 } 282 283 293 public double java2DToValue(double java2DValue, Rectangle2D area, 294 RectangleEdge edge) { 295 296 Range range = getRange(); 297 double axisMin = calculateLog(range.getLowerBound()); 298 double axisMax = calculateLog(range.getUpperBound()); 299 300 double min = 0.0; 301 double max = 0.0; 302 if (RectangleEdge.isTopOrBottom(edge)) { 303 min = area.getX(); 304 max = area.getMaxX(); 305 } 306 else if (RectangleEdge.isLeftOrRight(edge)) { 307 min = area.getMaxY(); 308 max = area.getY(); 309 } 310 double log = 0.0; 311 if (isInverted()) { 312 log = axisMax - (java2DValue - min) / (max - min) 313 * (axisMax - axisMin); 314 } 315 else { 316 log = axisMin + (java2DValue - min) / (max - min) 317 * (axisMax - axisMin); 318 } 319 return calculateValue(log); 320 } 321 322 333 public double valueToJava2D(double value, Rectangle2D area, 334 RectangleEdge edge) { 335 336 Range range = getRange(); 337 double axisMin = calculateLog(range.getLowerBound()); 338 double axisMax = calculateLog(range.getUpperBound()); 339 value = calculateLog(value); 340 341 double min = 0.0; 342 double max = 0.0; 343 if (RectangleEdge.isTopOrBottom(edge)) { 344 min = area.getX(); 345 max = area.getMaxX(); 346 } 347 else if (RectangleEdge.isLeftOrRight(edge)) { 348 max = area.getMinY(); 349 min = area.getMaxY(); 350 } 351 if (isInverted()) { 352 return max 353 - ((value - axisMin) / (axisMax - axisMin)) * (max - min); 354 } 355 else { 356 return min 357 + ((value - axisMin) / (axisMax - axisMin)) * (max - min); 358 } 359 } 360 361 365 public void configure() { 366 if (isAutoRange()) { 367 autoAdjustRange(); 368 } 369 } 370 371 375 protected void autoAdjustRange() { 376 Plot plot = getPlot(); 377 if (plot == null) { 378 return; } 380 381 if (plot instanceof ValueAxisPlot) { 382 ValueAxisPlot vap = (ValueAxisPlot) plot; 383 384 Range r = vap.getDataRange(this); 385 if (r == null) { 386 r = new Range(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND); 387 } 388 389 double upper = r.getUpperBound(); 390 double lower = r.getLowerBound(); 391 double range = upper - lower; 392 393 double fixedAutoRange = getFixedAutoRange(); 395 if (fixedAutoRange > 0.0) { 396 lower = Math.max(upper - fixedAutoRange, this.smallestValue); 397 } 398 else { 399 double minRange = getAutoRangeMinimumSize(); 401 if (range < minRange) { 402 double expand = (minRange - range) / 2; 403 upper = upper + expand; 404 lower = lower - expand; 405 } 406 407 } 411 412 setRange(new Range(lower, upper), false, false); 413 } 414 415 } 416 417 431 public AxisState draw(Graphics2D g2, double cursor, Rectangle2D plotArea, 432 Rectangle2D dataArea, RectangleEdge edge, 433 PlotRenderingInfo plotState) { 434 435 AxisState state = null; 436 if (!isVisible()) { 438 state = new AxisState(cursor); 439 List ticks = refreshTicks(g2, state, dataArea, edge); 442 state.setTicks(ticks); 443 return state; 444 } 445 state = drawTickMarksAndLabels(g2, cursor, plotArea, dataArea, edge); 446 state = drawLabel(getLabel(), g2, plotArea, dataArea, edge, state); 447 return state; 448 } 449 450 462 public List refreshTicks(Graphics2D g2, AxisState state, 463 Rectangle2D dataArea, RectangleEdge edge) { 464 465 List result = new java.util.ArrayList (); 466 if (RectangleEdge.isTopOrBottom(edge)) { 467 result = refreshTicksHorizontal(g2, dataArea, edge); 468 } 469 else if (RectangleEdge.isLeftOrRight(edge)) { 470 result = refreshTicksVertical(g2, dataArea, edge); 471 } 472 return result; 473 474 } 475 476 485 protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, 486 RectangleEdge edge) { 487 Range range = getRange(); 488 List ticks = new ArrayList (); 489 double start = Math.floor(calculateLog(getLowerBound())); 490 double end = Math.ceil(calculateLog(getUpperBound())); 491 double current = start; 492 while (current <= end) { 493 double v = calculateValue(current); 494 if (range.contains(v)) { 495 ticks.add(new NumberTick(new Double (v), createTickLabel(v), 496 TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); 497 } 498 double next = Math.pow(this.base, current 500 + this.tickUnit.getSize()); 501 for (int i = 1; i < this.minorTickCount; i++) { 502 double minorV = v + i * ((next - v) / this.minorTickCount); 503 if (range.contains(minorV)) { 504 ticks.add(new NumberTick(new Double (minorV), 505 "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); 506 } 507 } 508 current = current + this.tickUnit.getSize(); 509 } 510 return ticks; 511 } 512 513 522 protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, 523 RectangleEdge edge) { 524 Range range = getRange(); 525 List ticks = new ArrayList (); 526 double start = Math.floor(calculateLog(getLowerBound())); 527 double end = Math.ceil(calculateLog(getUpperBound())); 528 double current = start; 529 while (current <= end) { 530 double v = calculateValue(current); 531 if (range.contains(v)) { 532 ticks.add(new NumberTick(new Double (v), createTickLabel(v), 533 TextAnchor.CENTER_RIGHT, TextAnchor.CENTER, 0.0)); 534 } 535 double next = Math.pow(this.base, current 537 + this.tickUnit.getSize()); 538 for (int i = 1; i < this.minorTickCount; i++) { 539 double minorV = v + i * ((next - v) / this.minorTickCount); 540 if (range.contains(minorV)) { 541 ticks.add(new NumberTick(new Double (minorV), "", 542 TextAnchor.CENTER_RIGHT, TextAnchor.CENTER, 0.0)); 543 } 544 } 545 current = current + this.tickUnit.getSize(); 546 } 547 return ticks; 548 } 549 550 557 private String createTickLabel(double value) { 558 if (this.numberFormatOverride != null) { 559 return this.numberFormatOverride.format(value); 560 } 561 else { 562 return this.tickUnit.valueToString(value); 563 } 564 } 565 566 } 567 | Popular Tags |