Repository: pyqtgraph/pyqtgraph

Issue:
Crash when axis range set to invalid value in context menu
Hi,

Thanks for the fantastic package!  I encountered an issue where PyQtGraph crashes if an invalid string (e.g. '2.65a') is entered for a manual axis range limit in the context menu that appears when you right click in a plot window.  The error message reads:

```
Traceback (most recent call last):
  File "C:\Anaconda3\lib\site-packages\pyqtgraph\graphicsItems\ViewB
ox\ViewBoxMenu.py", line 201, in yMaxTextChanged
    self.view().setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1]
.maxText.text()), padding=0)
ValueError: could not convert string to float: '2.6398a'
```

best,

Thomas



Discussion:

Resolving patch:
diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBoxMenu.py b/pyqtgraph/graphicsItems/ViewBox/ViewBoxMenu.py
--- a/pyqtgraph/graphicsItems/ViewBox/ViewBoxMenu.py
+++ b/pyqtgraph/graphicsItems/ViewBox/ViewBoxMenu.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 from ...Qt import QtCore, QtGui, QT_LIB
 from ...python2_3 import asUnicode
 from ...WidgetGroup import WidgetGroup
@@ -48,8 +49,8 @@ def __init__(self, view):
             connects = [
                 (ui.mouseCheck.toggled, 'MouseToggled'),
                 (ui.manualRadio.clicked, 'ManualClicked'),
-                (ui.minText.editingFinished, 'MinTextChanged'),
-                (ui.maxText.editingFinished, 'MaxTextChanged'),
+                (ui.minText.editingFinished, 'RangeTextChanged'),
+                (ui.maxText.editingFinished, 'RangeTextChanged'),
                 (ui.autoRadio.clicked, 'AutoClicked'),
                 (ui.autoPercentSpin.valueChanged, 'AutoSpinChanged'),
                 (ui.linkCombo.currentIndexChanged, 'LinkComboChanged'),
@@ -162,14 +163,10 @@ def xMouseToggled(self, b):
     def xManualClicked(self):
         self.view().enableAutoRange(ViewBox.XAxis, False)
         
-    def xMinTextChanged(self):
+    def xRangeTextChanged(self):
         self.ctrl[0].manualRadio.setChecked(True)
-        self.view().setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
+        self.view().setXRange(*self._validateRangeText(0), padding=0)
 
-    def xMaxTextChanged(self):
-        self.ctrl[0].manualRadio.setChecked(True)
-        self.view().setXRange(float(self.ctrl[0].minText.text()), float(self.ctrl[0].maxText.text()), padding=0)
-        
     def xAutoClicked(self):
         val = self.ctrl[0].autoPercentSpin.value() * 0.01
         self.view().enableAutoRange(ViewBox.XAxis, val)
@@ -194,13 +191,9 @@ def yMouseToggled(self, b):
     def yManualClicked(self):
         self.view().enableAutoRange(ViewBox.YAxis, False)
         
-    def yMinTextChanged(self):
-        self.ctrl[1].manualRadio.setChecked(True)
-        self.view().setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
-        
-    def yMaxTextChanged(self):
+    def yRangeTextChanged(self):
         self.ctrl[1].manualRadio.setChecked(True)
-        self.view().setYRange(float(self.ctrl[1].minText.text()), float(self.ctrl[1].maxText.text()), padding=0)
+        self.view().setYRange(*self._validateRangeText(1), padding=0)
         
     def yAutoClicked(self):
         val = self.ctrl[1].autoPercentSpin.value() * 0.01
@@ -265,6 +258,20 @@ def setViewList(self, views):
             if changed:
                 c.setCurrentIndex(0)
                 c.currentIndexChanged.emit(c.currentIndex())
+
+    def _validateRangeText(self, axis):
+        """Validate range text inputs. Return current value(s) if invalid."""
+        inputs = (self.ctrl[axis].minText.text(),
+                  self.ctrl[axis].maxText.text())
+        vals = self.view().viewRange()[axis]
+        for i, text in enumerate(inputs):
+            try:
+                vals[i] = float(text)
+            except ValueError:
+                # could not convert string to float
+                pass
+        return vals
+
         
 from .ViewBox import ViewBox
         


Test patch: