From cc5f066764aeacc4dc750930518702862bf90a85 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sat, 1 Sep 2018 18:15:52 -0400 Subject: [PATCH 1/3] Removed redundant test --- _plotly_utils/tests/validators/test_color_validator.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/_plotly_utils/tests/validators/test_color_validator.py b/_plotly_utils/tests/validators/test_color_validator.py index c83947204ee..0ffb31a2f14 100644 --- a/_plotly_utils/tests/validators/test_color_validator.py +++ b/_plotly_utils/tests/validators/test_color_validator.py @@ -192,12 +192,6 @@ def test_description_aok(validator_aok): assert 'A list or array of any of the above' in desc -def test_description_aok(validator_colorscale): - desc = validator_colorscale.description() - assert 'A number that will be interpreted as a color' in desc - assert 'A list or array of any of the above' not in desc - - def test_description_aok_colorscale(validator_aok_colorscale): desc = validator_aok_colorscale.description() assert 'A number that will be interpreted as a color' in desc From 849c188d4fc368b8bde63f46fad37ac411f057ba Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sat, 1 Sep 2018 18:41:36 -0400 Subject: [PATCH 2/3] Performance optimization for numeric coercion of pandas series/index --- _plotly_utils/basevalidators.py | 6 ++++++ _plotly_utils/tests/validators/test_integer_validator.py | 8 ++++++-- _plotly_utils/tests/validators/test_number_validator.py | 6 ++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/_plotly_utils/basevalidators.py b/_plotly_utils/basevalidators.py index e7b0d9b093f..cfe478e61dd 100644 --- a/_plotly_utils/basevalidators.py +++ b/_plotly_utils/basevalidators.py @@ -83,6 +83,12 @@ def copy_to_readonly_numpy_array(v, dtype=None, force_numeric=False): # u: unsigned int, i: signed int, f: float numeric_kinds = ['u', 'i', 'f'] + # Unwrap data types that have a `values` property that might be a numpy + # array. If this values property is a numeric numpy array then we + # can take the fast path below + if pd and isinstance(v, (pd.Series, pd.Index)): + v = v.values + if not isinstance(v, np.ndarray): v_list = [to_scalar_or_list(e) for e in v] new_v = np.array(v_list, order='C', dtype=dtype) diff --git a/_plotly_utils/tests/validators/test_integer_validator.py b/_plotly_utils/tests/validators/test_integer_validator.py index 796622e3792..2aefff0c246 100644 --- a/_plotly_utils/tests/validators/test_integer_validator.py +++ b/_plotly_utils/tests/validators/test_integer_validator.py @@ -4,6 +4,7 @@ from pytest import approx from _plotly_utils.basevalidators import IntegerValidator import numpy as np +import pandas as pd # ### Fixtures ### @@ -121,10 +122,12 @@ def test_acceptance_aok_list(val, validator_aok): [([1, 0], (1, 0)), ((1, -1), (1, -1)), (np.array([-1, 0, 5.0], dtype='int16'), [-1, 0, 5]), - (np.array([1, 0], dtype=np.int64), [1, 0])]) + (np.array([1, 0], dtype=np.int64), [1, 0]), + (pd.Series([1, 0], dtype=np.int64), [1, 0]), + (pd.Index([1, 0], dtype=np.int64), [1, 0])]) def test_coercion_aok_list(val, expected, validator_aok): v = validator_aok.validate_coerce(val) - if isinstance(val, np.ndarray): + if isinstance(val, (np.ndarray, pd.Series, pd.Index)): assert v.dtype == np.int32 assert np.array_equal(validator_aok.present(v), np.array(expected, dtype=np.int32)) @@ -132,6 +135,7 @@ def test_coercion_aok_list(val, expected, validator_aok): assert isinstance(v, list) assert validator_aok.present(v) == expected + # ### Rejection ### # @pytest.mark.parametrize('val', diff --git a/_plotly_utils/tests/validators/test_number_validator.py b/_plotly_utils/tests/validators/test_number_validator.py index 017e92432a0..32dc127e1d3 100644 --- a/_plotly_utils/tests/validators/test_number_validator.py +++ b/_plotly_utils/tests/validators/test_number_validator.py @@ -3,7 +3,7 @@ from _plotly_utils.basevalidators import NumberValidator import numpy as np - +import pandas as pd # Fixtures # -------- @@ -119,10 +119,12 @@ def test_acceptance_aok_list(val, validator_aok): @pytest.mark.parametrize('val,expected', [([1.0, 0], (1.0, 0)), (np.array([1, -1]), np.array([1.0, -1.0])), + (pd.Series([1, -1]), np.array([1.0, -1.0])), + (pd.Index([1, -1]), np.array([1.0, -1.0])), ((-0.1234, 0, -1), (-0.1234, 0.0, -1.0))]) def test_coercion_aok_list(val, expected, validator_aok): v = validator_aok.validate_coerce(val) - if isinstance(val, np.ndarray): + if isinstance(val, (np.ndarray, pd.Series, pd.Index)): assert v.dtype == 'float' assert np.array_equal(v, expected) else: From 153a1cae2891c214567fb1b2af5f29251794d99c Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sat, 1 Sep 2018 20:02:59 -0400 Subject: [PATCH 3/3] Preserve integer type in homogenous array (don't case to double) --- _plotly_utils/basevalidators.py | 5 ++++- _plotly_utils/tests/validators/test_number_validator.py | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/_plotly_utils/basevalidators.py b/_plotly_utils/basevalidators.py index cfe478e61dd..56011b4517c 100644 --- a/_plotly_utils/basevalidators.py +++ b/_plotly_utils/basevalidators.py @@ -93,7 +93,10 @@ def copy_to_readonly_numpy_array(v, dtype=None, force_numeric=False): v_list = [to_scalar_or_list(e) for e in v] new_v = np.array(v_list, order='C', dtype=dtype) elif v.dtype.kind in numeric_kinds: - new_v = np.ascontiguousarray(v.astype(dtype)) + if dtype: + new_v = np.ascontiguousarray(v.astype(dtype)) + else: + new_v = np.ascontiguousarray(v) else: new_v = v.copy() diff --git a/_plotly_utils/tests/validators/test_number_validator.py b/_plotly_utils/tests/validators/test_number_validator.py index 32dc127e1d3..92412bf7ba3 100644 --- a/_plotly_utils/tests/validators/test_number_validator.py +++ b/_plotly_utils/tests/validators/test_number_validator.py @@ -118,14 +118,13 @@ def test_acceptance_aok_list(val, validator_aok): # Coerced to general consistent numeric type @pytest.mark.parametrize('val,expected', [([1.0, 0], (1.0, 0)), - (np.array([1, -1]), np.array([1.0, -1.0])), - (pd.Series([1, -1]), np.array([1.0, -1.0])), - (pd.Index([1, -1]), np.array([1.0, -1.0])), + (np.array([1, -1]), np.array([1, -1])), + (pd.Series([1, -1]), np.array([1, -1])), + (pd.Index([1, -1]), np.array([1, -1])), ((-0.1234, 0, -1), (-0.1234, 0.0, -1.0))]) def test_coercion_aok_list(val, expected, validator_aok): v = validator_aok.validate_coerce(val) if isinstance(val, (np.ndarray, pd.Series, pd.Index)): - assert v.dtype == 'float' assert np.array_equal(v, expected) else: assert isinstance(v, list)