Merge pull request #1540 from ixjlyons/siprefix-without-suffix
Support siPrefix with no suffix in SpinBox
This commit is contained in:
commit
6123e16f54
@ -65,6 +65,8 @@ SI Unit Conversion Functions
|
|||||||
|
|
||||||
.. autofunction:: pyqtgraph.siEval
|
.. autofunction:: pyqtgraph.siEval
|
||||||
|
|
||||||
|
.. autofunction:: pyqtgraph.siParse
|
||||||
|
|
||||||
|
|
||||||
Image Preparation Functions
|
Image Preparation Functions
|
||||||
---------------------------
|
---------------------------
|
||||||
@ -100,5 +102,3 @@ Miscellaneous Functions
|
|||||||
.. autofunction:: pyqtgraph.systemInfo
|
.. autofunction:: pyqtgraph.systemInfo
|
||||||
|
|
||||||
.. autofunction:: pyqtgraph.exit
|
.. autofunction:: pyqtgraph.exit
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ spins = [
|
|||||||
pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=0.5, minStep=0.01)),
|
pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=0.5, minStep=0.01)),
|
||||||
("Float with SI-prefixed units,<br>dec step=1.0, minStep=0.001",
|
("Float with SI-prefixed units,<br>dec step=1.0, minStep=0.001",
|
||||||
pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=1.0, minStep=0.001)),
|
pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=1.0, minStep=0.001)),
|
||||||
|
("Float with SI prefix but no suffix",
|
||||||
|
pg.SpinBox(value=1e9, siPrefix=True)),
|
||||||
("Float with custom formatting",
|
("Float with custom formatting",
|
||||||
pg.SpinBox(value=23.07, format='${value:0.02f}',
|
pg.SpinBox(value=23.07, format='${value:0.02f}',
|
||||||
regex='\$?(?P<number>(-?\d+(\.\d+)?)|(-?\.\d+))$')),
|
regex='\$?(?P<number>(-?\d+(\.\d+)?)|(-?\.\d+))$')),
|
||||||
|
@ -122,7 +122,25 @@ def siParse(s, regex=FLOAT_REGEX, suffix=None):
|
|||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
siParse('100 μV") # returns ('100', 'μ', 'V')
|
siParse('100 µV") # returns ('100', 'µ', 'V')
|
||||||
|
|
||||||
|
Note that in the above example, the µ symbol is the "micro sign" (UTF-8
|
||||||
|
0xC2B5), as opposed to the Greek letter mu (UTF-8 0xCEBC).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
s : str
|
||||||
|
The string to parse.
|
||||||
|
regex : re.Pattern, optional
|
||||||
|
Compiled regular expression object for parsing. The default is a
|
||||||
|
general-purpose regex for parsing floating point expressions,
|
||||||
|
potentially containing an SI prefix and a suffix.
|
||||||
|
suffix : str, optional
|
||||||
|
Suffix to check for in ``s``. The default (None) indicates there may or
|
||||||
|
may not be a suffix contained in the string and it is returned if
|
||||||
|
found. An empty string ``""`` is handled differently: if the string
|
||||||
|
contains a suffix, it is discarded. This enables interpreting
|
||||||
|
characters following the numerical value as an SI prefix.
|
||||||
"""
|
"""
|
||||||
s = asUnicode(s)
|
s = asUnicode(s)
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
@ -131,9 +149,14 @@ def siParse(s, regex=FLOAT_REGEX, suffix=None):
|
|||||||
raise ValueError("String '%s' does not have the expected suffix '%s'" % (s, suffix))
|
raise ValueError("String '%s' does not have the expected suffix '%s'" % (s, suffix))
|
||||||
s = s[:-len(suffix)] + 'X' # add a fake suffix so the regex still picks up the si prefix
|
s = s[:-len(suffix)] + 'X' # add a fake suffix so the regex still picks up the si prefix
|
||||||
|
|
||||||
|
# special case: discard any extra characters if suffix is explicitly empty
|
||||||
|
if suffix == "":
|
||||||
|
s += 'X'
|
||||||
|
|
||||||
m = regex.match(s)
|
m = regex.match(s)
|
||||||
if m is None:
|
if m is None:
|
||||||
raise ValueError('Cannot parse number "%s"' % s)
|
raise ValueError('Cannot parse number "%s"' % s)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sip = m.group('siPrefix')
|
sip = m.group('siPrefix')
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
@ -424,5 +424,29 @@ def test_eq():
|
|||||||
assert not eq(set(range(10)), set(range(9)))
|
assert not eq(set(range(10)), set(range(9)))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
@pytest.mark.parametrize("s,suffix,expected", [
|
||||||
test_interpolateArray()
|
# usual cases
|
||||||
|
("100 uV", "V", ("100", "u", "V")),
|
||||||
|
("100 µV", "V", ("100", "µ", "V")),
|
||||||
|
("4.2 nV", None, ("4.2", "n", "V")),
|
||||||
|
("1.2 m", "m", ("1.2", "", "m")),
|
||||||
|
("1.2 m", None, ("1.2", "", "m")),
|
||||||
|
("5.0e9", None, ("5.0e9", "", "")),
|
||||||
|
("2 units", "units", ("2", "", "units")),
|
||||||
|
# siPrefix with explicit empty suffix
|
||||||
|
("1.2 m", "", ("1.2", "m", "")),
|
||||||
|
("5.0e-9 M", "", ("5.0e-9", "M", "")),
|
||||||
|
# weirder cases that should return the reasonable thing
|
||||||
|
("4.2 nV", "nV", ("4.2", "", "nV")),
|
||||||
|
("4.2 nV", "", ("4.2", "n", "")),
|
||||||
|
("1.2 j", "", ("1.2", "", "")),
|
||||||
|
("1.2 j", None, ("1.2", "", "j")),
|
||||||
|
# expected error cases
|
||||||
|
("100 uV", "v", ValueError),
|
||||||
|
])
|
||||||
|
def test_siParse(s, suffix, expected):
|
||||||
|
if isinstance(expected, tuple):
|
||||||
|
assert pg.siParse(s, suffix=suffix) == expected
|
||||||
|
else:
|
||||||
|
with pytest.raises(expected):
|
||||||
|
pg.siParse(s, suffix=suffix)
|
||||||
|
@ -132,8 +132,10 @@ class SpinBox(QtGui.QAbstractSpinBox):
|
|||||||
siPrefix (bool) If True, then an SI prefix is automatically prepended
|
siPrefix (bool) If True, then an SI prefix is automatically prepended
|
||||||
to the units and the value is scaled accordingly. For example,
|
to the units and the value is scaled accordingly. For example,
|
||||||
if value=0.003 and suffix='V', then the SpinBox will display
|
if value=0.003 and suffix='V', then the SpinBox will display
|
||||||
"300 mV" (but a call to SpinBox.value will still return 0.003). Default
|
"300 mV" (but a call to SpinBox.value will still return 0.003). In case
|
||||||
is False.
|
the value represents a dimensionless quantity that might span many
|
||||||
|
orders of magnitude, such as a Reynold's number, an SI
|
||||||
|
prefix is allowed with no suffix. Default is False.
|
||||||
step (float) The size of a single step. This is used when clicking the up/
|
step (float) The size of a single step. This is used when clicking the up/
|
||||||
down arrows, when rolling the mouse wheel, or when pressing
|
down arrows, when rolling the mouse wheel, or when pressing
|
||||||
keyboard arrows while the widget has keyboard focus. Note that
|
keyboard arrows while the widget has keyboard focus. Note that
|
||||||
@ -466,7 +468,7 @@ class SpinBox(QtGui.QAbstractSpinBox):
|
|||||||
|
|
||||||
# format the string
|
# format the string
|
||||||
val = self.value()
|
val = self.value()
|
||||||
if self.opts['siPrefix'] is True and len(self.opts['suffix']) > 0:
|
if self.opts['siPrefix'] is True:
|
||||||
# SI prefix was requested, so scale the value accordingly
|
# SI prefix was requested, so scale the value accordingly
|
||||||
|
|
||||||
if self.val == 0 and prev is not None:
|
if self.val == 0 and prev is not None:
|
||||||
@ -545,7 +547,7 @@ class SpinBox(QtGui.QAbstractSpinBox):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# check suffix
|
# check suffix
|
||||||
if suffix != self.opts['suffix'] or (suffix == '' and siprefix != ''):
|
if suffix != self.opts['suffix']:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# generate value
|
# generate value
|
||||||
|
@ -23,6 +23,7 @@ def test_SpinBox_defaults():
|
|||||||
(1.45, '1.45 PSI', dict(int=False, decimals=6, suffix='PSI', siPrefix=True)),
|
(1.45, '1.45 PSI', dict(int=False, decimals=6, suffix='PSI', siPrefix=True)),
|
||||||
(1.45e-3, '1.45 mPSI', dict(int=False, decimals=6, suffix='PSI', siPrefix=True)),
|
(1.45e-3, '1.45 mPSI', dict(int=False, decimals=6, suffix='PSI', siPrefix=True)),
|
||||||
(-2500.3427, '$-2500.34', dict(int=False, format='${value:0.02f}')),
|
(-2500.3427, '$-2500.34', dict(int=False, format='${value:0.02f}')),
|
||||||
|
(1000, '1 k', dict(siPrefix=True, suffix="")),
|
||||||
])
|
])
|
||||||
def test_SpinBox_formatting(value, expected_text, opts):
|
def test_SpinBox_formatting(value, expected_text, opts):
|
||||||
sb = pg.SpinBox(**opts)
|
sb = pg.SpinBox(**opts)
|
||||||
@ -35,10 +36,11 @@ def test_SpinBox_formatting(value, expected_text, opts):
|
|||||||
@pytest.mark.parametrize("suffix", ["", "V"])
|
@pytest.mark.parametrize("suffix", ["", "V"])
|
||||||
def test_SpinBox_gui_set_value(suffix):
|
def test_SpinBox_gui_set_value(suffix):
|
||||||
sb = pg.SpinBox(suffix=suffix)
|
sb = pg.SpinBox(suffix=suffix)
|
||||||
|
|
||||||
sb.lineEdit().setText('0.1' + suffix)
|
sb.lineEdit().setText('0.1' + suffix)
|
||||||
sb.editingFinishedEvent()
|
sb.editingFinishedEvent()
|
||||||
assert sb.value() == 0.1
|
assert sb.value() == 0.1
|
||||||
if suffix != '':
|
|
||||||
sb.lineEdit().setText('0.1 m' + suffix)
|
sb.lineEdit().setText('0.1 m' + suffix)
|
||||||
sb.editingFinishedEvent()
|
sb.editingFinishedEvent()
|
||||||
assert sb.value() == 0.1e-3
|
assert sb.value() == 0.1e-3
|
||||||
|
Loading…
Reference in New Issue
Block a user