Repository: silx-kit/silx
Issue: [Plot] Negative values lost when toggling log axes

When visualizing a curve with negative values, the values are not shown when setting the axis as being logarithmic, that is desired behavior. However, when coming back to linear axis, the negative values are lost/not show.


Changed files:
silx/gui/plot/Plot.py, silx/gui/plot/test/testPlotWidget.py

diff --git a/silx/gui/plot/Plot.py b/silx/gui/plot/Plot.py
index 52fe8f9ef..788ecd4d3 100644
--- a/silx/gui/plot/Plot.py
+++ b/silx/gui/plot/Plot.py
@@ -529,12 +529,12 @@ class Plot(object):
                     self._setDirtyPlot()
 
         # Filter-out values <= 0
-        x, y, color, xerror, yerror = self._logFilterData(
+        xFiltered, yFiltered, color, xerror, yerror = self._logFilterData(
             x, y, params['color'], params['xerror'], params['yerror'],
             self.isXAxisLogarithmic(), self.isYAxisLogarithmic())
 
-        if len(x) and not self.isCurveHidden(legend):
-            handle = self._backend.addCurve(x, y, legend,
+        if len(xFiltered) and not self.isCurveHidden(legend):
+            handle = self._backend.addCurve(xFiltered, yFiltered, legend,
                                             color=color,
                                             symbol=params['symbol'],
                                             linestyle=params['linestyle'],
diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py
index 7da5ab0eb..6c32d0561 100644
--- a/silx/gui/plot/test/testPlotWidget.py
+++ b/silx/gui/plot/test/testPlotWidget.py
@@ -33,6 +33,7 @@ import unittest
 
 import numpy
 
+from silx.testutils import ParametricTestCase
 from silx.gui.testutils import TestCaseQt
 
 from silx.gui import qt
@@ -424,20 +425,19 @@ class TestPlotEmptyLog(_PlotWidgetTest):
         self.qWait()
 
 
-class TestPlotCurveLog(_PlotWidgetTest):
+class TestPlotCurveLog(_PlotWidgetTest, ParametricTestCase):
     """Basic tests for addCurve with log scale axes"""
 
     # Test data
     xData = numpy.arange(1000) + 1
     yData = xData ** 2
 
-    def setUp(self):
-        super(TestPlotCurveLog, self).setUp()
-
+    def _setLabels(self):
         self.plot.setGraphXLabel('X')
         self.plot.setGraphYLabel('X * X')
 
     def testPlotCurveLogX(self):
+        self._setLabels()
         self.plot.setXAxisLogarithmic(True)
         self.plot.setGraphTitle('Curve X: Log Y: Linear')
 
@@ -445,10 +445,10 @@ class TestPlotCurveLog(_PlotWidgetTest):
                            legend="curve",
                            replace=False, resetzoom=True,
                            color='green', linestyle="-", symbol='o')
-        self.plot.resetZoom()
-        self.qWait()
+        self.qapp.processEvents()
 
     def testPlotCurveLogY(self):
+        self._setLabels()
         self.plot.setYAxisLogarithmic(True)
 
         self.plot.setGraphTitle('Curve X: Linear Y: Log')
@@ -457,10 +457,10 @@ class TestPlotCurveLog(_PlotWidgetTest):
                            legend="curve",
                            replace=False, resetzoom=True,
                            color='green', linestyle="-", symbol='o')
-        self.plot.resetZoom()
-        self.qWait()
+        self.qapp.processEvents()
 
     def testPlotCurveLogXY(self):
+        self._setLabels()
         self.plot.setXAxisLogarithmic(True)
         self.plot.setYAxisLogarithmic(True)
 
@@ -470,8 +470,91 @@ class TestPlotCurveLog(_PlotWidgetTest):
                            legend="curve",
                            replace=False, resetzoom=True,
                            color='green', linestyle="-", symbol='o')
-        self.plot.resetZoom()
-        self.qWait()
+        self.qapp.processEvents()
+
+    def testPlotCurveToggleLog(self):
+        """Add a curve with negative data and toggle log axis"""
+        arange = numpy.arange(1000) + 1
+        tests = [  # name, xData, yData
+            ('x>0, some negative y', arange, arange - 500),
+            ('x>0, y<0', arange, -arange),
+            ('some negative x, y>0', arange - 500, arange),
+            ('x<0, y>0', -arange, arange),
+            ('some negative x and y', arange - 500, arange - 500),
+            ('x<0, y<0', -arange, -arange),
+            ]
+
+        for name, xData, yData in tests:
+            with self.subTest(name):
+                self.plot.addCurve(xData, yData, resetzoom=True)
+                self.qapp.processEvents()
+
+                # no log axis
+                xLim = self.plot.getGraphXLimits()
+                self.assertEqual(xLim, (min(xData), max(xData)))
+                yLim = self.plot.getGraphYLimits()
+                self.assertEqual(yLim, (min(yData), max(yData)))
+
+                # x axis log
+                self.plot.setXAxisLogarithmic(True)
+                self.qapp.processEvents()
+
+                xLim = self.plot.getGraphXLimits()
+                yLim = self.plot.getGraphYLimits()
+                positives = xData > 0
+                if numpy.any(positives):
+                    self.assertTrue(numpy.allclose(
+                        xLim, (min(xData[positives]), max(xData[positives]))))
+                    self.assertEqual(
+                        yLim, (min(yData[positives]), max(yData[positives])))
+                else:  # No positive x in the curve
+                    self.assertEqual(xLim, (1., 100.))
+                    self.assertEqual(yLim, (1., 100.))
+
+                # x axis and y axis log
+                self.plot.setYAxisLogarithmic(True)
+                self.qapp.processEvents()
+
+                xLim = self.plot.getGraphXLimits()
+                yLim = self.plot.getGraphYLimits()
+                positives = numpy.logical_and(xData > 0, yData > 0)
+                if numpy.any(positives):
+                    self.assertTrue(numpy.allclose(
+                        xLim, (min(xData[positives]), max(xData[positives]))))
+                    self.assertTrue(numpy.allclose(
+                        yLim, (min(yData[positives]), max(yData[positives]))))
+                else:  # No positive x and y in the curve
+                    self.assertEqual(xLim, (1., 100.))
+                    self.assertEqual(yLim, (1., 100.))
+
+                # y axis log
+                self.plot.setXAxisLogarithmic(False)
+                self.qapp.processEvents()
+
+                xLim = self.plot.getGraphXLimits()
+                yLim = self.plot.getGraphYLimits()
+                positives = yData > 0
+                if numpy.any(positives):
+                    self.assertEqual(
+                        xLim, (min(xData[positives]), max(xData[positives])))
+                    self.assertTrue(numpy.allclose(
+                        yLim, (min(yData[positives]), max(yData[positives]))))
+                else:  # No positive y in the curve
+                    self.assertEqual(xLim, (1., 100.))
+                    self.assertEqual(yLim, (1., 100.))
+
+                # no log axis
+                self.plot.setYAxisLogarithmic(False)
+                self.qapp.processEvents()
+
+                xLim = self.plot.getGraphXLimits()
+                self.assertEqual(xLim, (min(xData), max(xData)))
+                yLim = self.plot.getGraphYLimits()
+                self.assertEqual(yLim, (min(yData), max(yData)))
+
+                self.plot.clear()
+                self.plot.resetZoom()
+                self.qapp.processEvents()
 
 
 class TestPlotImageLog(_PlotWidgetTest):