📄 logarithmicaxis.java
字号:
//if flag then change to log version of lowest value
// to make range begin at a 10^n value:
if (this.autoRangeNextLogFlag) {
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();
//apply upper margin by increasing upper bound:
final double upperMargin;
if (upper > 0.0 && (upperMargin = getUpperMargin()) > 0.0) {
//upper bound and margin OK; get log10 of upper bound
final double logUpper = (Math.log(upper) / LOG10_VALUE);
double logAbs; //get absolute value of log10 value
if ((logAbs = Math.abs(logUpper)) < 1.0) {
logAbs = 1.0; //if less than 1.0 then make it 1.0
} //add in margin and get exponential value:
upper = Math.pow(10, (logUpper + (logAbs * upperMargin)));
}
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
//if flag then change to log version of highest value to
// make range begin at a 10^n value; else use nearest int
upper = (this.autoRangeNextLogFlag) ? computeLogCeil(upper)
: Math.ceil(upper);
}
// 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) {
double absUpper = Math.abs(upper);
//need to account for case where upper==0.0
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 switchedPow10(axisMax - ((java2DValue - plotMin)
/ (plotMax - plotMin)) * (axisMax - axisMin));
}
else {
return switchedPow10(axisMin + ((java2DValue - plotMin)
/ (plotMax - plotMin)) * (axisMax - axisMin));
}
}
/**
* Zooms in on the current range.
*
* @param lowerPercent the new lower bound.
* @param upperPercent the new upper bound.
*/
public void zoomRange(double lowerPercent, double upperPercent) {
double startLog = switchedLog10(getRange().getLowerBound());
double lengthLog = switchedLog10(getRange().getUpperBound()) -
startLog;
Range adjusted;
if (isInverted()) {
adjusted = new Range(
switchedPow10(
startLog + (lengthLog * (1 - upperPercent))),
switchedPow10(
startLog + (lengthLog * (1 - lowerPercent))));
}
else {
adjusted = new Range(
switchedPow10(startLog + (lengthLog * lowerPercent)),
switchedPow10(startLog + (lengthLog * upperPercent)));
}
setRange(adjusted);
}
/**
* 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 dataArea the area in which the plot should be drawn.
* @param edge the location of the axis.
*
* @return A list of ticks.
*/
protected List refreshTicksHorizontal(Graphics2D g2,
Rectangle2D dataArea,
RectangleEdge edge) {
List ticks = new java.util.ArrayList();
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
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:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -