📄 logarithmicaxis.java
字号:
* not less than the argument, is equal to a mathematical integer and * satisfying the condition that log base 10 of the value is an integer * (i.e., the value returned will be a power of 10: 1, 10, 100, 1000, etc.). * * @param upper a double value above which a ceiling will be calcualted. * * @return 10<sup>N</sup> with N .. { 1 ... } */ protected double computeLogCeil(double upper) { double logCeil; if (this.allowNegativesFlag) { //negative values are allowed if (upper > 10.0) { //parameter value is > 10 // The Math.log() function is based on e not 10. logCeil = Math.log(upper) / LOG10_VALUE; logCeil = Math.ceil(logCeil); logCeil = Math.pow(10, logCeil); } else if (upper < -10.0) { //parameter value is < -10 //calculate log using positive value: logCeil = Math.log(-upper) / LOG10_VALUE; //calculate ceil using negative value: logCeil = Math.ceil(-logCeil); //calculate power using positive value; then negate logCeil = -Math.pow(10, -logCeil); } else { //parameter value is -10 > val < 10 logCeil = Math.ceil(upper); //use as-is } } else { //negative values not allowed if (upper > 0.0) { //parameter value is > 0 // The Math.log() function is based on e not 10. logCeil = Math.log(upper) / LOG10_VALUE; logCeil = Math.ceil(logCeil); logCeil = Math.pow(10, logCeil); } else { //parameter value is <= 0 logCeil = Math.ceil(upper); //use as-is } } return logCeil; } /** * Rescales the axis to ensure that all data is visible. */ public void autoAdjustRange() { Plot plot = getPlot(); if (plot == null) { return; // no plot, no data. } if (plot instanceof ValueAxisPlot) { ValueAxisPlot vap = (ValueAxisPlot) plot; double lower; Range r = vap.getDataRange(this); if (r == null) { //no real data present r = new Range(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND); lower = r.getLowerBound(); //get lower bound value } else { //actual data is present lower = r.getLowerBound(); //get lower bound value if (this.strictValuesFlag && !this.allowNegativesFlag && lower <= 0.0) { //strict flag set, allow-negatives not set and values <= 0 throw new RuntimeException("Values less than or equal to " + "zero not allowed with logarithmic axis"); } } //change to log version of lowest value to make range // begin at a 10^n value: lower = computeLogFloor(lower); if (!this.allowNegativesFlag && lower >= 0.0 && lower < SMALL_LOG_VALUE) { //negatives not allowed and lower range bound is zero lower = r.getLowerBound(); //use data range bound instead } double upper = r.getUpperBound(); if (!this.allowNegativesFlag && upper < 1.0 && upper > 0.0 && lower > 0.0) { //negatives not allowed and upper bound between 0 & 1 //round up to nearest significant digit for bound: //get negative exponent: double expVal = Math.log(upper) / LOG10_VALUE; expVal = Math.ceil(-expVal + 0.001); //get positive exponent expVal = Math.pow(10, expVal); //create multiplier value //multiply, round up, and divide for bound value: upper = (expVal > 0.0) ? Math.ceil(upper * expVal) / expVal : Math.ceil(upper); } else { //negatives allowed or upper bound not between 0 & 1 upper = computeLogCeil(upper); //use nearest log value } // ensure the autorange is at least <minRange> in size... double minRange = getAutoRangeMinimumSize(); if (upper - lower < minRange) { upper = (upper + lower + minRange) / 2; lower = (upper + lower - minRange) / 2; //if autorange still below minimum then adjust by 1% // (can be needed when minRange is very small): if (upper - lower < minRange) { final double absUpper = Math.abs(upper); //need to account for case where upper==0.0 final double adjVal = (absUpper > SMALL_LOG_VALUE) ? absUpper / 100.0 : 0.01; upper = (upper + lower + adjVal) / 2; lower = (upper + lower - adjVal) / 2; } } setRange(new Range(lower, upper), false, false); setupSmallLogFlag(); //setup flag based on bounds values } } /** * Converts a data value to a coordinate in Java2D space, assuming that * the axis runs along one edge of the specified plotArea. * Note that it is possible for the coordinate to fall outside the * plotArea. * * @param value the data value. * @param plotArea the area for plotting the data. * @param edge the axis location. * * @return the Java2D coordinate. */ public double valueToJava2D(double value, Rectangle2D plotArea, RectangleEdge edge) { Range range = getRange(); double axisMin = switchedLog10(range.getLowerBound()); double axisMax = switchedLog10(range.getUpperBound()); double min = 0.0; double max = 0.0; if (RectangleEdge.isTopOrBottom(edge)) { min = plotArea.getMinX(); max = plotArea.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { min = plotArea.getMaxY(); max = plotArea.getMinY(); } value = switchedLog10(value); if (isInverted()) { return max - (((value - axisMin) / (axisMax - axisMin)) * (max - min)); } else { return min + (((value - axisMin) / (axisMax - axisMin)) * (max - min)); } } /** * Converts a coordinate in Java2D space to the corresponding data * value, assuming that the axis runs along one edge of the specified plotArea. * * @param java2DValue the coordinate in Java2D space. * @param plotArea the area in which the data is plotted. * @param edge the axis location. * * @return the data value. */ public double java2DToValue(double java2DValue, Rectangle2D plotArea, RectangleEdge edge) { Range range = getRange(); double axisMin = switchedLog10(range.getLowerBound()); double axisMax = switchedLog10(range.getUpperBound()); double plotMin = 0.0; double plotMax = 0.0; if (RectangleEdge.isTopOrBottom(edge)) { plotMin = plotArea.getX(); plotMax = plotArea.getMaxX(); } else if (RectangleEdge.isLeftOrRight(edge)) { plotMin = plotArea.getMaxY(); plotMax = plotArea.getMinY(); } if (isInverted()) { return Math.pow( 10, axisMax - ((java2DValue - plotMin) / (plotMax - plotMin)) * (axisMax - axisMin) ); } else { return Math.pow( 10, axisMin + ((java2DValue - plotMin) / (plotMax - plotMin)) * (axisMax - axisMin) ); } } /** * Calculates the positions of the tick labels for the axis, storing the results in the * tick label list (ready for drawing). * * @param g2 the graphics device. * @param state the axis state. * @param drawArea the area in which the plot and the axes should be drawn. * @param dataArea the area in which the plot should be drawn. * @param edge the location of the axis. * * @return a list of ticks. */ public List refreshTicks(Graphics2D g2, AxisState state, Rectangle2D drawArea, Rectangle2D dataArea, RectangleEdge edge) { List ticks = new java.util.ArrayList(); if (RectangleEdge.isTopOrBottom(edge)) { ticks = refreshTicksHorizontal(g2, state.getCursor(), drawArea, dataArea, edge); } else if (RectangleEdge.isLeftOrRight(edge)) { ticks = refreshTicksVertical(g2, state.getCursor(), drawArea, dataArea, edge); } return ticks; } /** * Calculates the positions of the tick labels for the axis, storing the results in the * tick label list (ready for drawing). * * @param g2 the graphics device. * @param cursor the cursor position. * @param drawArea the area in which the plot and the axes should be drawn. * @param dataArea the area in which the plot should be drawn. * @param edge the location of the axis. * * @return A list of ticks. */ public List refreshTicksHorizontal(Graphics2D g2, double cursor, Rectangle2D drawArea, Rectangle2D dataArea, RectangleEdge edge) { List ticks = new java.util.ArrayList();// FontMetrics fm = g2.getFontMetrics(getTickLabelFont()); Range range = getRange(); //get lower bound value: double lowerBoundVal = range.getLowerBound(); //if small log values and lower bound value too small // then set to a small value (don't allow <= 0): if (this.smallLogFlag && lowerBoundVal < SMALL_LOG_VALUE) { lowerBoundVal = SMALL_LOG_VALUE; } //get upper bound value final double upperBoundVal = range.getUpperBound(); //get log10 version of lower bound and round to integer: int iBegCount = (int) Math.rint(switchedLog10(lowerBoundVal)); //get log10 version of upper bound and round to integer: final int iEndCount = (int) Math.rint(switchedLog10(upperBoundVal)); if (iBegCount == iEndCount && iBegCount > 0 && Math.pow(10, iBegCount) > lowerBoundVal) { //only 1 power of 10 value, it's > 0 and its resulting // tick value will be larger than lower bound of data --iBegCount; //decrement to generate more ticks } double currentTickValue; String tickLabel; boolean zeroTickFlag = false; for (int i = iBegCount; i <= iEndCount; i++) { //for each power of 10 value; create ten ticks for (int j = 0; j < 10; ++j) { //for each tick to be displayed if (this.smallLogFlag) { //small log values in use; create numeric value for tick currentTickValue = Math.pow(10, i) + (Math.pow(10, i) * j); if (this.expTickLabelsFlag || (i < 0 && currentTickValue > 0.0 && currentTickValue < 1.0)) { //showing "1e#"-style ticks or negative exponent // generating tick value between 0 & 1; show fewer if (j == 0 || (i > -4 && j < 2) || currentTickValue >= upperBoundVal) { //first tick of series, or not too small a value and // one of first 3 ticks, or last tick to be displayed //set exact number of fractional digits to be shown // (no effect if showing "1e#"-style ticks): this.numberFormatterObj.setMaximumFractionDigits(-i); //create tick label (force use of fmt obj): tickLabel = makeTickLabel(currentTickValue, true); } else { //no tick label to be shown tickLabel = ""; } } else { //tick value not between 0 & 1 //show tick label if it's the first or last in // the set, or if it's 1-5; beyond that show // fewer as the values get larger: tickLabel = (j < 1 || (i < 1 && j < 5) || (j < 4 - i) || currentTickValue >= upperBoundVal) ? makeTickLabel(currentTickValue) : ""; } } else { //not small log values in use; allow for values <= 0 if (zeroTickFlag) { //if did zero tick last iter then --j; //decrement to do 1.0 tick now } //calculate power-of-ten value for tick: currentTickValue = (i >= 0) ? Math.pow(10, i) + (Math.pow(10, i) * j) : -(Math.pow(10, -i) - (Math.pow(10, -i - 1) * j)); if (!zeroTickFlag) { //did not do zero tick last iteration if (Math.abs(currentTickValue - 1.0) < 0.0001 && lowerBoundVal <= 0.0 && upperBoundVal >= 0.0) { //tick value is 1.0 and 0.0 is within data range currentTickValue = 0.0; //set tick value to zero zeroTickFlag = true; //indicate zero tick } } else { //did zero tick last iteration zeroTickFlag = false; //clear flag } //create tick label string: //show tick label if "1e#"-style and it's one // of the first two, if it's the first or last // in the set, or if it's 1-5; beyond that // show fewer as the values get larger: tickLabel = ((this.expTickLabelsFlag && j < 2) || j < 1 || (i < 1 && j < 5) || (j < 4 - i) || currentTickValue >= upperBoundVal) ? makeTickLabel(currentTickValue) : ""; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -