From: SourceForge.net <no...@so...> - 2007-02-28 17:45:08
|
Bugs item #880597, was opened at 2004-01-20 14:46 Message generated for change (Comment added) made by sergei_ivanov You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=115494&aid=880597&group_id=15494 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: General Group: None Status: Open Resolution: None Priority: 7 Private: No Submitted By: Corey Himes (keldon00) Assigned to: David Gilbert (mungady) Summary: Zooming ChartPanel w/Logarithmic Axes Initial Comment: Logarithmic axes are being used for both the domain and range axes of an XYPlot in a ChartPanel. Zooming in in any form causes the plot to zoom to an unidentifiable location. ---------------------------------------------------------------------- Comment By: Sergei Ivanov (sergei_ivanov) Date: 2007-02-28 17:44 Message: Logged In: YES user_id=1606022 Originator: NO I have just tested berth's modifications against 1.0.4 and they are working just fine. There was a problem with inverted axes, which is fixed in the new version of zoomRange(), submitted as patch #1671069. @David: could you please integrate the complete patch into the latest codebase? https://sourceforge.net/tracker/index.php?func=detail&aid=1671069&group_id=15494&atid=315494 ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-31 09:22 Message: Logged In: YES user_id=1031412 Over-riding zoomRange did not work for me, so I fixed it in LogarithmicAxisZoomPatched. LogarithmicAxisZoomPatched works for me, obviously :-) The problem is that jfreechart underwent some API (and implementation) changes in the pre-1.0 versions. So maybe the zoomRange fix worked in jfreechart 0.9.x. ---------------------------------------------------------------------- Comment By: Kurt (peterskurt) Date: 2006-03-28 14:52 Message: Logged In: YES user_id=1448929 Did over-riding zoomRange work for anyone else? It didn't work for me. Does LogarithmicAxisZoomPatched work? Has anyone tried it? Kurt ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-15 09:51 Message: Logged In: YES user_id=1031412 Here is the unit test for the fix below. Please note that you'll have to put this class into another package. --------------- /* * LogarithmicAxisZoomPatchedTest.java * JUnit based test * * Created on 14. März 2006, 15:58 */ package com.decodon.visualization.jrefinery.chart; import junit.framework.*; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.data.Range; import org.jfree.ui.RectangleEdge; import java.awt.geom.Rectangle2D; /** Unit tests for LogarithmicAxisZoomPatched. This test covers the zoom in functionality. * TODO: tests with Margins > 0, tests with negative axis values (I guess that's possible in JFreeChart) * @author berth (at) decodon dot com */ public class LogarithmicAxisZoomPatchedTest extends TestCase { /** Tolerance for floating point comparisons */ public static double EPSILON = 0.000001; LogarithmicAxisZoomPatched axis = null; public LogarithmicAxisZoomPatchedTest(String testName) { super(testName); } protected void setUp() throws Exception { axis = new LogarithmicAxisZoomPatched("Value (log)"); axis.setAllowNegativesFlag(false); axis.setLog10TickLabelsFlag(false); axis.setLowerMargin(0.0); axis.setUpperMargin(0.0); axis.setLowerBound(0.2); axis.setUpperBound(100.0); } public static Test suite() { TestSuite suite = new TestSuite(LogarithmicAxisZoomPatchedTest.class); return suite; } /** Test if adjustedLog10 and adjustedPow10 are inverses of each other */ public void testAdjustedLog10() { checkLogPowRoundTrip(20); checkLogPowRoundTrip(10); checkLogPowRoundTrip(5); checkLogPowRoundTrip(2); checkLogPowRoundTrip(1); checkLogPowRoundTrip(0.5); checkLogPowRoundTrip(0.2); checkLogPowRoundTrip(0.0001); } private void checkLogPowRoundTrip(double value) { assertEquals("log(pow(x)) = x", value, axis.adjustedLog10(axis.adjustedPow10(value)), EPSILON); assertEquals("pow(log(x)) = x", value, axis.adjustedPow10(axis.adjustedLog10(value)), EPSILON); } /** Test if switchedLog10 and switchedPow10 are inverses of each other */ public void testSwitchedLog10() { assertFalse("Axis should not allow negative values", axis.getAllowNegativesFlag()); assertEquals(Math.log(0.5) / LogarithmicAxis.LOG10_VALUE, // log10(0.5) = -0.30102999566398114 axis.switchedLog10(0.5), EPSILON); checkSwitchedLogPowRoundTrip(20); checkSwitchedLogPowRoundTrip(10); checkSwitchedLogPowRoundTrip(5); checkSwitchedLogPowRoundTrip(2); checkSwitchedLogPowRoundTrip(1); checkSwitchedLogPowRoundTrip(0.5); checkSwitchedLogPowRoundTrip(0.2); checkSwitchedLogPowRoundTrip(0.0001); } private void checkSwitchedLogPowRoundTrip(double value) { assertEquals("log(pow(x)) = x", value, axis.switchedLog10(axis.switchedPow10(value)), EPSILON); assertEquals("pow(log(x)) = x", value, axis.switchedPow10(axis.switchedLog10(value)), EPSILON); } /** * Test of java2DToValue method, of class com.decodon.visualization.jrefinery.chart.LogarithmicAxisZoomPatched. */ public void testJava2DToValue() { Rectangle2D plotArea = new Rectangle2D.Double(22, 33, 500, 500); RectangleEdge edge = RectangleEdge.BOTTOM; // set axis bounds to be both greater than 1 axis.setRange(10, 20); checkPointsToValue(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.5, 10); checkPointsToValue(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.2, 20); checkPointsToValue(edge, plotArea); // check for both bounds smaller than 1 axis.setRange(0.2, 0.7); checkPointsToValue(edge, plotArea); } /** * Test of valueToJava2D method, of class com.decodon.visualization.jrefinery.chart.LogarithmicAxisZoomPatched. */ public void testValueToJava2D() { Rectangle2D plotArea = new Rectangle2D.Double(22, 33, 500, 500); RectangleEdge edge = RectangleEdge.BOTTOM; // set axis bounds to be both greater than 1 axis.setRange(10, 20); checkPointsToJava2D(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.5, 10); checkPointsToJava2D(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.2, 20); checkPointsToJava2D(edge, plotArea); // check for both bounds smaller than 1 axis.setRange(0.2, 0.7); checkPointsToJava2D(edge, plotArea); } private void checkPointsToJava2D(final RectangleEdge edge, final Rectangle2D plotArea) { assertEquals("Left most point on the axis should be beginning of range.", plotArea.getX(), axis.valueToJava2D(axis.getLowerBound(), plotArea, edge), EPSILON); assertEquals("Right most point on the axis should be end of range.", plotArea.getX() + plotArea.getWidth(), axis.valueToJava2D(axis.getUpperBound(), plotArea, edge), EPSILON); assertEquals("Center point on the axis should geometric mean of the bounds.", plotArea.getX() + (plotArea.getWidth() / 2), axis.valueToJava2D(Math.sqrt( axis.getLowerBound() * axis.getUpperBound()), plotArea, edge), EPSILON); } /** Check the translation java2D to value for left, right, and center point of the */ private void checkPointsToValue(RectangleEdge edge, Rectangle2D plotArea) { assertEquals("Right most point on the axis should be end of range.", axis.getUpperBound(), axis.java2DToValue(plotArea.getX() + plotArea.getWidth(), plotArea, edge), EPSILON); assertEquals("Left most point on the axis should be beginning of range.", axis.getLowerBound(), axis.java2DToValue(plotArea.getX(), plotArea, edge), EPSILON); assertEquals("Center point on the axis should geometric mean of the bounds.", Math.sqrt(axis.getUpperBound() * axis.getLowerBound()), axis.java2DToValue(plotArea.getX() + (plotArea.getWidth() / 2), plotArea, edge), EPSILON); } public static void main(String[] args) { junit.textui.TestRunner.run(LogarithmicAxisZoomPatchedTest.class); } } ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-15 09:48 Message: Logged In: YES user_id=1031412 Here is a fix, unit tested for JFreechart 1.0.1. I have made a subclass of LogarithmicAxis that does zoom in correctly. I have used the patches suggested here, the main problem was that switchedLog10 was not really an inverse of switchedLog10, you have to use this.smallLogFlag for switching, just like switchedLog10 does. Unit test follows in next comment. Please note that you'll have to put this class into another package. --------------- package com.decodon.visualization.jrefinery.chart; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.data.Range; import org.jfree.ui.RectangleEdge; import java.awt.geom.Rectangle2D; /** * This is a patched version of org.jfree.chart.axis.LogarithmicAxis, according to * http://sourceforge.net/tracker/index.php?func=detail&aid=880597&group_id=15494&atid=115494 * It fixes a problem with zooming when logarithmic axes are used. Tested with JFreechart 1.0.1. * * @author berth (at) decodon dot com */ public class LogarithmicAxisZoomPatched extends LogarithmicAxis { /** * Creates a new instance of LogarithmicAxisZoomPatched * @param label the axis label. */ public LogarithmicAxisZoomPatched(String label) { super(label); } public double adjustedPow10(double val) { boolean negFlag = (val < 0.0); if (negFlag) { val = -val; // if negative then set flag and make positive } double res = Math.pow(10, val); if (val < 1.0) { res = (Math.pow(10, val + 1.0) - 10.0) / 9.0; //invert adjustLog10 } return negFlag ? (-res) : res; } /** * 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.getMinX(); 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))); } } /** * Returns the log10 value, depending on if values between 0 and * 1 are being plotted. If negative values are not allowed and * the lower bound is between 0 and 10 then a normal log is * returned; otherwise the returned value is adjusted if the * given value is less than 10. * * Note: I've made this a public method to be able to access it in a unit test * * @param val the value. * @return log<sub>10</sub>(val). */ public double switchedLog10(double val) { double retValue; retValue = super.switchedLog10(val); return retValue; } /** Inverse function of switchedLog10 */ public double switchedPow10(double val) { return this.smallLogFlag ? Math.pow(10.0, val) : adjustedPow10(val); } /** * 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 = null; if (isInverted()) { adjusted = new Range(switchedPow10(startLog + (lengthLog * (1 - lowerPercent))), switchedPow10(startLog + (lengthLog * (1 + upperPercent)))); } else { adjusted = new Range(switchedPow10(startLog + (lengthLog * lowerPercent)), switchedPow10(startLog + (lengthLog * upperPercent))); } setRange(adjusted); } } ---------------------------------------------------------------------- Comment By: Roger Shaw (rjshaw) Date: 2005-09-14 15:00 Message: Logged In: YES user_id=712400 Problem still exists in RC1 - Please fix! ---------------------------------------------------------------------- Comment By: Nobody/Anonymous (nobody) Date: 2005-07-21 12:56 Message: Logged In: NO Why is this bug still open? It was reported over a year ago and in my opinion it is a serious problem that you cannot do mouse zooming in an XYPlot with a logarithmic range axis. It seems quite easy to fix, so why not give it a little attention. Thanks. ---------------------------------------------------------------------- Comment By: Vincent (vincegay) Date: 2005-03-03 09:50 Message: Logged In: YES user_id=1231559 Hi! The 2nd patch doesn't work if the axis is inverted. cheers Vincent ---------------------------------------------------------------------- Comment By: deverhel (deverhel) Date: 2004-05-26 13:53 Message: Logged In: YES user_id=1050162 I have try the patch , it work well for positive values, but if the axis allow negative values the problems are still present. I suggest to insert a switchingPow10 method that invert the switchingLog10, and use it instead the Math.pow in the method zoomRange: (and also in the java2DToValue method): Below I wrote the methods proposed to be inserted/overwritten in the LogarithmicAxis ------------------------------------------------------------ protected double switchedPow10(double val) { return (!this.allowNegativesFlag && val < 1.0 && val > 0.0) ? Math.pow(10.0,val) : adjustedPow10(val); } public double adjustedPow10(double val) { boolean negFlag = (val < 0.0); if (negFlag) { val = -val ; // if negative then set flag and make positive } double res=Math.pow(10,val); if (val < 1.0) { res=(Math.pow(10,val+1.0)-10.0)/9.0; //invert adjustLog10 } return negFlag ? -res : res; } 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.getMinX(); 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)); } } public void zoomRange(double lowerPercent, double upperPercent) { double startLog = switchedLog10(getRange().getLowerBound()); double lengthLog = switchedLog10(getRange().getUpperBound()) - startLog; Range adjusted = null; if(isInverted()){ adjusted = new Range( switchedPow10( startLog + lengthLog * (1 - lowerPercent)),switchedPow10(startLog + lengthLog * (1 + upperPercent))); } else{ adjusted = new Range(switchedPow10( startLog + lengthLog * lowerPercent), switchedPow10( startLog + lengthLog * upperPercent)); } setRange(adjusted); } ---------------------------------------------------------------------- Comment By: David Gilbert (mungady) Date: 2004-01-28 19:24 Message: Logged In: YES user_id=112975 Thanks for the report. I will look at your solution... Regards, Dave Gilbert JFreeChart Project Leader ---------------------------------------------------------------------- Comment By: Corey Himes (keldon00) Date: 2004-01-20 16:40 Message: Logged In: YES user_id=951857 I have traced the problem to LogarithmicAxis. zoomRange needs to be overridden in LogarithmicAxis. I have attached a corrected version of zoomRange. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=115494&aid=880597&group_id=15494 |
From: SourceForge.net <no...@so...> - 2007-03-02 15:39:27
|
Bugs item #880597, was opened at 2004-01-20 14:46 Message generated for change (Comment added) made by mungady You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=115494&aid=880597&group_id=15494 Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: General Group: None >Status: Closed >Resolution: Fixed Priority: 7 Private: No Submitted By: Corey Himes (keldon00) Assigned to: David Gilbert (mungady) Summary: Zooming ChartPanel w/Logarithmic Axes Initial Comment: Logarithmic axes are being used for both the domain and range axes of an XYPlot in a ChartPanel. Zooming in in any form causes the plot to zoom to an unidentifiable location. ---------------------------------------------------------------------- >Comment By: David Gilbert (mungady) Date: 2007-03-02 15:39 Message: Logged In: YES user_id=112975 Originator: NO Hi Sergei, Thanks for your work on this. I committed your patch from #1671069, and added the unit test. This will be included in the 1.0.5 release. Regards, Dave Gilbert JFreeChart Project Leader ---------------------------------------------------------------------- Comment By: Sergei Ivanov (sergei_ivanov) Date: 2007-02-28 17:44 Message: Logged In: YES user_id=1606022 Originator: NO I have just tested berth's modifications against 1.0.4 and they are working just fine. There was a problem with inverted axes, which is fixed in the new version of zoomRange(), submitted as patch #1671069. @David: could you please integrate the complete patch into the latest codebase? https://sourceforge.net/tracker/index.php?func=detail&aid=1671069&group_id=15494&atid=315494 ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-31 08:22 Message: Logged In: YES user_id=1031412 Over-riding zoomRange did not work for me, so I fixed it in LogarithmicAxisZoomPatched. LogarithmicAxisZoomPatched works for me, obviously :-) The problem is that jfreechart underwent some API (and implementation) changes in the pre-1.0 versions. So maybe the zoomRange fix worked in jfreechart 0.9.x. ---------------------------------------------------------------------- Comment By: Kurt (peterskurt) Date: 2006-03-28 13:52 Message: Logged In: YES user_id=1448929 Did over-riding zoomRange work for anyone else? It didn't work for me. Does LogarithmicAxisZoomPatched work? Has anyone tried it? Kurt ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-15 09:51 Message: Logged In: YES user_id=1031412 Here is the unit test for the fix below. Please note that you'll have to put this class into another package. --------------- /* * LogarithmicAxisZoomPatchedTest.java * JUnit based test * * Created on 14. März 2006, 15:58 */ package com.decodon.visualization.jrefinery.chart; import junit.framework.*; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.data.Range; import org.jfree.ui.RectangleEdge; import java.awt.geom.Rectangle2D; /** Unit tests for LogarithmicAxisZoomPatched. This test covers the zoom in functionality. * TODO: tests with Margins > 0, tests with negative axis values (I guess that's possible in JFreeChart) * @author berth (at) decodon dot com */ public class LogarithmicAxisZoomPatchedTest extends TestCase { /** Tolerance for floating point comparisons */ public static double EPSILON = 0.000001; LogarithmicAxisZoomPatched axis = null; public LogarithmicAxisZoomPatchedTest(String testName) { super(testName); } protected void setUp() throws Exception { axis = new LogarithmicAxisZoomPatched("Value (log)"); axis.setAllowNegativesFlag(false); axis.setLog10TickLabelsFlag(false); axis.setLowerMargin(0.0); axis.setUpperMargin(0.0); axis.setLowerBound(0.2); axis.setUpperBound(100.0); } public static Test suite() { TestSuite suite = new TestSuite(LogarithmicAxisZoomPatchedTest.class); return suite; } /** Test if adjustedLog10 and adjustedPow10 are inverses of each other */ public void testAdjustedLog10() { checkLogPowRoundTrip(20); checkLogPowRoundTrip(10); checkLogPowRoundTrip(5); checkLogPowRoundTrip(2); checkLogPowRoundTrip(1); checkLogPowRoundTrip(0.5); checkLogPowRoundTrip(0.2); checkLogPowRoundTrip(0.0001); } private void checkLogPowRoundTrip(double value) { assertEquals("log(pow(x)) = x", value, axis.adjustedLog10(axis.adjustedPow10(value)), EPSILON); assertEquals("pow(log(x)) = x", value, axis.adjustedPow10(axis.adjustedLog10(value)), EPSILON); } /** Test if switchedLog10 and switchedPow10 are inverses of each other */ public void testSwitchedLog10() { assertFalse("Axis should not allow negative values", axis.getAllowNegativesFlag()); assertEquals(Math.log(0.5) / LogarithmicAxis.LOG10_VALUE, // log10(0.5) = -0.30102999566398114 axis.switchedLog10(0.5), EPSILON); checkSwitchedLogPowRoundTrip(20); checkSwitchedLogPowRoundTrip(10); checkSwitchedLogPowRoundTrip(5); checkSwitchedLogPowRoundTrip(2); checkSwitchedLogPowRoundTrip(1); checkSwitchedLogPowRoundTrip(0.5); checkSwitchedLogPowRoundTrip(0.2); checkSwitchedLogPowRoundTrip(0.0001); } private void checkSwitchedLogPowRoundTrip(double value) { assertEquals("log(pow(x)) = x", value, axis.switchedLog10(axis.switchedPow10(value)), EPSILON); assertEquals("pow(log(x)) = x", value, axis.switchedPow10(axis.switchedLog10(value)), EPSILON); } /** * Test of java2DToValue method, of class com.decodon.visualization.jrefinery.chart.LogarithmicAxisZoomPatched. */ public void testJava2DToValue() { Rectangle2D plotArea = new Rectangle2D.Double(22, 33, 500, 500); RectangleEdge edge = RectangleEdge.BOTTOM; // set axis bounds to be both greater than 1 axis.setRange(10, 20); checkPointsToValue(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.5, 10); checkPointsToValue(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.2, 20); checkPointsToValue(edge, plotArea); // check for both bounds smaller than 1 axis.setRange(0.2, 0.7); checkPointsToValue(edge, plotArea); } /** * Test of valueToJava2D method, of class com.decodon.visualization.jrefinery.chart.LogarithmicAxisZoomPatched. */ public void testValueToJava2D() { Rectangle2D plotArea = new Rectangle2D.Double(22, 33, 500, 500); RectangleEdge edge = RectangleEdge.BOTTOM; // set axis bounds to be both greater than 1 axis.setRange(10, 20); checkPointsToJava2D(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.5, 10); checkPointsToJava2D(edge, plotArea); // check for bounds interval that includes 1 axis.setRange(0.2, 20); checkPointsToJava2D(edge, plotArea); // check for both bounds smaller than 1 axis.setRange(0.2, 0.7); checkPointsToJava2D(edge, plotArea); } private void checkPointsToJava2D(final RectangleEdge edge, final Rectangle2D plotArea) { assertEquals("Left most point on the axis should be beginning of range.", plotArea.getX(), axis.valueToJava2D(axis.getLowerBound(), plotArea, edge), EPSILON); assertEquals("Right most point on the axis should be end of range.", plotArea.getX() + plotArea.getWidth(), axis.valueToJava2D(axis.getUpperBound(), plotArea, edge), EPSILON); assertEquals("Center point on the axis should geometric mean of the bounds.", plotArea.getX() + (plotArea.getWidth() / 2), axis.valueToJava2D(Math.sqrt( axis.getLowerBound() * axis.getUpperBound()), plotArea, edge), EPSILON); } /** Check the translation java2D to value for left, right, and center point of the */ private void checkPointsToValue(RectangleEdge edge, Rectangle2D plotArea) { assertEquals("Right most point on the axis should be end of range.", axis.getUpperBound(), axis.java2DToValue(plotArea.getX() + plotArea.getWidth(), plotArea, edge), EPSILON); assertEquals("Left most point on the axis should be beginning of range.", axis.getLowerBound(), axis.java2DToValue(plotArea.getX(), plotArea, edge), EPSILON); assertEquals("Center point on the axis should geometric mean of the bounds.", Math.sqrt(axis.getUpperBound() * axis.getLowerBound()), axis.java2DToValue(plotArea.getX() + (plotArea.getWidth() / 2), plotArea, edge), EPSILON); } public static void main(String[] args) { junit.textui.TestRunner.run(LogarithmicAxisZoomPatchedTest.class); } } ---------------------------------------------------------------------- Comment By: berth (berth) Date: 2006-03-15 09:48 Message: Logged In: YES user_id=1031412 Here is a fix, unit tested for JFreechart 1.0.1. I have made a subclass of LogarithmicAxis that does zoom in correctly. I have used the patches suggested here, the main problem was that switchedLog10 was not really an inverse of switchedLog10, you have to use this.smallLogFlag for switching, just like switchedLog10 does. Unit test follows in next comment. Please note that you'll have to put this class into another package. --------------- package com.decodon.visualization.jrefinery.chart; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.data.Range; import org.jfree.ui.RectangleEdge; import java.awt.geom.Rectangle2D; /** * This is a patched version of org.jfree.chart.axis.LogarithmicAxis, according to * http://sourceforge.net/tracker/index.php?func=detail&aid=880597&group_id=15494&atid=115494 * It fixes a problem with zooming when logarithmic axes are used. Tested with JFreechart 1.0.1. * * @author berth (at) decodon dot com */ public class LogarithmicAxisZoomPatched extends LogarithmicAxis { /** * Creates a new instance of LogarithmicAxisZoomPatched * @param label the axis label. */ public LogarithmicAxisZoomPatched(String label) { super(label); } public double adjustedPow10(double val) { boolean negFlag = (val < 0.0); if (negFlag) { val = -val; // if negative then set flag and make positive } double res = Math.pow(10, val); if (val < 1.0) { res = (Math.pow(10, val + 1.0) - 10.0) / 9.0; //invert adjustLog10 } return negFlag ? (-res) : res; } /** * 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.getMinX(); 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))); } } /** * Returns the log10 value, depending on if values between 0 and * 1 are being plotted. If negative values are not allowed and * the lower bound is between 0 and 10 then a normal log is * returned; otherwise the returned value is adjusted if the * given value is less than 10. * * Note: I've made this a public method to be able to access it in a unit test * * @param val the value. * @return log<sub>10</sub>(val). */ public double switchedLog10(double val) { double retValue; retValue = super.switchedLog10(val); return retValue; } /** Inverse function of switchedLog10 */ public double switchedPow10(double val) { return this.smallLogFlag ? Math.pow(10.0, val) : adjustedPow10(val); } /** * 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 = null; if (isInverted()) { adjusted = new Range(switchedPow10(startLog + (lengthLog * (1 - lowerPercent))), switchedPow10(startLog + (lengthLog * (1 + upperPercent)))); } else { adjusted = new Range(switchedPow10(startLog + (lengthLog * lowerPercent)), switchedPow10(startLog + (lengthLog * upperPercent))); } setRange(adjusted); } } ---------------------------------------------------------------------- Comment By: Roger Shaw (rjshaw) Date: 2005-09-14 14:00 Message: Logged In: YES user_id=712400 Problem still exists in RC1 - Please fix! ---------------------------------------------------------------------- Comment By: Nobody/Anonymous (nobody) Date: 2005-07-21 11:56 Message: Logged In: NO Why is this bug still open? It was reported over a year ago and in my opinion it is a serious problem that you cannot do mouse zooming in an XYPlot with a logarithmic range axis. It seems quite easy to fix, so why not give it a little attention. Thanks. ---------------------------------------------------------------------- Comment By: Vincent (vincegay) Date: 2005-03-03 09:50 Message: Logged In: YES user_id=1231559 Hi! The 2nd patch doesn't work if the axis is inverted. cheers Vincent ---------------------------------------------------------------------- Comment By: deverhel (deverhel) Date: 2004-05-26 12:53 Message: Logged In: YES user_id=1050162 I have try the patch , it work well for positive values, but if the axis allow negative values the problems are still present. I suggest to insert a switchingPow10 method that invert the switchingLog10, and use it instead the Math.pow in the method zoomRange: (and also in the java2DToValue method): Below I wrote the methods proposed to be inserted/overwritten in the LogarithmicAxis ------------------------------------------------------------ protected double switchedPow10(double val) { return (!this.allowNegativesFlag && val < 1.0 && val > 0.0) ? Math.pow(10.0,val) : adjustedPow10(val); } public double adjustedPow10(double val) { boolean negFlag = (val < 0.0); if (negFlag) { val = -val ; // if negative then set flag and make positive } double res=Math.pow(10,val); if (val < 1.0) { res=(Math.pow(10,val+1.0)-10.0)/9.0; //invert adjustLog10 } return negFlag ? -res : res; } 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.getMinX(); 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)); } } public void zoomRange(double lowerPercent, double upperPercent) { double startLog = switchedLog10(getRange().getLowerBound()); double lengthLog = switchedLog10(getRange().getUpperBound()) - startLog; Range adjusted = null; if(isInverted()){ adjusted = new Range( switchedPow10( startLog + lengthLog * (1 - lowerPercent)),switchedPow10(startLog + lengthLog * (1 + upperPercent))); } else{ adjusted = new Range(switchedPow10( startLog + lengthLog * lowerPercent), switchedPow10( startLog + lengthLog * upperPercent)); } setRange(adjusted); } ---------------------------------------------------------------------- Comment By: David Gilbert (mungady) Date: 2004-01-28 19:24 Message: Logged In: YES user_id=112975 Thanks for the report. I will look at your solution... Regards, Dave Gilbert JFreeChart Project Leader ---------------------------------------------------------------------- Comment By: Corey Himes (keldon00) Date: 2004-01-20 16:40 Message: Logged In: YES user_id=951857 I have traced the problem to LogarithmicAxis. zoomRange needs to be overridden in LogarithmicAxis. I have attached a corrected version of zoomRange. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=115494&aid=880597&group_id=15494 |