From 22dab2d14d3558518d6a40f6ff8844ab7193bee1 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Tue, 9 Oct 2018 19:18:47 +0200 Subject: [PATCH 01/41] DEPS: drop numpy < 1.12 --- ci/azure-macos-35.yaml | 2 +- ci/circle-27-compat.yaml | 2 +- ci/travis-27-locale.yaml | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 14 +++++++++ pandas/compat/numpy/__init__.py | 31 ++++++------------- pandas/core/algorithms.py | 11 +------ pandas/tests/arithmetic/test_period.py | 23 ++++---------- pandas/tests/frame/test_analytics.py | 4 --- pandas/tests/frame/test_quantile.py | 10 ++---- pandas/tests/indexes/datetimes/test_ops.py | 14 ++++----- pandas/tests/indexes/period/test_ops.py | 14 ++++----- .../indexes/period/test_partial_slicing.py | 14 ++++----- pandas/tests/indexes/timedeltas/test_ops.py | 15 ++++----- pandas/tests/series/test_analytics.py | 25 +++++++-------- pandas/tests/sparse/series/test_series.py | 20 ++++++------ pandas/tests/test_algos.py | 4 --- pandas/tests/test_expressions.py | 4 +-- pandas/tests/test_sorting.py | 5 ++- pandas/tests/test_window.py | 3 -- 20 files changed, 86 insertions(+), 133 deletions(-) diff --git a/ci/azure-macos-35.yaml b/ci/azure-macos-35.yaml index a36f748ded812..008f31173e780 100644 --- a/ci/azure-macos-35.yaml +++ b/ci/azure-macos-35.yaml @@ -11,7 +11,7 @@ dependencies: - matplotlib - nomkl - numexpr - - numpy=1.10.4 + - numpy=1.12.1 - openpyxl=2.5.5 - pytables - python=3.5* diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 84ec7e20fc8f1..473d060ee3e7f 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -7,7 +7,7 @@ dependencies: - cython=0.28.2 - jinja2=2.8 - numexpr=2.4.4 # we test that we correctly don't use an unsupported numexpr - - numpy=1.9.3 + - numpy=1.12.1 - openpyxl=2.5.5 - psycopg2 - pytables=3.2.2 diff --git a/ci/travis-27-locale.yaml b/ci/travis-27-locale.yaml index aca65f27d4187..ee29aff068b7d 100644 --- a/ci/travis-27-locale.yaml +++ b/ci/travis-27-locale.yaml @@ -7,7 +7,7 @@ dependencies: - cython=0.28.2 - lxml - matplotlib=1.4.3 - - numpy=1.9.3 + - numpy=1.12.1 - openpyxl=2.4.0 - python-dateutil - python-blosc diff --git a/doc/source/install.rst b/doc/source/install.rst index 7a846c817aee2..316a68a44f8c6 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -225,7 +225,7 @@ Dependencies ------------ * `setuptools `__: 24.2.0 or higher -* `NumPy `__: 1.9.0 or higher +* `NumPy `__: 1.12.0 or higher * `python-dateutil `__: 2.5.0 or higher * `pytz `__ diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index ca4ea8e366754..c0fdcbe73f269 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -199,8 +199,22 @@ Other Enhancements Backwards incompatible API changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + - A newly constructed empty :class:`DataFrame` with integer as the ``dtype`` will now only be cast to ``float64`` if ``index`` is specified (:issue:`22858`) +.. _whatsnew_0240.api_breaking.deps: + +Dependencies have increased minimum versions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We have updated our minimum supported versions of dependencies (:issue:`21242`). +We now require: + ++-----------------+-----------------+----------+---------------+ +| Package | Minimum Version | Required | Issue | ++=================+=================+==========+===============+ +| numpy | 1.12.0 | X | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: diff --git a/pandas/compat/numpy/__init__.py b/pandas/compat/numpy/__init__.py index a6f586c7f2638..43e12d145b49e 100644 --- a/pandas/compat/numpy/__init__.py +++ b/pandas/compat/numpy/__init__.py @@ -9,19 +9,16 @@ # numpy versioning _np_version = np.__version__ _nlv = LooseVersion(_np_version) -_np_version_under1p10 = _nlv < LooseVersion('1.10') -_np_version_under1p11 = _nlv < LooseVersion('1.11') -_np_version_under1p12 = _nlv < LooseVersion('1.12') _np_version_under1p13 = _nlv < LooseVersion('1.13') _np_version_under1p14 = _nlv < LooseVersion('1.14') _np_version_under1p15 = _nlv < LooseVersion('1.15') -if _nlv < '1.9': +if _nlv < '1.12': raise ImportError('this version of pandas is incompatible with ' - 'numpy < 1.9.0\n' + 'numpy < 1.12.0\n' 'your numpy version is {0}.\n' - 'Please upgrade numpy to >= 1.9.0 to use ' + 'Please upgrade numpy to >= 1.12.0 to use ' 'this pandas version'.format(_np_version)) @@ -43,9 +40,7 @@ def np_datetime64_compat(s, *args, **kwargs): tz-changes in 1.11 that make '2015-01-01 09:00:00Z' show a deprecation warning, when need to pass '2015-01-01 09:00:00' """ - - if not _np_version_under1p11: - s = tz_replacer(s) + s = tz_replacer(s) return np.datetime64(s, *args, **kwargs) @@ -56,23 +51,17 @@ def np_array_datetime64_compat(arr, *args, **kwargs): tz-changes in 1.11 that make '2015-01-01 09:00:00Z' show a deprecation warning, when need to pass '2015-01-01 09:00:00' """ - - if not _np_version_under1p11: - - # is_list_like - if hasattr(arr, '__iter__') and not \ - isinstance(arr, string_and_binary_types): - arr = [tz_replacer(s) for s in arr] - else: - arr = tz_replacer(arr) + # is_list_like + if hasattr(arr, '__iter__') and not \ + isinstance(arr, string_and_binary_types): + arr = [tz_replacer(s) for s in arr] + else: + arr = tz_replacer(arr) return np.array(arr, *args, **kwargs) __all__ = ['np', - '_np_version_under1p10', - '_np_version_under1p11', - '_np_version_under1p12', '_np_version_under1p13', '_np_version_under1p14', '_np_version_under1p15' diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index e91cc8ec1e996..44b3b885a67e8 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -30,7 +30,6 @@ ensure_platform_int, ensure_object, ensure_float64, ensure_uint64, ensure_int64) -from pandas.compat.numpy import _np_version_under1p10 from pandas.core.dtypes.missing import isna, na_value_for_dtype from pandas.core import common as com @@ -914,15 +913,7 @@ def _broadcast(arr_or_scalar, shape): """ Helper function to broadcast arrays / scalars to the desired shape. """ - if _np_version_under1p10: - if is_scalar(arr_or_scalar): - out = np.empty(shape) - out.fill(arr_or_scalar) - else: - out = arr_or_scalar - else: - out = np.broadcast_to(arr_or_scalar, shape) - return out + return np.broadcast_to(arr_or_scalar, shape) # For performance reasons, we broadcast 'b' to the new array 'b2' # so that it has the same size as 'arr'. diff --git a/pandas/tests/arithmetic/test_period.py b/pandas/tests/arithmetic/test_period.py index 3210290b9c5c8..9c8a2fafa0fdd 100644 --- a/pandas/tests/arithmetic/test_period.py +++ b/pandas/tests/arithmetic/test_period.py @@ -15,9 +15,7 @@ import pandas.core.indexes.period as period from pandas.core import ops -from pandas import ( - Period, PeriodIndex, period_range, Series, - _np_version_under1p10) +from pandas import Period, PeriodIndex, period_range, Series # ------------------------------------------------------------------ @@ -837,20 +835,14 @@ def test_pi_ops_errors(self, ng): with pytest.raises(TypeError): np.add(obj, ng) - if _np_version_under1p10: - assert np.add(ng, obj) is NotImplemented - else: - with pytest.raises(TypeError): - np.add(ng, obj) + with pytest.raises(TypeError): + np.add(ng, obj) with pytest.raises(TypeError): np.subtract(obj, ng) - if _np_version_under1p10: - assert np.subtract(ng, obj) is NotImplemented - else: - with pytest.raises(TypeError): - np.subtract(ng, obj) + with pytest.raises(TypeError): + np.subtract(ng, obj) def test_pi_ops_nat(self): idx = PeriodIndex(['2011-01', '2011-02', 'NaT', '2011-04'], @@ -954,10 +946,7 @@ def test_pi_sub_period(self): tm.assert_index_equal(result, exp) result = np.subtract(pd.Period('2012-01', freq='M'), idx) - if _np_version_under1p10: - assert result is NotImplemented - else: - tm.assert_index_equal(result, exp) + tm.assert_index_equal(result, exp) exp = pd.TimedeltaIndex([np.nan, np.nan, np.nan, np.nan], name='idx') tm.assert_index_equal(idx - pd.Period('NaT', freq='M'), exp) diff --git a/pandas/tests/frame/test_analytics.py b/pandas/tests/frame/test_analytics.py index 66bbc1f1a649b..124857d0a3d7f 100644 --- a/pandas/tests/frame/test_analytics.py +++ b/pandas/tests/frame/test_analytics.py @@ -15,7 +15,6 @@ from pandas.compat import lrange, PY35 from pandas import (compat, isna, notna, DataFrame, Series, MultiIndex, date_range, Timestamp, Categorical, - _np_version_under1p12, to_datetime, to_timedelta) import pandas as pd import pandas.core.nanops as nanops @@ -2021,9 +2020,6 @@ def test_dot(self): @pytest.mark.skipif(not PY35, reason='matmul supported for Python>=3.5') - @pytest.mark.xfail( - _np_version_under1p12, - reason="unpredictable return types under numpy < 1.12") def test_matmul(self): # matmul test is for GH 10259 a = DataFrame(np.random.randn(3, 4), index=['a', 'b', 'c'], diff --git a/pandas/tests/frame/test_quantile.py b/pandas/tests/frame/test_quantile.py index 2f264874378bc..3dbac79fed02b 100644 --- a/pandas/tests/frame/test_quantile.py +++ b/pandas/tests/frame/test_quantile.py @@ -6,7 +6,7 @@ import pytest import numpy as np -from pandas import (DataFrame, Series, Timestamp, _np_version_under1p11) +from pandas import DataFrame, Series, Timestamp import pandas as pd from pandas.util.testing import assert_series_equal, assert_frame_equal @@ -154,12 +154,8 @@ def test_quantile_interpolation(self): result = df.quantile([.25, .5], interpolation='midpoint') # https://github.com/numpy/numpy/issues/7163 - if _np_version_under1p11: - expected = DataFrame([[1.5, 1.5, 1.5], [2.5, 2.5, 2.5]], - index=[.25, .5], columns=['a', 'b', 'c']) - else: - expected = DataFrame([[1.5, 1.5, 1.5], [2.0, 2.0, 2.0]], - index=[.25, .5], columns=['a', 'b', 'c']) + expected = DataFrame([[1.5, 1.5, 1.5], [2.0, 2.0, 2.0]], + index=[.25, .5], columns=['a', 'b', 'c']) assert_frame_equal(result, expected) def test_quantile_multi(self): diff --git a/pandas/tests/indexes/datetimes/test_ops.py b/pandas/tests/indexes/datetimes/test_ops.py index b60b222d095b9..9ce77326d37b7 100644 --- a/pandas/tests/indexes/datetimes/test_ops.py +++ b/pandas/tests/indexes/datetimes/test_ops.py @@ -7,8 +7,7 @@ import pandas._libs.tslib as tslib import pandas.util.testing as tm from pandas import (DatetimeIndex, PeriodIndex, Series, Timestamp, - date_range, _np_version_under1p10, Index, - bdate_range) + date_range, bdate_range, Index) from pandas.tseries.offsets import BMonthEnd, CDay, BDay, Day, Hour from pandas.tests.test_base import Ops from pandas.core.dtypes.generic import ABCDateOffset @@ -89,12 +88,11 @@ def test_numpy_minmax(self): assert np.argmin(dr) == 0 assert np.argmax(dr) == 5 - if not _np_version_under1p10: - errmsg = "the 'out' parameter is not supported" - tm.assert_raises_regex( - ValueError, errmsg, np.argmin, dr, out=0) - tm.assert_raises_regex( - ValueError, errmsg, np.argmax, dr, out=0) + errmsg = "the 'out' parameter is not supported" + tm.assert_raises_regex( + ValueError, errmsg, np.argmin, dr, out=0) + tm.assert_raises_regex( + ValueError, errmsg, np.argmax, dr, out=0) def test_repeat_range(self, tz_naive_fixture): tz = tz_naive_fixture diff --git a/pandas/tests/indexes/period/test_ops.py b/pandas/tests/indexes/period/test_ops.py index 85aa3f6a38fb3..a59efe57f83c4 100644 --- a/pandas/tests/indexes/period/test_ops.py +++ b/pandas/tests/indexes/period/test_ops.py @@ -5,8 +5,7 @@ import pandas as pd import pandas._libs.tslib as tslib import pandas.util.testing as tm -from pandas import (DatetimeIndex, PeriodIndex, Series, Period, - _np_version_under1p10, Index) +from pandas import DatetimeIndex, PeriodIndex, Series, Period, Index from pandas.tests.test_base import Ops @@ -73,12 +72,11 @@ def test_numpy_minmax(self): assert np.argmin(pr) == 0 assert np.argmax(pr) == 5 - if not _np_version_under1p10: - errmsg = "the 'out' parameter is not supported" - tm.assert_raises_regex( - ValueError, errmsg, np.argmin, pr, out=0) - tm.assert_raises_regex( - ValueError, errmsg, np.argmax, pr, out=0) + errmsg = "the 'out' parameter is not supported" + tm.assert_raises_regex( + ValueError, errmsg, np.argmin, pr, out=0) + tm.assert_raises_regex( + ValueError, errmsg, np.argmax, pr, out=0) def test_resolution(self): for freq, expected in zip(['A', 'Q', 'M', 'D', 'H', diff --git a/pandas/tests/indexes/period/test_partial_slicing.py b/pandas/tests/indexes/period/test_partial_slicing.py index 6d142722c315a..58504f2a91d7b 100644 --- a/pandas/tests/indexes/period/test_partial_slicing.py +++ b/pandas/tests/indexes/period/test_partial_slicing.py @@ -5,7 +5,7 @@ import pandas as pd from pandas.util import testing as tm from pandas import (Series, period_range, DatetimeIndex, PeriodIndex, - DataFrame, _np_version_under1p12, Period) + DataFrame, Period) class TestPeriodIndex(object): @@ -68,16 +68,15 @@ def test_range_slice_day(self): didx = DatetimeIndex(start='2013/01/01', freq='D', periods=400) pidx = PeriodIndex(start='2013/01/01', freq='D', periods=400) - # changed to TypeError in 1.12 + # exception changed to TypeError in 1.12 # https://github.com/numpy/numpy/pull/6271 - exc = IndexError if _np_version_under1p12 else TypeError for idx in [didx, pidx]: # slices against index should raise IndexError values = ['2014', '2013/02', '2013/01/02', '2013/02/01 9H', '2013/02/01 09:00'] for v in values: - with pytest.raises(exc): + with pytest.raises(TypeError): idx[v:] s = Series(np.random.rand(len(idx)), index=idx) @@ -89,7 +88,7 @@ def test_range_slice_day(self): invalid = ['2013/02/01 9H', '2013/02/01 09:00'] for v in invalid: - with pytest.raises(exc): + with pytest.raises(TypeError): idx[v:] def test_range_slice_seconds(self): @@ -98,16 +97,15 @@ def test_range_slice_seconds(self): periods=4000) pidx = PeriodIndex(start='2013/01/01 09:00:00', freq='S', periods=4000) - # changed to TypeError in 1.12 + # exception changed to TypeError in 1.12 # https://github.com/numpy/numpy/pull/6271 - exc = IndexError if _np_version_under1p12 else TypeError for idx in [didx, pidx]: # slices against index should raise IndexError values = ['2014', '2013/02', '2013/01/02', '2013/02/01 9H', '2013/02/01 09:00'] for v in values: - with pytest.raises(exc): + with pytest.raises(TypeError): idx[v:] s = Series(np.random.rand(len(idx)), index=idx) diff --git a/pandas/tests/indexes/timedeltas/test_ops.py b/pandas/tests/indexes/timedeltas/test_ops.py index d7bdd18f48523..9f8a3e893c3de 100644 --- a/pandas/tests/indexes/timedeltas/test_ops.py +++ b/pandas/tests/indexes/timedeltas/test_ops.py @@ -5,10 +5,8 @@ import pandas as pd import pandas.util.testing as tm -from pandas import to_timedelta from pandas import (Series, Timedelta, Timestamp, TimedeltaIndex, - timedelta_range, - _np_version_under1p10) + timedelta_range, to_timedelta) from pandas._libs.tslib import iNaT from pandas.tests.test_base import Ops from pandas.tseries.offsets import Day, Hour @@ -68,12 +66,11 @@ def test_numpy_minmax(self): assert np.argmin(td) == 0 assert np.argmax(td) == 5 - if not _np_version_under1p10: - errmsg = "the 'out' parameter is not supported" - tm.assert_raises_regex( - ValueError, errmsg, np.argmin, td, out=0) - tm.assert_raises_regex( - ValueError, errmsg, np.argmax, td, out=0) + errmsg = "the 'out' parameter is not supported" + tm.assert_raises_regex( + ValueError, errmsg, np.argmin, td, out=0) + tm.assert_raises_regex( + ValueError, errmsg, np.argmax, td, out=0) def test_value_counts_unique(self): # GH 7735 diff --git a/pandas/tests/series/test_analytics.py b/pandas/tests/series/test_analytics.py index 58a160d17cbe8..1ec18597b4365 100644 --- a/pandas/tests/series/test_analytics.py +++ b/pandas/tests/series/test_analytics.py @@ -11,8 +11,7 @@ import pandas as pd from pandas import (Series, Categorical, DataFrame, isna, notna, - bdate_range, date_range, _np_version_under1p10, - CategoricalIndex) + bdate_range, date_range, CategoricalIndex) from pandas.core.index import MultiIndex from pandas.core.indexes.datetimes import Timestamp from pandas.core.indexes.timedeltas import Timedelta @@ -1246,12 +1245,11 @@ def test_numpy_argmin_deprecated(self): assert result == 1 - if not _np_version_under1p10: - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False): - msg = "the 'out' parameter is not supported" - tm.assert_raises_regex(ValueError, msg, np.argmin, - s, out=data) + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False): + msg = "the 'out' parameter is not supported" + tm.assert_raises_regex(ValueError, msg, np.argmin, + s, out=data) def test_idxmax(self): # test idxmax @@ -1315,12 +1313,11 @@ def test_numpy_argmax_deprecated(self): assert result == 10 - if not _np_version_under1p10: - with tm.assert_produces_warning(FutureWarning, - check_stacklevel=False): - msg = "the 'out' parameter is not supported" - tm.assert_raises_regex(ValueError, msg, np.argmax, - s, out=data) + with tm.assert_produces_warning(FutureWarning, + check_stacklevel=False): + msg = "the 'out' parameter is not supported" + tm.assert_raises_regex(ValueError, msg, np.argmax, + s, out=data) def test_ptp(self): # GH21614 diff --git a/pandas/tests/sparse/series/test_series.py b/pandas/tests/sparse/series/test_series.py index 5b50606bf37bd..c0f7dd4493d90 100644 --- a/pandas/tests/sparse/series/test_series.py +++ b/pandas/tests/sparse/series/test_series.py @@ -9,8 +9,7 @@ import numpy as np import pandas as pd -from pandas import (Series, DataFrame, bdate_range, - isna, compat, _np_version_under1p12) +from pandas import Series, DataFrame, bdate_range, isna, compat from pandas.tseries.offsets import BDay import pandas.util.testing as tm import pandas.util._test_decorators as td @@ -551,17 +550,16 @@ def test_numpy_take(self): sp = SparseSeries([1.0, 2.0, 3.0]) indices = [1, 2] - if not _np_version_under1p12: - tm.assert_series_equal(np.take(sp, indices, axis=0).to_dense(), - np.take(sp.to_dense(), indices, axis=0)) + tm.assert_series_equal(np.take(sp, indices, axis=0).to_dense(), + np.take(sp.to_dense(), indices, axis=0)) - msg = "the 'out' parameter is not supported" - tm.assert_raises_regex(ValueError, msg, np.take, - sp, indices, out=np.empty(sp.shape)) + msg = "the 'out' parameter is not supported" + tm.assert_raises_regex(ValueError, msg, np.take, + sp, indices, out=np.empty(sp.shape)) - msg = "the 'mode' parameter is not supported" - tm.assert_raises_regex(ValueError, msg, np.take, - sp, indices, out=None, mode='clip') + msg = "the 'mode' parameter is not supported" + tm.assert_raises_regex(ValueError, msg, np.take, + sp, indices, out=None, mode='clip') def test_setitem(self): self.bseries[5] = 7. diff --git a/pandas/tests/test_algos.py b/pandas/tests/test_algos.py index b2ddbf715b480..f0bda95e6cebc 100644 --- a/pandas/tests/test_algos.py +++ b/pandas/tests/test_algos.py @@ -224,10 +224,6 @@ def test_factorize_tuple_list(self, data, expected_label, expected_level): def test_complex_sorting(self): # gh 12666 - check no segfault - # Test not valid numpy versions older than 1.11 - if pd._np_version_under1p11: - pytest.skip("Test valid only for numpy 1.11+") - x17 = np.array([complex(i) for i in range(17)], dtype=object) pytest.raises(TypeError, algos.factorize, x17[::-1], sort=True) diff --git a/pandas/tests/test_expressions.py b/pandas/tests/test_expressions.py index c101fd25ce5e5..f6bcfbfa3f951 100644 --- a/pandas/tests/test_expressions.py +++ b/pandas/tests/test_expressions.py @@ -13,7 +13,7 @@ from pandas.core.api import DataFrame, Panel from pandas.core.computation import expressions as expr -from pandas import compat, _np_version_under1p11, _np_version_under1p13 +from pandas import compat, _np_version_under1p13 from pandas.util.testing import (assert_almost_equal, assert_series_equal, assert_frame_equal, assert_panel_equal) from pandas.io.formats.printing import pprint_thing @@ -275,7 +275,7 @@ def testit(): # numpy >= 1.11 doesn't handle integers # raised to integer powers # https://github.com/pandas-dev/pandas/issues/15363 - if op == 'pow' and not _np_version_under1p11: + if op == 'pow': continue if op == 'div': diff --git a/pandas/tests/test_sorting.py b/pandas/tests/test_sorting.py index 98026f6d4cf0e..aa5d0016eca95 100644 --- a/pandas/tests/test_sorting.py +++ b/pandas/tests/test_sorting.py @@ -7,8 +7,7 @@ import numpy as np from numpy import nan from pandas.core import common as com -from pandas import (DataFrame, MultiIndex, merge, concat, Series, compat, - _np_version_under1p10) +from pandas import DataFrame, MultiIndex, merge, concat, Series, compat from pandas.util import testing as tm from pandas.util.testing import assert_frame_equal, assert_series_equal from pandas.core.sorting import (is_int64_overflow_possible, @@ -416,7 +415,7 @@ def test_mixed_integer_from_list(self): def test_unsortable(self): # GH 13714 arr = np.array([1, 2, datetime.now(), 0, 3], dtype=object) - if compat.PY2 and not _np_version_under1p10: + if compat.PY2: # RuntimeWarning: tp_compare didn't return -1 or -2 for exception with warnings.catch_warnings(): pytest.raises(TypeError, safe_sort, arr) diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index cc663fc59cbf1..4b0c4d581a008 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -7,7 +7,6 @@ from datetime import datetime, timedelta from numpy.random import randn import numpy as np -from pandas import _np_version_under1p12 import pandas as pd from pandas import (Series, DataFrame, bdate_range, @@ -1292,8 +1291,6 @@ def test_rolling_quantile_np_percentile(self): tm.assert_almost_equal(df_quantile.values, np.array(np_percentile)) - @pytest.mark.skipif(_np_version_under1p12, - reason='numpy midpoint interpolation is broken') @pytest.mark.parametrize('quantile', [0.0, 0.1, 0.45, 0.5, 1]) @pytest.mark.parametrize('interpolation', ['linear', 'lower', 'higher', 'nearest', 'midpoint']) From a495db9a694447ad6b5e37514911720627a79d48 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Tue, 9 Oct 2018 22:28:04 +0200 Subject: [PATCH 02/41] Drop bottleneck < 1.2.0 --- ci/circle-27-compat.yaml | 2 +- ci/travis-27-locale.yaml | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 473d060ee3e7f..0e4d1bf9052f7 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -3,7 +3,7 @@ channels: - defaults - conda-forge dependencies: - - bottleneck=1.0.0 + - bottleneck=1.2.0 - cython=0.28.2 - jinja2=2.8 - numexpr=2.4.4 # we test that we correctly don't use an unsupported numexpr diff --git a/ci/travis-27-locale.yaml b/ci/travis-27-locale.yaml index ee29aff068b7d..247fcd9098baf 100644 --- a/ci/travis-27-locale.yaml +++ b/ci/travis-27-locale.yaml @@ -3,7 +3,7 @@ channels: - defaults - conda-forge dependencies: - - bottleneck=1.0.0 + - bottleneck=1.2.0 - cython=0.28.2 - lxml - matplotlib=1.4.3 diff --git a/doc/source/install.rst b/doc/source/install.rst index 316a68a44f8c6..769e3ee885778 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -240,7 +240,7 @@ Recommended Dependencies * `bottleneck `__: for accelerating certain types of ``nan`` evaluations. ``bottleneck`` uses specialized cython routines to achieve large speedups. If installed, - must be Version 1.0.0 or higher. + must be Version 1.2.0 or higher. .. note:: diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index c0fdcbe73f269..714c48c850158 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -208,13 +208,15 @@ Dependencies have increased minimum versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We have updated our minimum supported versions of dependencies (:issue:`21242`). -We now require: +If installed, we now require: +-----------------+-----------------+----------+---------------+ | Package | Minimum Version | Required | Issue | +=================+=================+==========+===============+ | numpy | 1.12.0 | X | :issue:`21242`| +-----------------+-----------------+----------+---------------+ +| bottleneck | 1.2.0 | | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: From 124d5112775a9f672f3843b090ab9159c04a2c68 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Tue, 9 Oct 2018 23:18:30 +0200 Subject: [PATCH 03/41] Drop matplotlib < 2.0.0 --- ci/azure-macos-35.yaml | 2 +- ci/circle-27-compat.yaml | 2 +- ci/travis-27-locale.yaml | 4 ++-- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 ++ 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ci/azure-macos-35.yaml b/ci/azure-macos-35.yaml index 008f31173e780..bbe578b858a07 100644 --- a/ci/azure-macos-35.yaml +++ b/ci/azure-macos-35.yaml @@ -11,7 +11,7 @@ dependencies: - matplotlib - nomkl - numexpr - - numpy=1.12.1 + - numpy=1.12.0 - openpyxl=2.5.5 - pytables - python=3.5* diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 0e4d1bf9052f7..498ff284830fd 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -7,7 +7,7 @@ dependencies: - cython=0.28.2 - jinja2=2.8 - numexpr=2.4.4 # we test that we correctly don't use an unsupported numexpr - - numpy=1.12.1 + - numpy=1.12.0 - openpyxl=2.5.5 - psycopg2 - pytables=3.2.2 diff --git a/ci/travis-27-locale.yaml b/ci/travis-27-locale.yaml index 247fcd9098baf..dc5580ae6d287 100644 --- a/ci/travis-27-locale.yaml +++ b/ci/travis-27-locale.yaml @@ -6,8 +6,8 @@ dependencies: - bottleneck=1.2.0 - cython=0.28.2 - lxml - - matplotlib=1.4.3 - - numpy=1.12.1 + - matplotlib=2.0.0 + - numpy=1.12.0 - openpyxl=2.4.0 - python-dateutil - python-blosc diff --git a/doc/source/install.rst b/doc/source/install.rst index 769e3ee885778..66563dcce6567 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -266,7 +266,7 @@ Optional Dependencies * `pymysql `__: for MySQL. * `SQLite `__: for SQLite, this is included in Python's standard library by default. -* `matplotlib `__: for plotting, Version 1.4.3 or higher. +* `matplotlib `__: for plotting, Version 2.0.0 or higher. * For Excel I/O: * `xlrd/xlwt `__: Excel reading (xlrd) and writing (xlwt) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 714c48c850158..2ee82bff37460 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -217,6 +217,8 @@ If installed, we now require: +-----------------+-----------------+----------+---------------+ | bottleneck | 1.2.0 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ +| matplotlib | 2.0.0 | | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: From 12b9a79222af9f318ac30478743d9903057bfcab Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 01:01:09 +0200 Subject: [PATCH 04/41] Drop numexpr < 2.6.2 --- ci/circle-27-compat.yaml | 2 +- ci/requirements-optional-conda.txt | 6 +++--- ci/requirements-optional-pip.txt | 6 +++--- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 ++ 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 498ff284830fd..460e31bb66829 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -6,7 +6,7 @@ dependencies: - bottleneck=1.2.0 - cython=0.28.2 - jinja2=2.8 - - numexpr=2.4.4 # we test that we correctly don't use an unsupported numexpr + - numexpr=2.6.2 - numpy=1.12.0 - openpyxl=2.5.5 - psycopg2 diff --git a/ci/requirements-optional-conda.txt b/ci/requirements-optional-conda.txt index 376fdb1e14e3a..dfea57923782f 100644 --- a/ci/requirements-optional-conda.txt +++ b/ci/requirements-optional-conda.txt @@ -1,6 +1,6 @@ beautifulsoup4>=4.2.1 blosc -bottleneck +bottleneck>=1.2.0 fastparquet feather-format gcsfs @@ -9,9 +9,9 @@ ipython>=5.6.0 ipykernel jinja2 lxml -matplotlib +matplotlib>=2.0.0 nbsphinx -numexpr +numexpr>=2.6.2 openpyxl=2.5.5 pyarrow pymysql diff --git a/ci/requirements-optional-pip.txt b/ci/requirements-optional-pip.txt index 09ce8e59a3b46..978869aabc5a7 100644 --- a/ci/requirements-optional-pip.txt +++ b/ci/requirements-optional-pip.txt @@ -2,7 +2,7 @@ # Do not modify directly beautifulsoup4>=4.2.1 blosc -bottleneck +bottleneck>=1.2.0 fastparquet feather-format gcsfs @@ -11,9 +11,9 @@ ipython>=5.6.0 ipykernel jinja2 lxml -matplotlib +matplotlib>=2.0.0 nbsphinx -numexpr +numexpr>=2.6.2 openpyxl==2.5.5 pyarrow pymysql diff --git a/doc/source/install.rst b/doc/source/install.rst index 66563dcce6567..db925cea713a1 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -236,7 +236,7 @@ Recommended Dependencies * `numexpr `__: for accelerating certain numerical operations. ``numexpr`` uses multiple cores as well as smart chunking and caching to achieve large speedups. - If installed, must be Version 2.4.6 or higher. + If installed, must be Version 2.6.2 or higher. * `bottleneck `__: for accelerating certain types of ``nan`` evaluations. ``bottleneck`` uses specialized cython routines to achieve large speedups. If installed, diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 2ee82bff37460..9786aee7f35e6 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -219,6 +219,8 @@ If installed, we now require: +-----------------+-----------------+----------+---------------+ | matplotlib | 2.0.0 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ +| numexpr | 2.6.2 | | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: From c8bfe660c61b8772ad4340568ead97a117e20790 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 01:07:12 +0200 Subject: [PATCH 05/41] Remove mpl compat code --- pandas/plotting/_compat.py | 8 - pandas/plotting/_converter.py | 9 - pandas/plotting/_core.py | 35 +--- pandas/plotting/_style.py | 17 +- pandas/tests/plotting/common.py | 43 +---- pandas/tests/plotting/test_boxplot_method.py | 15 +- pandas/tests/plotting/test_datetimelike.py | 93 +++------- pandas/tests/plotting/test_frame.py | 183 +++++++------------ pandas/tests/plotting/test_hist_method.py | 2 +- pandas/tests/plotting/test_misc.py | 10 +- pandas/tests/plotting/test_series.py | 52 ++---- pandas/util/_test_decorators.py | 13 -- 12 files changed, 130 insertions(+), 350 deletions(-) diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index 5032b259e9831..ee8ff0b760c2e 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -18,14 +18,6 @@ def inner(): return inner -_mpl_ge_1_2_1 = _mpl_version('1.2.1', operator.ge) -_mpl_le_1_2_1 = _mpl_version('1.2.1', operator.le) -_mpl_ge_1_3_1 = _mpl_version('1.3.1', operator.ge) -_mpl_ge_1_4_0 = _mpl_version('1.4.0', operator.ge) -_mpl_ge_1_4_1 = _mpl_version('1.4.1', operator.ge) -_mpl_ge_1_5_0 = _mpl_version('1.5.0', operator.ge) -_mpl_ge_2_0_0 = _mpl_version('2.0.0', operator.ge) -_mpl_le_2_0_0 = _mpl_version('2.0.0', operator.le) _mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) _mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) _mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) diff --git a/pandas/plotting/_converter.py b/pandas/plotting/_converter.py index 96ea8a542a451..fe773a6054db5 100644 --- a/pandas/plotting/_converter.py +++ b/pandas/plotting/_converter.py @@ -35,8 +35,6 @@ from pandas.tseries.frequencies import FreqGroup from pandas.core.indexes.period import Period, PeriodIndex -from pandas.plotting._compat import _mpl_le_2_0_0 - # constants HOURS_PER_DAY = 24. MIN_PER_HOUR = 60. @@ -371,13 +369,6 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): if self._tz is dates.UTC: self._tz._utcoffset = self._tz.utcoffset(None) - # For mpl > 2.0 the format strings are controlled via rcparams - # so do not mess with them. For mpl < 2.0 change the second - # break point and add a musec break point - if _mpl_le_2_0_0(): - self.scaled[1. / SEC_PER_DAY] = '%H:%M:%S' - self.scaled[1. / MUSEC_PER_DAY] = '%H:%M:%S.%f' - class PandasAutoDateLocator(dates.AutoDateLocator): diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 77c97412bd3d7..7db958e5baca7 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -30,10 +30,7 @@ from pandas.io.formats.printing import pprint_thing -from pandas.plotting._compat import (_mpl_ge_1_3_1, - _mpl_ge_1_5_0, - _mpl_ge_2_0_0, - _mpl_ge_3_0_0) +from pandas.plotting._compat import _mpl_ge_3_0_0 from pandas.plotting._style import (plot_params, _get_standard_colors) from pandas.plotting._tools import (_subplots, _flatten, table, @@ -551,14 +548,6 @@ def plt(self): import matplotlib.pyplot as plt return plt - @staticmethod - def mpl_ge_1_3_1(): - return _mpl_ge_1_3_1() - - @staticmethod - def mpl_ge_1_5_0(): - return _mpl_ge_1_5_0() - _need_to_set_index = False def _get_xticks(self, convert_period=False): @@ -908,8 +897,7 @@ def _make_plot(self): scatter = ax.scatter(data[x].values, data[y].values, c=c_values, label=label, cmap=cmap, **self.kwds) if cb: - if self.mpl_ge_1_3_1(): - cbar_label = c if c_is_column else '' + cbar_label = c if c_is_column else '' self._plot_colorbar(ax, label=cbar_label) if label is not None: @@ -1012,10 +1000,9 @@ def _make_plot(self): **kwds) self._add_legend_handle(newlines[0], label, index=i) - if not _mpl_ge_2_0_0(): - lines = _get_all_lines(ax) - left, right = _get_xlim(lines) - ax.set_xlim(left, right) + lines = _get_all_lines(ax) + left, right = _get_xlim(lines) + ax.set_xlim(left, right) @classmethod def _plot(cls, ax, x, y, style=None, column_num=None, @@ -1141,8 +1128,7 @@ def _plot(cls, ax, x, y, style=None, column_num=None, # need to remove label, because subplots uses mpl legend as it is line_kwds = kwds.copy() - if cls.mpl_ge_1_5_0(): - line_kwds.pop('label') + line_kwds.pop('label') lines = MPLPlot._plot(ax, x, y_values, style=style, **line_kwds) # get data from the line to get coordinates for fill_between @@ -1165,17 +1151,10 @@ def _plot(cls, ax, x, y, style=None, column_num=None, cls._update_stacker(ax, stacking_id, y) # LinePlot expects list of artists - res = [rect] if cls.mpl_ge_1_5_0() else lines + res = [rect] return res def _add_legend_handle(self, handle, label, index=None): - if not self.mpl_ge_1_5_0(): - from matplotlib.patches import Rectangle - # Because fill_between isn't supported in legend, - # specifically add Rectangle handle here - alpha = self.kwds.get('alpha', None) - handle = Rectangle((0, 0), 1, 1, fc=handle.get_color(), - alpha=alpha) LinePlot._add_legend_handle(self, handle, label, index=index) def _post_plot_logic(self, ax, data): diff --git a/pandas/plotting/_style.py b/pandas/plotting/_style.py index c72e092c73aa2..9bc12d22e1685 100644 --- a/pandas/plotting/_style.py +++ b/pandas/plotting/_style.py @@ -4,14 +4,12 @@ import warnings from contextlib import contextmanager -import re import numpy as np from pandas.core.dtypes.common import is_list_like from pandas.compat import lrange, lmap import pandas.compat as compat -from pandas.plotting._compat import _mpl_ge_2_0_0 def _get_standard_colors(num_colors=None, colormap=None, color_type='default', @@ -72,18 +70,9 @@ def _maybe_valid_colors(colors): # check whether each character can be convertible to colors maybe_color_cycle = _maybe_valid_colors(list(colors)) if maybe_single_color and maybe_color_cycle and len(colors) > 1: - # Special case for single str 'CN' match and convert to hex - # for supporting matplotlib < 2.0.0 - if re.match(r'\AC[0-9]\Z', colors) and _mpl_ge_2_0_0(): - hex_color = [c['color'] - for c in list(plt.rcParams['axes.prop_cycle'])] - colors = [hex_color[int(colors[1])]] - else: - # this may no longer be required - msg = ("'{0}' can be parsed as both single color and " - "color cycle. Specify each color using a list " - "like ['{0}'] or {1}") - raise ValueError(msg.format(colors, list(colors))) + hex_color = [c['color'] + for c in list(plt.rcParams['axes.prop_cycle'])] + colors = [hex_color[int(colors[1])]] elif maybe_single_color: colors = [colors] else: diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 5c88926828fa6..9495be2f404ee 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -39,7 +39,7 @@ def _ok_for_gaussian_kde(kind): except ImportError: return False - return plotting._compat._mpl_ge_1_5_0() + return True @td.skip_if_no_mpl @@ -50,31 +50,14 @@ def setup_method(self, method): import matplotlib as mpl mpl.rcdefaults() - self.mpl_le_1_2_1 = plotting._compat._mpl_le_1_2_1() - self.mpl_ge_1_3_1 = plotting._compat._mpl_ge_1_3_1() - self.mpl_ge_1_4_0 = plotting._compat._mpl_ge_1_4_0() - self.mpl_ge_1_5_0 = plotting._compat._mpl_ge_1_5_0() - self.mpl_ge_2_0_0 = plotting._compat._mpl_ge_2_0_0() self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() - if self.mpl_ge_1_4_0: - self.bp_n_objects = 7 - else: - self.bp_n_objects = 8 - if self.mpl_ge_1_5_0: - # 1.5 added PolyCollections to legend handler - # so we have twice as many items. - self.polycollection_factor = 2 - else: - self.polycollection_factor = 1 - - if self.mpl_ge_2_0_0: - self.default_figsize = (6.4, 4.8) - else: - self.default_figsize = (8.0, 6.0) - self.default_tick_position = 'left' if self.mpl_ge_2_0_0 else 'default' + self.bp_n_objects = 7 + self.polycollection_factor = 2 + self.default_figsize = (6.4, 4.8) + self.default_tick_position = 'left' n = 100 with tm.RNGContext(42): @@ -462,7 +445,7 @@ def _check_box_return_type(self, returned, return_type, expected_keys=None, assert isinstance(value.lines, dict) elif return_type == 'dict': line = value['medians'][0] - axes = line.axes if self.mpl_ge_1_5_0 else line.get_axes() + axes = line.axes if check_ax_title: assert axes.get_title() == key else: @@ -510,20 +493,6 @@ def is_grid_on(): obj.plot(kind=kind, grid=True, **kws) assert is_grid_on() - def _maybe_unpack_cycler(self, rcParams, field='color'): - """ - Compat layer for MPL 1.5 change to color cycle - - Before: plt.rcParams['axes.color_cycle'] -> ['b', 'g', 'r'...] - After : plt.rcParams['axes.prop_cycle'] -> cycler(...) - """ - if self.mpl_ge_1_5_0: - cyl = rcParams['axes.prop_cycle'] - colors = [v[field] for v in cyl] - else: - colors = rcParams['axes.color_cycle'] - return colors - def _check_plot_works(f, filterwarnings='always', **kwargs): import matplotlib.pyplot as plt diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index 7661b46a79061..e89584ca35d94 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -3,7 +3,6 @@ import pytest import itertools import string -from distutils.version import LooseVersion from pandas import Series, DataFrame, MultiIndex from pandas.compat import range, lzip @@ -21,15 +20,6 @@ """ Test cases for .boxplot method """ -def _skip_if_mpl_14_or_dev_boxplot(): - # GH 8382 - # Boxplot failures on 1.4 and 1.4.1 - # Don't need try / except since that's done at class level - import matplotlib - if LooseVersion(matplotlib.__version__) >= LooseVersion('1.4'): - pytest.skip("Matplotlib Regression in 1.4 and current dev.") - - @td.skip_if_no_mpl class TestDataFramePlots(TestPlotBase): @@ -71,12 +61,12 @@ def test_boxplot_legacy2(self): # passed ax should be used: fig, ax = self.plt.subplots() axes = df.boxplot('Col1', by='X', ax=ax) - ax_axes = ax.axes if self.mpl_ge_1_5_0 else ax.get_axes() + ax_axes = ax.axes assert ax_axes is axes fig, ax = self.plt.subplots() axes = df.groupby('Y').boxplot(ax=ax, return_type='axes') - ax_axes = ax.axes if self.mpl_ge_1_5_0 else ax.get_axes() + ax_axes = ax.axes assert ax_axes is axes['A'] # Multiple columns with an ax argument should use same figure @@ -155,7 +145,6 @@ def _check_ax_limits(col, ax): @pytest.mark.slow def test_boxplot_empty_column(self): - _skip_if_mpl_14_or_dev_boxplot() df = DataFrame(np.random.randn(20, 4)) df.loc[:, 0] = np.nan _check_plot_works(df.boxplot, return_type='axes') diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index de6f6b931987c..6df1bdc14528b 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -135,7 +135,7 @@ def f(*args, **kwds): _, ax = self.plt.subplots() ts.plot(style='k', ax=ax) - color = (0., 0., 0., 1) if self.mpl_ge_2_0_0 else (0., 0., 0.) + color = (0., 0., 0., 1) assert color == ax.get_lines()[0].get_color() def test_both_style_and_color(self): @@ -403,11 +403,8 @@ def test_get_finder(self): def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] - if self.mpl_ge_2_0_0: - xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] - xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] - else: - xpl1 = xpl2 = [Period('1999-1-1', freq='B').ordinal] * len(day_lst) + xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] + xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] for i, n in enumerate(day_lst): xp = xpl1[i] @@ -429,11 +426,8 @@ def test_finder_daily(self): def test_finder_quarterly(self): yrs = [3.5, 11] - if self.mpl_ge_2_0_0: - xpl1 = [68, 68] - xpl2 = [72, 68] - else: - xpl1 = xpl2 = [Period('1988Q1').ordinal] * len(yrs) + xpl1 = [68, 68] + xpl2 = [72, 68] for i, n in enumerate(yrs): xp = xpl1[i] @@ -455,11 +449,8 @@ def test_finder_quarterly(self): def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] - if self.mpl_ge_2_0_0: - xpl1 = [216, 216, 204, 204] - xpl2 = [216, 216, 216, 204] - else: - xpl1 = xpl2 = [Period('Jan 1988').ordinal] * len(yrs) + xpl1 = [216, 216, 204, 204] + xpl2 = [216, 216, 216, 204] for i, n in enumerate(yrs): xp = xpl1[i] @@ -489,10 +480,7 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): - if self.mpl_ge_2_0_0: - xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] - else: - xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] + xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] for i, nyears in enumerate([5, 10, 19, 49, 99, 199, 599, 1001]): rng = period_range('1987', periods=nyears, freq='A') @@ -513,10 +501,7 @@ def test_finder_minutely(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_0_0: - xp = Period('1998-12-29 12:00', freq='Min').ordinal - else: - xp = Period('1/1/1999', freq='Min').ordinal + xp = Period('1998-12-29 12:00', freq='Min').ordinal assert rs == xp def test_finder_hourly(self): @@ -527,13 +512,9 @@ def test_finder_hourly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_0_0: - xp = Period('1998-12-31 22:00', freq='H').ordinal - else: - xp = Period('1/1/1999', freq='H').ordinal + xp = Period('1998-12-31 22:00', freq='H').ordinal assert rs == xp - @td.skip_if_mpl_1_5 @pytest.mark.slow def test_gaps(self): ts = tm.makeTimeSeries() @@ -578,7 +559,6 @@ def test_gaps(self): mask = data.mask assert mask[2:5, 1].all() - @td.skip_if_mpl_1_5 @pytest.mark.slow def test_gap_upsample(self): low = tm.makeTimeSeries() @@ -659,8 +639,6 @@ def test_secondary_y_ts(self): @pytest.mark.slow @td.skip_if_no_scipy def test_secondary_kde(self): - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") _skip_if_no_scipy_gaussian_kde() ser = Series(np.random.randn(10)) @@ -1363,14 +1341,10 @@ def test_format_timedelta_ticks_narrow(self): expected_labels = (['-1 days 23:59:59.999999998'] + ['00:00:00.0000000{:0>2d}'.format(2 * i) for i in range(6)]) - elif self.mpl_ge_2_0_0: + else: expected_labels = [''] + [ '00:00:00.00000000{:d}'.format(2 * i) for i in range(5)] + [''] - else: - expected_labels = [ - '00:00:00.00000000{:d}'.format(i) - for i in range(10)] rng = timedelta_range('0', periods=10, freq='ns') df = DataFrame(np.random.randn(len(rng), 3), rng) @@ -1384,35 +1358,22 @@ def test_format_timedelta_ticks_narrow(self): def test_format_timedelta_ticks_wide(self): - if self.mpl_ge_2_0_0: - expected_labels = [ - '', - '00:00:00', - '1 days 03:46:40', - '2 days 07:33:20', - '3 days 11:20:00', - '4 days 15:06:40', - '5 days 18:53:20', - '6 days 22:40:00', - '8 days 02:26:40', - '9 days 06:13:20', - '' - ] - if self.mpl_ge_2_2_0: - expected_labels[0] = '-2 days 20:13:20' - expected_labels[-1] = '10 days 10:00:00' - else: - expected_labels = [ - '00:00:00', - '1 days 03:46:40', - '2 days 07:33:20', - '3 days 11:20:00', - '4 days 15:06:40', - '5 days 18:53:20', - '6 days 22:40:00', - '8 days 02:26:40', - '' - ] + expected_labels = [ + '', + '00:00:00', + '1 days 03:46:40', + '2 days 07:33:20', + '3 days 11:20:00', + '4 days 15:06:40', + '5 days 18:53:20', + '6 days 22:40:00', + '8 days 02:26:40', + '9 days 06:13:20', + '' + ] + if self.mpl_ge_2_2_0: + expected_labels[0] = '-2 days 20:13:20' + expected_labels[-1] = '10 days 10:00:00' rng = timedelta_range('0', periods=10, freq='1 d') df = DataFrame(np.random.randn(len(rng), 3), rng) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index cd297c356d60e..88a9bdff9486a 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -141,22 +141,15 @@ def test_plot(self): fig, ax = self.plt.subplots() axes = df.plot.bar(subplots=True, ax=ax) assert len(axes) == 1 - if self.mpl_ge_1_5_0: - result = ax.axes - else: - result = ax.get_axes() # deprecated + result = ax.axes assert result is axes[0] # GH 15516 def test_mpl2_color_cycle_str(self): - # test CN mpl 2.0 color cycle - if self.mpl_ge_2_0_0: - colors = ['C' + str(x) for x in range(10)] - df = DataFrame(randn(10, 3), columns=['a', 'b', 'c']) - for c in colors: - _check_plot_works(df.plot, color=c) - else: - pytest.skip("not supported in matplotlib < 2.0.0") + colors = ['C' + str(x) for x in range(10)] + df = DataFrame(randn(10, 3), columns=['a', 'b', 'c']) + for c in colors: + _check_plot_works(df.plot, color=c) def test_color_single_series_list(self): # GH 3486 @@ -854,7 +847,7 @@ def test_area_lim(self): @pytest.mark.slow def test_bar_colors(self): import matplotlib.pyplot as plt - default_colors = self._maybe_unpack_cycler(plt.rcParams) + default_colors = [v['color'] for v in plt.rcParams['axes.prop_cycle']] df = DataFrame(randn(5, 5)) ax = df.plot.bar() @@ -1180,11 +1173,9 @@ def test_plot_scatter_with_c(self): # default to Greys assert ax.collections[0].cmap.name == 'Greys' - if self.mpl_ge_1_3_1: - - # n.b. there appears to be no public method to get the colorbar - # label - assert ax.collections[0].colorbar._label == 'z' + # n.b. there appears to be no public method + # to get the colorbar label + assert ax.collections[0].colorbar._label == 'z' cm = 'cubehelix' ax = df.plot.scatter(x='x', y='y', c='z', colormap=cm) @@ -1227,7 +1218,8 @@ def test_scatter_colors(self): with pytest.raises(TypeError): df.plot.scatter(x='a', y='b', c='c', color='green') - default_colors = self._maybe_unpack_cycler(self.plt.rcParams) + default_colors = [v['color'] + for v in self.plt.rcParams['axes.prop_cycle']] ax = df.plot.scatter(x='a', y='b', c='c') tm.assert_numpy_array_equal( @@ -1392,10 +1384,7 @@ def test_bar_edge(self): def test_bar_log_no_subplots(self): # GH3254, GH3298 matplotlib/matplotlib#1882, #1892 # regressions in 1.2.1 - expected = np.array([1., 10.]) - - if not self.mpl_le_1_2_1: - expected = np.hstack((.1, expected, 100)) + expected = np.array([.1, 1., 10., 100]) # no subplots df = DataFrame({'A': [3] * 5, 'B': lrange(1, 6)}, index=lrange(5)) @@ -1404,9 +1393,7 @@ def test_bar_log_no_subplots(self): @pytest.mark.slow def test_bar_log_subplots(self): - expected = np.array([1., 10., 100., 1000.]) - if not self.mpl_le_1_2_1: - expected = np.hstack((.1, expected, 1e4)) + expected = np.array([.1, 1., 10., 100., 1000., 1e4]) ax = DataFrame([Series([200, 300]), Series([300, 500])]).plot.bar( log=True, subplots=True) @@ -1521,8 +1508,6 @@ def test_boxplot_subplots_return_type(self): @td.skip_if_no_scipy def test_kde_df(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") df = DataFrame(randn(100, 4)) ax = _check_plot_works(df.plot, kind='kde') @@ -1545,8 +1530,6 @@ def test_kde_df(self): @td.skip_if_no_scipy def test_kde_missing_vals(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") df = DataFrame(np.random.uniform(size=(100, 4))) df.loc[0, 0] = np.nan @@ -1555,8 +1538,6 @@ def test_kde_missing_vals(self): @pytest.mark.slow def test_hist_df(self): from matplotlib.patches import Rectangle - if self.mpl_le_1_2_1: - pytest.skip("not supported in matplotlib <= 1.2.x") df = DataFrame(randn(100, 4)) series = df[0] @@ -1668,44 +1649,42 @@ def test_hist_df_coord(self): expected_y=np.array([0, 0, 0, 0, 0]), expected_h=np.array([6, 7, 8, 9, 10])) - if self.mpl_ge_1_3_1: - - # horizontal - ax = df.plot.hist(bins=5, orientation='horizontal') - self._check_box_coord(ax.patches[:5], - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([10, 9, 8, 7, 6])) - self._check_box_coord(ax.patches[5:10], - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([8, 8, 8, 8, 8])) - self._check_box_coord(ax.patches[10:], - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([6, 7, 8, 9, 10])) - - ax = df.plot.hist(bins=5, stacked=True, - orientation='horizontal') - self._check_box_coord(ax.patches[:5], - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([10, 9, 8, 7, 6])) - self._check_box_coord(ax.patches[5:10], - expected_x=np.array([10, 9, 8, 7, 6]), - expected_w=np.array([8, 8, 8, 8, 8])) - self._check_box_coord( - ax.patches[10:], - expected_x=np.array([18, 17, 16, 15, 14]), - expected_w=np.array([6, 7, 8, 9, 10])) - - axes = df.plot.hist(bins=5, stacked=True, subplots=True, - orientation='horizontal') - self._check_box_coord(axes[0].patches, - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([10, 9, 8, 7, 6])) - self._check_box_coord(axes[1].patches, - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([8, 8, 8, 8, 8])) - self._check_box_coord(axes[2].patches, - expected_x=np.array([0, 0, 0, 0, 0]), - expected_w=np.array([6, 7, 8, 9, 10])) + # horizontal + ax = df.plot.hist(bins=5, orientation='horizontal') + self._check_box_coord(ax.patches[:5], + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([10, 9, 8, 7, 6])) + self._check_box_coord(ax.patches[5:10], + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([8, 8, 8, 8, 8])) + self._check_box_coord(ax.patches[10:], + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([6, 7, 8, 9, 10])) + + ax = df.plot.hist(bins=5, stacked=True, + orientation='horizontal') + self._check_box_coord(ax.patches[:5], + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([10, 9, 8, 7, 6])) + self._check_box_coord(ax.patches[5:10], + expected_x=np.array([10, 9, 8, 7, 6]), + expected_w=np.array([8, 8, 8, 8, 8])) + self._check_box_coord( + ax.patches[10:], + expected_x=np.array([18, 17, 16, 15, 14]), + expected_w=np.array([6, 7, 8, 9, 10])) + + axes = df.plot.hist(bins=5, stacked=True, subplots=True, + orientation='horizontal') + self._check_box_coord(axes[0].patches, + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([10, 9, 8, 7, 6])) + self._check_box_coord(axes[1].patches, + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([8, 8, 8, 8, 8])) + self._check_box_coord(axes[2].patches, + expected_x=np.array([0, 0, 0, 0, 0]), + expected_w=np.array([6, 7, 8, 9, 10])) @pytest.mark.slow def test_plot_int_columns(self): @@ -1904,14 +1883,14 @@ def test_dont_modify_colors(self): def test_line_colors_and_styles_subplots(self): # GH 9894 from matplotlib import cm - default_colors = self._maybe_unpack_cycler(self.plt.rcParams) + default_colors = [v['color'] + for v in self.plt.rcParams['axes.prop_cycle']] df = DataFrame(randn(5, 5)) axes = df.plot(subplots=True) for ax, c in zip(axes, list(default_colors)): - if self.mpl_ge_2_0_0: - c = [c] + c = [c] self._check_colors(ax.get_lines(), linecolors=c) tm.close() @@ -1992,13 +1971,7 @@ def test_area_colors(self): self._check_colors(poly, facecolors=custom_colors) handles, labels = ax.get_legend_handles_labels() - if self.mpl_ge_1_5_0: - self._check_colors(handles, facecolors=custom_colors) - else: - # legend is stored as Line2D, thus check linecolors - linehandles = [x for x in handles - if not isinstance(x, PolyCollection)] - self._check_colors(linehandles, linecolors=custom_colors) + self._check_colors(handles, facecolors=custom_colors) for h in handles: assert h.get_alpha() is None @@ -2011,12 +1984,7 @@ def test_area_colors(self): self._check_colors(poly, facecolors=jet_colors) handles, labels = ax.get_legend_handles_labels() - if self.mpl_ge_1_5_0: - self._check_colors(handles, facecolors=jet_colors) - else: - linehandles = [x for x in handles - if not isinstance(x, PolyCollection)] - self._check_colors(linehandles, linecolors=jet_colors) + self._check_colors(handles, facecolors=jet_colors) for h in handles: assert h.get_alpha() is None tm.close() @@ -2029,18 +1997,15 @@ def test_area_colors(self): self._check_colors(poly, facecolors=jet_with_alpha) handles, labels = ax.get_legend_handles_labels() - if self.mpl_ge_1_5_0: - linecolors = jet_with_alpha - else: - # Line2D can't have alpha in its linecolor - linecolors = jet_colors + linecolors = jet_with_alpha self._check_colors(handles[:len(jet_colors)], linecolors=linecolors) for h in handles: assert h.get_alpha() == 0.5 @pytest.mark.slow def test_hist_colors(self): - default_colors = self._maybe_unpack_cycler(self.plt.rcParams) + default_colors = [v['color'] + for v in self.plt.rcParams['axes.prop_cycle']] df = DataFrame(randn(5, 5)) ax = df.plot.hist() @@ -2076,8 +2041,6 @@ def test_hist_colors(self): @td.skip_if_no_scipy def test_kde_colors(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") from matplotlib import cm @@ -2101,11 +2064,10 @@ def test_kde_colors(self): @td.skip_if_no_scipy def test_kde_colors_and_styles_subplots(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") from matplotlib import cm - default_colors = self._maybe_unpack_cycler(self.plt.rcParams) + default_colors = [v['color'] + for v in self.plt.rcParams['axes.prop_cycle']] df = DataFrame(randn(5, 5)) @@ -2164,7 +2126,7 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', fliers_c=None): # TODO: outside this func? if fliers_c is None: - fliers_c = 'k' if self.mpl_ge_2_0_0 else 'b' + fliers_c = 'k' self._check_colors(bp['boxes'], linecolors=[box_c] * len(bp['boxes'])) self._check_colors(bp['whiskers'], @@ -2176,7 +2138,8 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', self._check_colors(bp['caps'], linecolors=[caps_c] * len(bp['caps'])) - default_colors = self._maybe_unpack_cycler(self.plt.rcParams) + default_colors = [v['color'] + for v in self.plt.rcParams['axes.prop_cycle']] df = DataFrame(randn(5, 5)) bp = df.plot.box(return_type='dict') @@ -2225,17 +2188,14 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', def test_default_color_cycle(self): import matplotlib.pyplot as plt + import cycler colors = list('rgbk') - if self.mpl_ge_1_5_0: - import cycler - plt.rcParams['axes.prop_cycle'] = cycler.cycler('color', colors) - else: - plt.rcParams['axes.color_cycle'] = colors + plt.rcParams['axes.prop_cycle'] = cycler.cycler('color', colors) df = DataFrame(randn(5, 3)) ax = df.plot() - expected = self._maybe_unpack_cycler(plt.rcParams)[:3] + expected = [v['color'] for v in plt.rcParams['axes.prop_cycle']][:3] self._check_colors(ax.get_lines(), linecolors=expected) def test_unordered_ts(self): @@ -2591,19 +2551,12 @@ def test_errorbar_asymmetrical(self): # each column is [0, 1, 2, 3, 4], [3, 4, 5, 6, 7]... df = DataFrame(np.arange(15).reshape(3, 5)).T - data = df.values ax = df.plot(yerr=err, xerr=err / 2) - if self.mpl_ge_2_0_0: - yerr_0_0 = ax.collections[1].get_paths()[0].vertices[:, 1] - expected_0_0 = err[0, :, 0] * np.array([-1, 1]) - tm.assert_almost_equal(yerr_0_0, expected_0_0) - else: - assert ax.lines[7].get_ydata()[0] == data[0, 1] - err[1, 0, 0] - assert ax.lines[8].get_ydata()[0] == data[0, 1] + err[1, 1, 0] - assert ax.lines[5].get_xdata()[0] == -err[1, 0, 0] / 2 - assert ax.lines[6].get_xdata()[0] == err[1, 1, 0] / 2 + yerr_0_0 = ax.collections[1].get_paths()[0].vertices[:, 1] + expected_0_0 = err[0, :, 0] * np.array([-1, 1]) + tm.assert_almost_equal(yerr_0_0, expected_0_0) with pytest.raises(ValueError): df.plot(yerr=err.T) diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py index 2864877550bac..1d9942603a269 100644 --- a/pandas/tests/plotting/test_hist_method.py +++ b/pandas/tests/plotting/test_hist_method.py @@ -122,7 +122,7 @@ def test_hist_no_overlap(self): subplot(122) y.hist() fig = gcf() - axes = fig.axes if self.mpl_ge_1_5_0 else fig.get_axes() + axes = fig.axes assert len(axes) == 2 @pytest.mark.slow diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index 8c84b785c88e4..54d17a4773749 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -76,10 +76,7 @@ def test_scatter_matrix_axis(self): axes0_labels = axes[0][0].yaxis.get_majorticklabels() # GH 5662 - if self.mpl_ge_2_0_0: - expected = ['-2', '0', '2'] - else: - expected = ['-2', '-1', '0', '1', '2'] + expected = ['-2', '0', '2'] self._check_text_labels(axes0_labels, expected) self._check_ticks_props( axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0) @@ -91,10 +88,7 @@ def test_scatter_matrix_axis(self): axes = _check_plot_works(scatter_matrix, filterwarnings='always', frame=df, range_padding=.1) axes0_labels = axes[0][0].yaxis.get_majorticklabels() - if self.mpl_ge_2_0_0: - expected = ['-1.0', '-0.5', '0.0'] - else: - expected = ['-1.2', '-1.0', '-0.8', '-0.6', '-0.4', '-0.2', '0.0'] + expected = ['-1.0', '-0.5', '0.0'] self._check_text_labels(axes0_labels, expected) self._check_ticks_props( axes, xlabelsize=8, xrot=90, ylabelsize=8, yrot=0) diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 5dc7d52e05778..2788d94bb7dfa 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -88,10 +88,7 @@ def test_plot_figsize_and_title(self): def test_dont_modify_rcParams(self): # GH 8242 - if self.mpl_ge_1_5_0: - key = 'axes.prop_cycle' - else: - key = 'axes.color_cycle' + key = 'axes.prop_cycle' colors = self.plt.rcParams[key] _, ax = self.plt.subplots() Series([1, 2, 3]).plot(ax=ax) @@ -211,10 +208,7 @@ def test_line_use_index_false(self): @pytest.mark.slow def test_bar_log(self): - expected = np.array([1., 10., 100., 1000.]) - - if not self.mpl_le_1_2_1: - expected = np.hstack((.1, expected, 1e4)) + expected = np.array([.1, 1., 10., 100., 1000., 1e4]) _, ax = self.plt.subplots() ax = Series([200, 500]).plot.bar(log=True, ax=ax) @@ -227,17 +221,12 @@ def test_bar_log(self): tm.close() # GH 9905 - expected = np.array([1.0e-03, 1.0e-02, 1.0e-01, 1.0e+00]) - - if not self.mpl_le_1_2_1: - expected = np.hstack((1.0e-04, expected, 1.0e+01)) - if self.mpl_ge_2_0_0: - expected = np.hstack((1.0e-05, expected)) + expected = np.array([1.0e-05, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1, 1., 10.]) _, ax = self.plt.subplots() ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='bar', ax=ax) - ymin = 0.0007943282347242822 if self.mpl_ge_2_0_0 else 0.001 - ymax = 0.12589254117941673 if self.mpl_ge_2_0_0 else .10000000000000001 + ymin = 0.0007943282347242822 + ymax = 0.12589254117941673 res = ax.get_ylim() tm.assert_almost_equal(res[0], ymin) tm.assert_almost_equal(res[1], ymax) @@ -474,7 +463,7 @@ def test_hist_no_overlap(self): subplot(122) y.hist() fig = gcf() - axes = fig.axes if self.mpl_ge_1_5_0 else fig.get_axes() + axes = fig.axes assert len(axes) == 2 @pytest.mark.slow @@ -591,8 +580,6 @@ def test_plot_fails_with_dupe_color_and_style(self): @pytest.mark.slow @td.skip_if_no_scipy def test_hist_kde(self): - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") _, ax = self.plt.subplots() ax = self.ts.plot.hist(logy=True, ax=ax) @@ -618,8 +605,6 @@ def test_hist_kde(self): @td.skip_if_no_scipy def test_kde_kwargs(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") sample_points = np.linspace(-100, 100, 20) _check_plot_works(self.ts.plot.kde, bw_method='scott', ind=20) @@ -638,8 +623,6 @@ def test_kde_kwargs(self): @td.skip_if_no_scipy def test_kde_missing_vals(self): _skip_if_no_scipy_gaussian_kde() - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") s = Series(np.random.uniform(size=50)) s[0] = np.nan @@ -656,22 +639,18 @@ def test_hist_kwargs(self): self._check_text_labels(ax.yaxis.get_label(), 'Frequency') tm.close() - if self.mpl_ge_1_3_1: - _, ax = self.plt.subplots() - ax = self.ts.plot.hist(orientation='horizontal', ax=ax) - self._check_text_labels(ax.xaxis.get_label(), 'Frequency') - tm.close() + _, ax = self.plt.subplots() + ax = self.ts.plot.hist(orientation='horizontal', ax=ax) + self._check_text_labels(ax.xaxis.get_label(), 'Frequency') + tm.close() - _, ax = self.plt.subplots() - ax = self.ts.plot.hist(align='left', stacked=True, ax=ax) - tm.close() + _, ax = self.plt.subplots() + ax = self.ts.plot.hist(align='left', stacked=True, ax=ax) + tm.close() @pytest.mark.slow @td.skip_if_no_scipy def test_hist_kde_color(self): - if not self.mpl_ge_1_5_0: - pytest.skip("mpl is not supported") - _, ax = self.plt.subplots() ax = self.ts.plot.hist(logy=True, bins=10, color='b', ax=ax) self._check_ax_scales(ax, yaxis='log') @@ -870,10 +849,7 @@ def test_time_series_plot_color_kwargs(self): def test_time_series_plot_color_with_empty_kwargs(self): import matplotlib as mpl - if self.mpl_ge_1_5_0: - def_colors = self._maybe_unpack_cycler(mpl.rcParams) - else: - def_colors = mpl.rcParams['axes.color_cycle'] + def_colors = [v['color'] for v in mpl.rcParams['axes.prop_cycle']] index = date_range('1/1/2000', periods=12) s = Series(np.arange(1, 13), index=index) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index c6ab24403d58d..a3d8c07d62e25 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -78,17 +78,6 @@ def _skip_if_no_mpl(): return True -def _skip_if_mpl_1_5(): - mod = safe_import("matplotlib") - - if mod: - v = mod.__version__ - if LooseVersion(v) > LooseVersion('1.4.3') or str(v)[0] == '0': - return True - else: - mod.use("Agg", warn=False) - - def _skip_if_mpl_2_2(): mod = safe_import("matplotlib") @@ -165,8 +154,6 @@ def decorated_func(func): reason="NumPy 1.15 or greater required") skip_if_mpl = pytest.mark.skipif(not _skip_if_no_mpl(), reason="matplotlib is present") -skip_if_mpl_1_5 = pytest.mark.skipif(_skip_if_mpl_1_5(), - reason="matplotlib 1.5") xfail_if_mpl_2_2 = pytest.mark.xfail(_skip_if_mpl_2_2(), reason="matplotlib 2.2") skip_if_32bit = pytest.mark.skipif(is_platform_32bit(), From b2cffb4b914f474b169dc7d97d1cf91f24fcb854 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 01:14:18 +0200 Subject: [PATCH 06/41] Remove redundant functions --- pandas/core/algorithms.py | 10 ++-------- pandas/plotting/_core.py | 3 --- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/pandas/core/algorithms.py b/pandas/core/algorithms.py index 44b3b885a67e8..2b9152fa08b23 100644 --- a/pandas/core/algorithms.py +++ b/pandas/core/algorithms.py @@ -909,18 +909,12 @@ def checked_add_with_arr(arr, b, arr_mask=None, b_mask=None): ------ OverflowError if any x + y exceeds the maximum or minimum int64 value. """ - def _broadcast(arr_or_scalar, shape): - """ - Helper function to broadcast arrays / scalars to the desired shape. - """ - return np.broadcast_to(arr_or_scalar, shape) - # For performance reasons, we broadcast 'b' to the new array 'b2' # so that it has the same size as 'arr'. - b2 = _broadcast(b, arr.shape) + b2 = np.broadcast_to(b, arr.shape) if b_mask is not None: # We do the same broadcasting for b_mask as well. - b2_mask = _broadcast(b_mask, arr.shape) + b2_mask = np.broadcast_to(b_mask, arr.shape) else: b2_mask = None diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 7db958e5baca7..405c534e8528b 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -1154,9 +1154,6 @@ def _plot(cls, ax, x, y, style=None, column_num=None, res = [rect] return res - def _add_legend_handle(self, handle, label, index=None): - LinePlot._add_legend_handle(self, handle, label, index=index) - def _post_plot_logic(self, ax, data): LinePlot._post_plot_logic(self, ax, data) From e9c407e6e9309480fbe9c27fe0bb2165b94f5e63 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 07:47:32 +0200 Subject: [PATCH 07/41] Reinstante _unpack_cycler --- pandas/tests/plotting/common.py | 6 ++++++ pandas/tests/plotting/test_frame.py | 19 +++++++------------ pandas/tests/plotting/test_series.py | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 9495be2f404ee..e09f309ff8601 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -493,6 +493,12 @@ def is_grid_on(): obj.plot(kind=kind, grid=True, **kws) assert is_grid_on() + def _unpack_cycler(self, rcParams, field='color'): + """ + Auxiliary function for correctly unpacking cycler after MPL >= 1.5 + """ + return [v[field] for v in rcParams['axes.prop_cycle']] + def _check_plot_works(f, filterwarnings='always', **kwargs): import matplotlib.pyplot as plt diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 88a9bdff9486a..f4bcf85af8c73 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -847,7 +847,7 @@ def test_area_lim(self): @pytest.mark.slow def test_bar_colors(self): import matplotlib.pyplot as plt - default_colors = [v['color'] for v in plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(plt.rcParams) df = DataFrame(randn(5, 5)) ax = df.plot.bar() @@ -1218,8 +1218,7 @@ def test_scatter_colors(self): with pytest.raises(TypeError): df.plot.scatter(x='a', y='b', c='c', color='green') - default_colors = [v['color'] - for v in self.plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(self.plt.rcParams) ax = df.plot.scatter(x='a', y='b', c='c') tm.assert_numpy_array_equal( @@ -1883,8 +1882,7 @@ def test_dont_modify_colors(self): def test_line_colors_and_styles_subplots(self): # GH 9894 from matplotlib import cm - default_colors = [v['color'] - for v in self.plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(self.plt.rcParams) df = DataFrame(randn(5, 5)) @@ -2004,8 +2002,7 @@ def test_area_colors(self): @pytest.mark.slow def test_hist_colors(self): - default_colors = [v['color'] - for v in self.plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(self.plt.rcParams) df = DataFrame(randn(5, 5)) ax = df.plot.hist() @@ -2066,8 +2063,7 @@ def test_kde_colors_and_styles_subplots(self): _skip_if_no_scipy_gaussian_kde() from matplotlib import cm - default_colors = [v['color'] - for v in self.plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(self.plt.rcParams) df = DataFrame(randn(5, 5)) @@ -2138,8 +2134,7 @@ def _check_colors(bp, box_c, whiskers_c, medians_c, caps_c='k', self._check_colors(bp['caps'], linecolors=[caps_c] * len(bp['caps'])) - default_colors = [v['color'] - for v in self.plt.rcParams['axes.prop_cycle']] + default_colors = self._unpack_cycler(self.plt.rcParams) df = DataFrame(randn(5, 5)) bp = df.plot.box(return_type='dict') @@ -2195,7 +2190,7 @@ def test_default_color_cycle(self): df = DataFrame(randn(5, 3)) ax = df.plot() - expected = [v['color'] for v in plt.rcParams['axes.prop_cycle']][:3] + expected = self._unpack_cycler(plt.rcParams)[:3] self._check_colors(ax.get_lines(), linecolors=expected) def test_unordered_ts(self): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index 2788d94bb7dfa..d97740b9a3e5c 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -849,7 +849,7 @@ def test_time_series_plot_color_kwargs(self): def test_time_series_plot_color_with_empty_kwargs(self): import matplotlib as mpl - def_colors = [v['color'] for v in mpl.rcParams['axes.prop_cycle']] + def_colors = self._unpack_cycler(mpl.rcParams) index = date_range('1/1/2000', periods=12) s = Series(np.arange(1, 13), index=index) From aac634d391cc3f08ee1d41cbaafef583602e022a Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 08:37:10 +0200 Subject: [PATCH 08/41] Drop pytables < 3.4.2 --- ci/circle-27-compat.yaml | 2 +- ci/requirements-optional-conda.txt | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 460e31bb66829..e35b95a1f9ad3 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -10,7 +10,7 @@ dependencies: - numpy=1.12.0 - openpyxl=2.5.5 - psycopg2 - - pytables=3.2.2 + - pytables=3.4.2 - python-dateutil=2.5.0 - python=2.7* - pytz=2013b diff --git a/ci/requirements-optional-conda.txt b/ci/requirements-optional-conda.txt index dfea57923782f..14552f0eeb86c 100644 --- a/ci/requirements-optional-conda.txt +++ b/ci/requirements-optional-conda.txt @@ -15,7 +15,7 @@ numexpr>=2.6.2 openpyxl=2.5.5 pyarrow pymysql -pytables +pytables>=3.4.2 pytest-cov pytest-xdist s3fs diff --git a/doc/source/install.rst b/doc/source/install.rst index db925cea713a1..b89d7686caedb 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -257,7 +257,7 @@ Optional Dependencies version. Version 0.28.2 or higher. * `SciPy `__: miscellaneous statistical functions, Version 0.14.0 or higher * `xarray `__: pandas like handling for > 2 dims, needed for converting Panels to xarray objects. Version 0.7.0 or higher is recommended. -* `PyTables `__: necessary for HDF5-based storage. Version 3.0.0 or higher required, Version 3.2.1 or higher highly recommended. +* `PyTables `__: necessary for HDF5-based storage. Version 3.4.2 or higher required. * `Feather Format `__: necessary for feather-based storage, version 0.3.1 or higher. * `Apache Parquet `__, either `pyarrow `__ (>= 0.4.1) or `fastparquet `__ (>= 0.0.6) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. * `SQLAlchemy `__: for SQL database support. Version 0.8.1 or higher recommended. Besides SQLAlchemy, you also need a database specific driver. You can find an overview of supported drivers for each SQL dialect in the `SQLAlchemy docs `__. Some common drivers are: diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 9786aee7f35e6..7e6e904df10c1 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -221,6 +221,8 @@ If installed, we now require: +-----------------+-----------------+----------+---------------+ | numexpr | 2.6.2 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ +| pytables | 3.4.2 | | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: From f18880d56ddd620267f0c968042a63cac0a2c211 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 08:39:52 +0200 Subject: [PATCH 09/41] Bump numpy requirement in install.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bfd0c50c9e9be..f31aaa7e79a0d 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def is_platform_windows(): return sys.platform == 'win32' or sys.platform == 'cygwin' -min_numpy_ver = '1.9.0' +min_numpy_ver = '1.12.0' setuptools_kwargs = { 'install_requires': [ 'python-dateutil >= 2.5.0', From f81ad9f516535b1d0424940196d40b1e99b1b4ff Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 08:40:33 +0200 Subject: [PATCH 10/41] Add output for debugging tests/plotting/test_datetimelike --- pandas/tests/plotting/test_datetimelike.py | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 6df1bdc14528b..861c6b72426e3 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -414,11 +414,15 @@ def test_finder_daily(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert xp == rs xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -437,11 +441,15 @@ def test_finder_quarterly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert rs == xp xp = xpl2[i] (vmin, vmax) = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -460,11 +468,15 @@ def test_finder_monthly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert rs == xp xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] + if rs != xp: + print(self.plt.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -489,7 +501,10 @@ def test_finder_annual(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - assert rs == Period(xp[i], freq='A').ordinal + xpp = Period(xp[i], freq='A').ordinal + if rs != xpp: + print(self.plt.__version__, rs, xpp) + assert rs == xpp self.plt.close(ax.get_figure()) @pytest.mark.slow @@ -502,6 +517,8 @@ def test_finder_minutely(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] xp = Period('1998-12-29 12:00', freq='Min').ordinal + if rs != xp: + print(self.plt.__version__, rs, xp) assert rs == xp def test_finder_hourly(self): @@ -513,6 +530,8 @@ def test_finder_hourly(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] xp = Period('1998-12-31 22:00', freq='H').ordinal + if rs != xp: + print(self.plt.__version__, rs, xp) assert rs == xp @pytest.mark.slow @@ -525,6 +544,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if not isinstance(data, np.ma.core.MaskedArray): + print(self.plt.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -540,6 +561,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if not isinstance(data, np.ma.core.MaskedArray): + print(self.plt.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -555,6 +578,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if not isinstance(data, np.ma.core.MaskedArray): + print(self.plt.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -575,6 +600,8 @@ def test_gap_upsample(self): l = lines[0] data = l.get_xydata() + if not isinstance(data, np.ma.core.MaskedArray): + print(self.plt.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -1352,6 +1379,8 @@ def test_format_timedelta_ticks_narrow(self): df.plot(fontsize=2, ax=ax) fig.canvas.draw() labels = ax.get_xticklabels() + if len(labels) != len(expected_labels): + print(self.plt.__version__, labels, expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected @@ -1381,6 +1410,8 @@ def test_format_timedelta_ticks_wide(self): ax = df.plot(fontsize=2, ax=ax) fig.canvas.draw() labels = ax.get_xticklabels() + if len(labels) != len(expected_labels): + print(self.plt.__version__, labels, expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected From c29b47828e6f07587498bc8113aeab78741b47d7 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 08:48:51 +0200 Subject: [PATCH 11/41] Drop scipy < 0.18.1 --- ci/circle-27-compat.yaml | 2 +- ci/requirements-optional-conda.txt | 2 +- ci/requirements-optional-pip.txt | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index e35b95a1f9ad3..f4711c8e06aa2 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -14,7 +14,7 @@ dependencies: - python-dateutil=2.5.0 - python=2.7* - pytz=2013b - - scipy=0.14.0 + - scipy=0.18.1 - sqlalchemy=0.7.8 - xlrd=0.9.2 - xlsxwriter=0.5.2 diff --git a/ci/requirements-optional-conda.txt b/ci/requirements-optional-conda.txt index 14552f0eeb86c..f2dc3f2679df5 100644 --- a/ci/requirements-optional-conda.txt +++ b/ci/requirements-optional-conda.txt @@ -19,7 +19,7 @@ pytables>=3.4.2 pytest-cov pytest-xdist s3fs -scipy +scipy>=0.18.1 seaborn sqlalchemy statsmodels diff --git a/ci/requirements-optional-pip.txt b/ci/requirements-optional-pip.txt index 978869aabc5a7..8c151e1155a57 100644 --- a/ci/requirements-optional-pip.txt +++ b/ci/requirements-optional-pip.txt @@ -21,7 +21,7 @@ tables pytest-cov pytest-xdist s3fs -scipy +scipy>=0.18.1 seaborn sqlalchemy statsmodels diff --git a/doc/source/install.rst b/doc/source/install.rst index b89d7686caedb..9286ad7e356fd 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -255,7 +255,7 @@ Optional Dependencies * `Cython `__: Only necessary to build development version. Version 0.28.2 or higher. -* `SciPy `__: miscellaneous statistical functions, Version 0.14.0 or higher +* `SciPy `__: miscellaneous statistical functions, Version 0.18.1 or higher * `xarray `__: pandas like handling for > 2 dims, needed for converting Panels to xarray objects. Version 0.7.0 or higher is recommended. * `PyTables `__: necessary for HDF5-based storage. Version 3.4.2 or higher required. * `Feather Format `__: necessary for feather-based storage, version 0.3.1 or higher. diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 7e6e904df10c1..e34cae54daa76 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -223,6 +223,8 @@ If installed, we now require: +-----------------+-----------------+----------+---------------+ | pytables | 3.4.2 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ +| scipy | 0.18.1 | | :issue:`21242`| ++-----------------+-----------------+----------+---------------+ .. _whatsnew_0240.api_breaking.interval_values: From 7ecc5f2f79b4404fba245223d3eddddcc4de969d Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 09:12:19 +0200 Subject: [PATCH 12/41] Fix debugging output --- pandas/tests/plotting/test_datetimelike.py | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 861c6b72426e3..e7bca48d999b4 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -5,6 +5,7 @@ import pytest from pandas.compat import lrange, zip +import matplotlib import numpy as np from pandas import Index, Series, DataFrame, NaT @@ -415,14 +416,14 @@ def test_finder_daily(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert xp == rs xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -442,14 +443,14 @@ def test_finder_quarterly(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert rs == xp xp = xpl2[i] (vmin, vmax) = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -469,14 +470,14 @@ def test_finder_monthly(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert rs == xp xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs = xaxis.get_majorticklocs()[0] if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert xp == rs self.plt.close(ax.get_figure()) @@ -503,7 +504,7 @@ def test_finder_annual(self): rs = xaxis.get_majorticklocs()[0] xpp = Period(xp[i], freq='A').ordinal if rs != xpp: - print(self.plt.__version__, rs, xpp) + print(matplotlib.__version__, rs, xpp) assert rs == xpp self.plt.close(ax.get_figure()) @@ -518,7 +519,7 @@ def test_finder_minutely(self): rs = xaxis.get_majorticklocs()[0] xp = Period('1998-12-29 12:00', freq='Min').ordinal if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert rs == xp def test_finder_hourly(self): @@ -531,7 +532,7 @@ def test_finder_hourly(self): rs = xaxis.get_majorticklocs()[0] xp = Period('1998-12-31 22:00', freq='H').ordinal if rs != xp: - print(self.plt.__version__, rs, xp) + print(matplotlib.__version__, rs, xp) assert rs == xp @pytest.mark.slow @@ -545,7 +546,7 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(self.plt.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -562,7 +563,7 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(self.plt.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -579,7 +580,7 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(self.plt.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -601,7 +602,7 @@ def test_gap_upsample(self): data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(self.plt.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -1380,7 +1381,7 @@ def test_format_timedelta_ticks_narrow(self): fig.canvas.draw() labels = ax.get_xticklabels() if len(labels) != len(expected_labels): - print(self.plt.__version__, labels, expected_labels) + print(matplotlib.__version__, [str(x) for x in labels], expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected @@ -1411,7 +1412,7 @@ def test_format_timedelta_ticks_wide(self): fig.canvas.draw() labels = ax.get_xticklabels() if len(labels) != len(expected_labels): - print(self.plt.__version__, labels, expected_labels) + print(matplotlib.__version__, [str(x) for x in labels], expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected From 6e533e7895841f1fb6811338c538fd7ec1edd7b1 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 18:13:56 +0200 Subject: [PATCH 13/41] Reduce min version for numexpr/pytables after conda investigation --- ci/circle-27-compat.yaml | 4 ++-- ci/requirements-optional-conda.txt | 4 ++-- ci/requirements-optional-pip.txt | 2 +- doc/source/install.rst | 4 ++-- doc/source/whatsnew/v0.24.0.txt | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index f4711c8e06aa2..da9da8f729de5 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -6,11 +6,11 @@ dependencies: - bottleneck=1.2.0 - cython=0.28.2 - jinja2=2.8 - - numexpr=2.6.2 + - numexpr=2.6.1 - numpy=1.12.0 - openpyxl=2.5.5 - psycopg2 - - pytables=3.4.2 + - pytables=3.2.2 - python-dateutil=2.5.0 - python=2.7* - pytz=2013b diff --git a/ci/requirements-optional-conda.txt b/ci/requirements-optional-conda.txt index f2dc3f2679df5..b16b6e8b861a4 100644 --- a/ci/requirements-optional-conda.txt +++ b/ci/requirements-optional-conda.txt @@ -11,11 +11,11 @@ jinja2 lxml matplotlib>=2.0.0 nbsphinx -numexpr>=2.6.2 +numexpr>=2.6.1 openpyxl=2.5.5 pyarrow pymysql -pytables>=3.4.2 +pytables>=3.2.2 pytest-cov pytest-xdist s3fs diff --git a/ci/requirements-optional-pip.txt b/ci/requirements-optional-pip.txt index 8c151e1155a57..ebe0c4ca88ee6 100644 --- a/ci/requirements-optional-pip.txt +++ b/ci/requirements-optional-pip.txt @@ -13,7 +13,7 @@ jinja2 lxml matplotlib>=2.0.0 nbsphinx -numexpr>=2.6.2 +numexpr>=2.6.1 openpyxl==2.5.5 pyarrow pymysql diff --git a/doc/source/install.rst b/doc/source/install.rst index 9286ad7e356fd..a123076f4361d 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -236,7 +236,7 @@ Recommended Dependencies * `numexpr `__: for accelerating certain numerical operations. ``numexpr`` uses multiple cores as well as smart chunking and caching to achieve large speedups. - If installed, must be Version 2.6.2 or higher. + If installed, must be Version 2.6.1 or higher. * `bottleneck `__: for accelerating certain types of ``nan`` evaluations. ``bottleneck`` uses specialized cython routines to achieve large speedups. If installed, @@ -257,7 +257,7 @@ Optional Dependencies version. Version 0.28.2 or higher. * `SciPy `__: miscellaneous statistical functions, Version 0.18.1 or higher * `xarray `__: pandas like handling for > 2 dims, needed for converting Panels to xarray objects. Version 0.7.0 or higher is recommended. -* `PyTables `__: necessary for HDF5-based storage. Version 3.4.2 or higher required. +* `PyTables `__: necessary for HDF5-based storage. Version 3.2.2 or higher required. * `Feather Format `__: necessary for feather-based storage, version 0.3.1 or higher. * `Apache Parquet `__, either `pyarrow `__ (>= 0.4.1) or `fastparquet `__ (>= 0.0.6) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. * `SQLAlchemy `__: for SQL database support. Version 0.8.1 or higher recommended. Besides SQLAlchemy, you also need a database specific driver. You can find an overview of supported drivers for each SQL dialect in the `SQLAlchemy docs `__. Some common drivers are: diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index e34cae54daa76..6721e03fd7ace 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -219,9 +219,9 @@ If installed, we now require: +-----------------+-----------------+----------+---------------+ | matplotlib | 2.0.0 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ -| numexpr | 2.6.2 | | :issue:`21242`| +| numexpr | 2.6.1 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ -| pytables | 3.4.2 | | :issue:`21242`| +| pytables | 3.2.2 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ | scipy | 0.18.1 | | :issue:`21242`| +-----------------+-----------------+----------+---------------+ From 2ab7f553712f18c4cb174fda0377f8edf208340b Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 18:15:38 +0200 Subject: [PATCH 14/41] Review (jreback & jbrockmendel) --- doc/source/whatsnew/v0.24.0.txt | 30 +++++++++++++++--------------- pandas/compat/numpy/__init__.py | 4 ++-- pandas/core/ops.py | 7 +------ 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 6721e03fd7ace..57c39799c9df9 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -210,21 +210,21 @@ Dependencies have increased minimum versions We have updated our minimum supported versions of dependencies (:issue:`21242`). If installed, we now require: -+-----------------+-----------------+----------+---------------+ -| Package | Minimum Version | Required | Issue | -+=================+=================+==========+===============+ -| numpy | 1.12.0 | X | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ -| bottleneck | 1.2.0 | | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ -| matplotlib | 2.0.0 | | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ -| numexpr | 2.6.1 | | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ -| pytables | 3.2.2 | | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ -| scipy | 0.18.1 | | :issue:`21242`| -+-----------------+-----------------+----------+---------------+ ++-----------------+-----------------+----------+ +| Package | Minimum Version | Required | ++=================+=================+==========+ +| numpy | 1.12.0 | X | ++-----------------+-----------------+----------+ +| bottleneck | 1.2.0 | | ++-----------------+-----------------+----------+ +| matplotlib | 2.0.0 | | ++-----------------+-----------------+----------+ +| numexpr | 2.6.1 | | ++-----------------+-----------------+----------+ +| pytables | 3.2.2 | | ++-----------------+-----------------+----------+ +| scipy | 0.18.1 | | ++-----------------+-----------------+----------+ .. _whatsnew_0240.api_breaking.interval_values: diff --git a/pandas/compat/numpy/__init__.py b/pandas/compat/numpy/__init__.py index 43e12d145b49e..5e67cf2ee2837 100644 --- a/pandas/compat/numpy/__init__.py +++ b/pandas/compat/numpy/__init__.py @@ -52,8 +52,8 @@ def np_array_datetime64_compat(arr, *args, **kwargs): warning, when need to pass '2015-01-01 09:00:00' """ # is_list_like - if hasattr(arr, '__iter__') and not \ - isinstance(arr, string_and_binary_types): + if (hasattr(arr, '__iter__') + and not isinstance(arr, string_and_binary_types)): arr = [tz_replacer(s) for s in arr] else: arr = tz_replacer(arr) diff --git a/pandas/core/ops.py b/pandas/core/ops.py index 20559bca9caed..d44a7367b3af1 100644 --- a/pandas/core/ops.py +++ b/pandas/core/ops.py @@ -1805,12 +1805,7 @@ def to_series(right): elif right.shape[0] == left.shape[0] and right.shape[1] == 1: # Broadcast across columns - try: - right = np.broadcast_to(right, left.shape) - except AttributeError: - # numpy < 1.10.0 - right = np.tile(right, (1, left.shape[1])) - + right = np.broadcast_to(right, left.shape) right = left._constructor(right, index=left.index, columns=left.columns) From 7ca175352a02716a456d54c309ed1331ed5256f5 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 18:18:10 +0200 Subject: [PATCH 15/41] Next iteration debugging tests/plotting/test_datetimelike --- pandas/plotting/_compat.py | 1 + pandas/tests/plotting/common.py | 1 + pandas/tests/plotting/test_datetimelike.py | 145 ++++++++++++++------- 3 files changed, 98 insertions(+), 49 deletions(-) diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index ee8ff0b760c2e..cca983d7499b6 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -21,4 +21,5 @@ def inner(): _mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) _mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) _mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) +_mpl_ge_2_2_3 = _mpl_version('2.2.3', operator.ge) _mpl_ge_3_0_0 = _mpl_version('3.0.0', operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index e09f309ff8601..3d1fa33d85e92 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -52,6 +52,7 @@ def setup_method(self, method): self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() + self.mpl_ge_2_2_3 = plotting._compat._mpl_ge_2_2_3() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() self.bp_n_objects = 7 diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index e7bca48d999b4..a8234f5945aa5 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -5,7 +5,10 @@ import pytest from pandas.compat import lrange, zip -import matplotlib +try: + import matplotlib +except: + pass import numpy as np from pandas import Index, Series, DataFrame, NaT @@ -405,8 +408,13 @@ def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] - xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] + if self.mpl_ge_2_0_1: + xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] + else: + xpl2 = xpl1 + rs1 = [] + rs2 = [] for i, n in enumerate(day_lst): xp = xpl1[i] rng = bdate_range('1999-1-1', periods=n) @@ -414,26 +422,34 @@ def test_finder_daily(self): _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert xp == rs + rs1.append(xaxis.get_majorticklocs()[0]) xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert xp == rs + rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) + if rs1 != xpl1 or rs2 != xpl2: + print(matplotlib.__version__, np.__version__, + rs1, xpl1, rs2, xpl2) + for rs, xp in zip(rs1, xpl1): + assert rs == xp + for rs, xp in zip(rs2, xpl2): + assert rs == xp + @pytest.mark.slow def test_finder_quarterly(self): yrs = [3.5, 11] - xpl1 = [68, 68] - xpl2 = [72, 68] + if self.mpl_ge_2_0_1: + xpl1 = [68, 68] + xpl2 = [72, 68] + else: + xpl1 = [72, 68] + xpl2 = xpl1 + rs1 = [] + rs2 = [] for i, n in enumerate(yrs): xp = xpl1[i] rng = period_range('1987Q2', periods=int(n * 4), freq='Q') @@ -441,26 +457,34 @@ def test_finder_quarterly(self): _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert rs == xp + rs1.append(xaxis.get_majorticklocs()[0]) xp = xpl2[i] (vmin, vmax) = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert xp == rs + rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) + if rs1 != xpl1 or rs2 != xpl2: + print(matplotlib.__version__, np.__version__, + rs1, xpl1, rs2, xpl2) + for rs, xp in zip(rs1, xpl1): + assert rs == xp + for rs, xp in zip(rs2, xpl2): + assert rs == xp + @pytest.mark.slow def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] - xpl1 = [216, 216, 204, 204] - xpl2 = [216, 216, 216, 204] + if self.mpl_ge_2_0_1: + xpl1 = [216, 216, 204, 204] + xpl2 = [216, 216, 216, 204] + else: + xpl1 = [216, 216, 216, 204] + xpl2 = [216, 216, 216, 204] + rs1 = [] + rs2 = [] for i, n in enumerate(yrs): xp = xpl1[i] rng = period_range('1987Q2', periods=int(n * 12), freq='M') @@ -468,19 +492,21 @@ def test_finder_monthly(self): _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert rs == xp + rs1.append(xaxis.get_majorticklocs()[0]) xp = xpl2[i] vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) - rs = xaxis.get_majorticklocs()[0] - if rs != xp: - print(matplotlib.__version__, rs, xp) - assert xp == rs + rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) + if rs1 != xpl1 or rs2 != xpl2: + print(matplotlib.__version__, np.__version__, + rs1, xpl1, rs2, xpl2) + for rs, xp in zip(rs1, xpl1): + assert rs == xp + for rs, xp in zip(rs2, xpl2): + assert rs == xp + def test_finder_monthly_long(self): rng = period_range('1988Q1', periods=24 * 12, freq='M') ser = Series(np.random.randn(len(rng)), rng) @@ -493,21 +519,28 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): - xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] + if self.mpl_ge_2_0_1: + xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] + else: + xp = [1987, 1987, 1990, 1990, 1995, 2020, 1970, 1970] + xp = [Period(x, freq='A').ordinal for x in xp] + rs = [] for i, nyears in enumerate([5, 10, 19, 49, 99, 199, 599, 1001]): rng = period_range('1987', periods=nyears, freq='A') ser = Series(np.random.randn(len(rng)), rng) _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() - rs = xaxis.get_majorticklocs()[0] - xpp = Period(xp[i], freq='A').ordinal - if rs != xpp: - print(matplotlib.__version__, rs, xpp) - assert rs == xpp + rs.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) + if rs != xp: + print(matplotlib.__version__, np.__version__, + rs, xp) + for res, exp in zip(rs1, xpl1): + assert res == exp + @pytest.mark.slow def test_finder_minutely(self): nminutes = 50 * 24 * 60 @@ -517,9 +550,12 @@ def test_finder_minutely(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - xp = Period('1998-12-29 12:00', freq='Min').ordinal + if self.mpl_ge_2_0_1: + xp = Period('1999-01-01 00:00', freq='Min').ordinal + else: + xp = Period('1998-12-29 12:00', freq='Min').ordinal if rs != xp: - print(matplotlib.__version__, rs, xp) + print(matplotlib.__version__, np.__version__, rs, xp) assert rs == xp def test_finder_hourly(self): @@ -530,9 +566,12 @@ def test_finder_hourly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - xp = Period('1998-12-31 22:00', freq='H').ordinal + if self.mpl_ge_2_2_3: + xp = Period('1999-01-01 00:00', freq='H').ordinal + else: + xp = Period('1998-12-31 22:00', freq='H').ordinal if rs != xp: - print(matplotlib.__version__, rs, xp) + print(matplotlib.__version__, np.__version__, rs, xp) assert rs == xp @pytest.mark.slow @@ -546,7 +585,7 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version__, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -563,7 +602,7 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version__, type(data)) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -580,7 +619,8 @@ def test_gaps(self): l = lines[0] data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version__, type(data)) + print(data) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -602,7 +642,8 @@ def test_gap_upsample(self): data = l.get_xydata() if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version, type(data)) + print(matplotlib.__version__, np.__version__, type(data)) + print(data) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -1365,7 +1406,10 @@ def test_plot_outofbounds_datetime(self): def test_format_timedelta_ticks_narrow(self): - if self.mpl_ge_2_2_0: + if self.mpl_ge_2_2_3: + expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) + for i in range(10)]) + elif self.mpl_ge_2_2_0: expected_labels = (['-1 days 23:59:59.999999998'] + ['00:00:00.0000000{:0>2d}'.format(2 * i) for i in range(6)]) @@ -1381,13 +1425,13 @@ def test_format_timedelta_ticks_narrow(self): fig.canvas.draw() labels = ax.get_xticklabels() if len(labels) != len(expected_labels): - print(matplotlib.__version__, [str(x) for x in labels], expected_labels) + print(matplotlib.__version__, np.__version__, + [str(x) for x in labels], expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected def test_format_timedelta_ticks_wide(self): - expected_labels = [ '', '00:00:00', @@ -1401,7 +1445,9 @@ def test_format_timedelta_ticks_wide(self): '9 days 06:13:20', '' ] - if self.mpl_ge_2_2_0: + if self.mpl_ge_2_2_3: + expected_labels = expected_labels[1:-1] + elif self.mpl_ge_2_2_0: expected_labels[0] = '-2 days 20:13:20' expected_labels[-1] = '10 days 10:00:00' @@ -1412,7 +1458,8 @@ def test_format_timedelta_ticks_wide(self): fig.canvas.draw() labels = ax.get_xticklabels() if len(labels) != len(expected_labels): - print(matplotlib.__version__, [str(x) for x in labels], expected_labels) + print(matplotlib.__version__, np.__version__, + [str(x) for x in labels], expected_labels) assert len(labels) == len(expected_labels) for l, l_expected in zip(labels, expected_labels): assert l.get_text() == l_expected From 9b850612baf433371267898d4c562effc52c78ea Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 18:20:05 +0200 Subject: [PATCH 16/41] Spread matplotlib-version in CI for debugging --- ci/azure-macos-35.yaml | 2 +- ci/azure-windows-27.yaml | 2 +- ci/travis-27.yaml | 2 +- ci/travis-36-doc.yaml | 2 +- ci/travis-36.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci/azure-macos-35.yaml b/ci/azure-macos-35.yaml index bbe578b858a07..6ccdc79d11b27 100644 --- a/ci/azure-macos-35.yaml +++ b/ci/azure-macos-35.yaml @@ -8,7 +8,7 @@ dependencies: - html5lib - jinja2 - lxml - - matplotlib + - matplotlib=2.2.0 - nomkl - numexpr - numpy=1.12.0 diff --git a/ci/azure-windows-27.yaml b/ci/azure-windows-27.yaml index bcd9ddee1715e..d48a9ba986a93 100644 --- a/ci/azure-windows-27.yaml +++ b/ci/azure-windows-27.yaml @@ -10,7 +10,7 @@ dependencies: - html5lib - jinja2=2.8 - lxml - - matplotlib + - matplotlib=2.0.1 - numexpr - numpy=1.12* - openpyxl=2.5.5 diff --git a/ci/travis-27.yaml b/ci/travis-27.yaml index 6955db363ca1f..6f6bd4d2f229a 100644 --- a/ci/travis-27.yaml +++ b/ci/travis-27.yaml @@ -16,7 +16,7 @@ dependencies: - jemalloc=4.5.0.post - jinja2=2.8 - lxml - - matplotlib + - matplotlib=2.1.0 - mock - nomkl - numexpr diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 8353659e7b9a9..e367b34020a77 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib + - matplotlib=2.2.1 - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36.yaml b/ci/travis-36.yaml index 3c9daa5f8b73c..df31fea66e752 100644 --- a/ci/travis-36.yaml +++ b/ci/travis-36.yaml @@ -14,7 +14,7 @@ dependencies: - ipython - jinja2 - lxml - - matplotlib + - matplotlib=2.2.2 - nomkl - numexpr - numpy From 5b546122a7d31d9e8e02fb5119c3b652b6e319ab Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 22:48:02 +0200 Subject: [PATCH 17/41] Re-drop pytables < 3.4.2 --- ci/circle-27-compat.yaml | 2 +- ci/requirements-optional-conda.txt | 2 +- doc/source/install.rst | 2 +- doc/source/whatsnew/v0.24.0.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index da9da8f729de5..5b726304cf414 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -10,7 +10,7 @@ dependencies: - numpy=1.12.0 - openpyxl=2.5.5 - psycopg2 - - pytables=3.2.2 + - pytables=3.4.2 - python-dateutil=2.5.0 - python=2.7* - pytz=2013b diff --git a/ci/requirements-optional-conda.txt b/ci/requirements-optional-conda.txt index b16b6e8b861a4..e9afd7a551b6e 100644 --- a/ci/requirements-optional-conda.txt +++ b/ci/requirements-optional-conda.txt @@ -15,7 +15,7 @@ numexpr>=2.6.1 openpyxl=2.5.5 pyarrow pymysql -pytables>=3.2.2 +pytables>=3.4.2 pytest-cov pytest-xdist s3fs diff --git a/doc/source/install.rst b/doc/source/install.rst index a123076f4361d..8fe77272b0a1a 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -257,7 +257,7 @@ Optional Dependencies version. Version 0.28.2 or higher. * `SciPy `__: miscellaneous statistical functions, Version 0.18.1 or higher * `xarray `__: pandas like handling for > 2 dims, needed for converting Panels to xarray objects. Version 0.7.0 or higher is recommended. -* `PyTables `__: necessary for HDF5-based storage. Version 3.2.2 or higher required. +* `PyTables `__: necessary for HDF5-based storage. Version 3.4.2 or higher required. * `Feather Format `__: necessary for feather-based storage, version 0.3.1 or higher. * `Apache Parquet `__, either `pyarrow `__ (>= 0.4.1) or `fastparquet `__ (>= 0.0.6) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. * `SQLAlchemy `__: for SQL database support. Version 0.8.1 or higher recommended. Besides SQLAlchemy, you also need a database specific driver. You can find an overview of supported drivers for each SQL dialect in the `SQLAlchemy docs `__. Some common drivers are: diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 57c39799c9df9..71eeb3cf4f07a 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -221,7 +221,7 @@ If installed, we now require: +-----------------+-----------------+----------+ | numexpr | 2.6.1 | | +-----------------+-----------------+----------+ -| pytables | 3.2.2 | | +| pytables | 3.4.2 | | +-----------------+-----------------+----------+ | scipy | 0.18.1 | | +-----------------+-----------------+----------+ From 708b2f638b3df9f6d3a80df8303549b6bfa47d3e Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 23:22:48 +0200 Subject: [PATCH 18/41] Remove non-existent version --- ci/travis-36-doc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index e367b34020a77..6b0f198dc430e 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib=2.2.1 + - matplotlib=2.2.0 - nbconvert - nbformat - nbsphinx From a41ed9fd8a206226c254b24cf743facd568dc8f3 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 23:23:02 +0200 Subject: [PATCH 19/41] Debugggggg --- pandas/tests/plotting/test_datetimelike.py | 36 ++++++++++++++-------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index a8234f5945aa5..5e2e0ffc34797 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -23,6 +23,7 @@ import pandas.util.testing as tm import pandas.util._test_decorators as td +from pandas.plotting._compat import _mpl_ge_3_0_0 from pandas.tests.plotting.common import (TestPlotBase, _skip_if_no_scipy_gaussian_kde) @@ -407,11 +408,12 @@ def test_get_finder(self): def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] - xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] - if self.mpl_ge_2_0_1: - xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] - else: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + xpl1 = [7566] * len(day_lst) xpl2 = xpl1 + else: + xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] + xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] rs1 = [] rs2 = [] @@ -441,7 +443,10 @@ def test_finder_daily(self): def test_finder_quarterly(self): yrs = [3.5, 11] - if self.mpl_ge_2_0_1: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + xpl1 = [72, 72] + xpl2 = [72, 72] + elif self.mpl_ge_2_0_1: xpl1 = [68, 68] xpl2 = [72, 68] else: @@ -476,6 +481,9 @@ def test_finder_quarterly(self): def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + xpl1 = [216] * 4 + xpl2 = xpl1 if self.mpl_ge_2_0_1: xpl1 = [216, 216, 204, 204] xpl2 = [216, 216, 216, 204] @@ -519,6 +527,8 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] if self.mpl_ge_2_0_1: xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] else: @@ -536,9 +546,8 @@ def test_finder_annual(self): self.plt.close(ax.get_figure()) if rs != xp: - print(matplotlib.__version__, np.__version__, - rs, xp) - for res, exp in zip(rs1, xpl1): + print(matplotlib.__version__, np.__version__, rs, xp) + for res, exp in zip(rs, xp): assert res == exp @pytest.mark.slow @@ -550,10 +559,7 @@ def test_finder_minutely(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_0_1: - xp = Period('1999-01-01 00:00', freq='Min').ordinal - else: - xp = Period('1998-12-29 12:00', freq='Min').ordinal + xp = Period('1999-01-01 00:00', freq='Min').ordinal if rs != xp: print(matplotlib.__version__, np.__version__, rs, xp) assert rs == xp @@ -566,7 +572,7 @@ def test_finder_hourly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_2_3: + if self.mpl_ge_2_1_0: xp = Period('1999-01-01 00:00', freq='H').ordinal else: xp = Period('1998-12-31 22:00', freq='H').ordinal @@ -575,6 +581,8 @@ def test_finder_hourly(self): assert rs == xp @pytest.mark.slow + @pytest.mark.xfail(_mpl_ge_3_0_0, + reason="return type not a masked array anymore?") def test_gaps(self): ts = tm.makeTimeSeries() ts[5:25] = np.nan @@ -626,6 +634,8 @@ def test_gaps(self): assert mask[2:5, 1].all() @pytest.mark.slow + @pytest.mark.xfail(_mpl_ge_3_0_0, + reason="return type not a masked array anymore?") def test_gap_upsample(self): low = tm.makeTimeSeries() low[5:25] = np.nan From 1e0c553e07b9f14b036244f62d562467aa0f091d Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Wed, 10 Oct 2018 23:54:42 +0200 Subject: [PATCH 20/41] Fix typos --- pandas/tests/plotting/common.py | 1 + pandas/tests/plotting/test_datetimelike.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 3d1fa33d85e92..2cc1562b803e4 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -51,6 +51,7 @@ def setup_method(self, method): mpl.rcdefaults() self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() + self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() self.mpl_ge_2_2_3 = plotting._compat._mpl_ge_2_2_3() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 5e2e0ffc34797..5da034ffed991 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -484,7 +484,7 @@ def test_finder_monthly(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: xpl1 = [216] * 4 xpl2 = xpl1 - if self.mpl_ge_2_0_1: + elif self.mpl_ge_2_0_1: xpl1 = [216, 216, 204, 204] xpl2 = [216, 216, 216, 204] else: @@ -529,7 +529,7 @@ def test_finder_monthly_long(self): def test_finder_annual(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] - if self.mpl_ge_2_0_1: + elif self.mpl_ge_2_0_1: xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] else: xp = [1987, 1987, 1990, 1990, 1995, 2020, 1970, 1970] From 317e042a4abd2556c5445f81048458e595868926 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 01:00:55 +0200 Subject: [PATCH 21/41] More mpl compat --- pandas/plotting/_compat.py | 2 +- pandas/tests/plotting/common.py | 2 +- pandas/tests/plotting/test_datetimelike.py | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index cca983d7499b6..385e88d58cc26 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -21,5 +21,5 @@ def inner(): _mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) _mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) _mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) -_mpl_ge_2_2_3 = _mpl_version('2.2.3', operator.ge) +_mpl_ge_2_2_2 = _mpl_version('2.2.2', operator.ge) _mpl_ge_3_0_0 = _mpl_version('3.0.0', operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 2cc1562b803e4..efbb083b352b8 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -53,7 +53,7 @@ def setup_method(self, method): self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() - self.mpl_ge_2_2_3 = plotting._compat._mpl_ge_2_2_3() + self.mpl_ge_2_2_2 = plotting._compat._mpl_ge_2_2_2() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() self.bp_n_objects = 7 diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 5da034ffed991..ea08f11eaa8c5 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1416,14 +1416,18 @@ def test_plot_outofbounds_datetime(self): def test_format_timedelta_ticks_narrow(self): - if self.mpl_ge_2_2_3: + if self.mpl_ge_2_2_2: expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) for i in range(10)]) elif self.mpl_ge_2_2_0: expected_labels = (['-1 days 23:59:59.999999998'] + ['00:00:00.0000000{:0>2d}'.format(2 * i) for i in range(6)]) - else: + elif self.mpl_ge_2_0_1: + # same as >= 2.2.3 + expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) + for i in range(10)]) + else: # 2.0.0 expected_labels = [''] + [ '00:00:00.00000000{:d}'.format(2 * i) for i in range(5)] + [''] @@ -1455,11 +1459,14 @@ def test_format_timedelta_ticks_wide(self): '9 days 06:13:20', '' ] - if self.mpl_ge_2_2_3: + if self.mpl_ge_2_2_2: expected_labels = expected_labels[1:-1] elif self.mpl_ge_2_2_0: expected_labels[0] = '-2 days 20:13:20' expected_labels[-1] = '10 days 10:00:00' + elif self.mpl_ge_2_0_1: + expected_labels = expected_labels[1:-1] + expected_labels[-1] = '' rng = timedelta_range('0', periods=10, freq='1 d') df = DataFrame(np.random.randn(len(rng), 3), rng) From 31dc4fae855c4acb9e09a90258c5d64e35fa7be2 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 01:42:38 +0200 Subject: [PATCH 22/41] Revert xfails for missing MaskedArrays --- pandas/tests/plotting/test_datetimelike.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index ea08f11eaa8c5..85157f0379cb0 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -11,7 +11,7 @@ pass import numpy as np -from pandas import Index, Series, DataFrame, NaT +from pandas import Index, Series, DataFrame, NaT, isna from pandas.compat import PY3 from pandas.core.indexes.datetimes import date_range, bdate_range from pandas.core.indexes.timedeltas import timedelta_range @@ -581,8 +581,6 @@ def test_finder_hourly(self): assert rs == xp @pytest.mark.slow - @pytest.mark.xfail(_mpl_ge_3_0_0, - reason="return type not a masked array anymore?") def test_gaps(self): ts = tm.makeTimeSeries() ts[5:25] = np.nan @@ -592,6 +590,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if _mpl_ge_3_0_0: + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) assert isinstance(data, np.ma.core.MaskedArray) @@ -609,6 +609,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if _mpl_ge_3_0_0: + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) assert isinstance(data, np.ma.core.MaskedArray) @@ -626,6 +628,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() + if _mpl_ge_3_0_0: + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) print(data) @@ -634,8 +638,6 @@ def test_gaps(self): assert mask[2:5, 1].all() @pytest.mark.slow - @pytest.mark.xfail(_mpl_ge_3_0_0, - reason="return type not a masked array anymore?") def test_gap_upsample(self): low = tm.makeTimeSeries() low[5:25] = np.nan @@ -650,6 +652,8 @@ def test_gap_upsample(self): assert len(ax.right_ax.get_lines()) == 1 l = lines[0] data = l.get_xydata() + if _mpl_ge_3_0_0: + data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) From ec93bdb7360f67580fcc3903cd88ee1e580d35e7 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 02:03:51 +0200 Subject: [PATCH 23/41] Clean up diff/switches in test_datetimelike --- pandas/tests/plotting/test_datetimelike.py | 68 ++++++++-------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 85157f0379cb0..0b5dbb5709259 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -23,7 +23,6 @@ import pandas.util.testing as tm import pandas.util._test_decorators as td -from pandas.plotting._compat import _mpl_ge_3_0_0 from pandas.tests.plotting.common import (TestPlotBase, _skip_if_no_scipy_gaussian_kde) @@ -409,8 +408,8 @@ def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - xpl1 = [7566] * len(day_lst) - xpl2 = xpl1 + # 2.0.0 and >= 3.0.0 + xpl1 = xpl2 = [Period('1999-1-1', freq='B').ordinal] * len(day_lst) else: xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] @@ -418,14 +417,13 @@ def test_finder_daily(self): rs1 = [] rs2 = [] for i, n in enumerate(day_lst): - xp = xpl1[i] rng = bdate_range('1999-1-1', periods=n) ser = Series(np.random.randn(len(rng)), rng) _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() rs1.append(xaxis.get_majorticklocs()[0]) - xp = xpl2[i] + vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs2.append(xaxis.get_majorticklocs()[0]) @@ -434,36 +432,30 @@ def test_finder_daily(self): if rs1 != xpl1 or rs2 != xpl2: print(matplotlib.__version__, np.__version__, rs1, xpl1, rs2, xpl2) - for rs, xp in zip(rs1, xpl1): - assert rs == xp - for rs, xp in zip(rs2, xpl2): - assert rs == xp + assert rs1 == xpl1 + assert rs2 == xpl2 @pytest.mark.slow def test_finder_quarterly(self): yrs = [3.5, 11] if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - xpl1 = [72, 72] - xpl2 = [72, 72] - elif self.mpl_ge_2_0_1: + # 2.0.0 and >= 3.0.0 + xpl1 = xpl2 = [Period('1988Q1').ordinal] * len(yrs) + else: xpl1 = [68, 68] xpl2 = [72, 68] - else: - xpl1 = [72, 68] - xpl2 = xpl1 rs1 = [] rs2 = [] for i, n in enumerate(yrs): - xp = xpl1[i] rng = period_range('1987Q2', periods=int(n * 4), freq='Q') ser = Series(np.random.randn(len(rng)), rng) _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() rs1.append(xaxis.get_majorticklocs()[0]) - xp = xpl2[i] + (vmin, vmax) = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs2.append(xaxis.get_majorticklocs()[0]) @@ -472,36 +464,30 @@ def test_finder_quarterly(self): if rs1 != xpl1 or rs2 != xpl2: print(matplotlib.__version__, np.__version__, rs1, xpl1, rs2, xpl2) - for rs, xp in zip(rs1, xpl1): - assert rs == xp - for rs, xp in zip(rs2, xpl2): - assert rs == xp + assert rs1 == xpl1 + assert rs2 == xpl2 @pytest.mark.slow def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - xpl1 = [216] * 4 - xpl2 = xpl1 - elif self.mpl_ge_2_0_1: - xpl1 = [216, 216, 204, 204] - xpl2 = [216, 216, 216, 204] + # 2.0.0 or >= 3.0.0 + xpl1 = xpl2 = [Period('Jan 1988').ordinal] * len(yrs) else: - xpl1 = [216, 216, 216, 204] + xpl1 = [216, 216, 204, 204] xpl2 = [216, 216, 216, 204] rs1 = [] rs2 = [] for i, n in enumerate(yrs): - xp = xpl1[i] rng = period_range('1987Q2', periods=int(n * 12), freq='M') ser = Series(np.random.randn(len(rng)), rng) _, ax = self.plt.subplots() ser.plot(ax=ax) xaxis = ax.get_xaxis() rs1.append(xaxis.get_majorticklocs()[0]) - xp = xpl2[i] + vmin, vmax = ax.get_xlim() ax.set_xlim(vmin + 0.9, vmax) rs2.append(xaxis.get_majorticklocs()[0]) @@ -510,10 +496,8 @@ def test_finder_monthly(self): if rs1 != xpl1 or rs2 != xpl2: print(matplotlib.__version__, np.__version__, rs1, xpl1, rs2, xpl2) - for rs, xp in zip(rs1, xpl1): - assert rs == xp - for rs, xp in zip(rs2, xpl2): - assert rs == xp + assert rs1 == xpl1 + assert rs2 == xpl2 def test_finder_monthly_long(self): rng = period_range('1988Q1', periods=24 * 12, freq='M') @@ -528,11 +512,10 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + # 2.0.0 or >= 3.0.0 xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] - elif self.mpl_ge_2_0_1: - xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] else: - xp = [1987, 1987, 1990, 1990, 1995, 2020, 1970, 1970] + xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] xp = [Period(x, freq='A').ordinal for x in xp] rs = [] @@ -547,8 +530,7 @@ def test_finder_annual(self): if rs != xp: print(matplotlib.__version__, np.__version__, rs, xp) - for res, exp in zip(rs, xp): - assert res == exp + assert rs == xp @pytest.mark.slow def test_finder_minutely(self): @@ -559,7 +541,7 @@ def test_finder_minutely(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - xp = Period('1999-01-01 00:00', freq='Min').ordinal + xp = Period('1/1/1999', freq='Min').ordinal if rs != xp: print(matplotlib.__version__, np.__version__, rs, xp) assert rs == xp @@ -590,7 +572,7 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if _mpl_ge_3_0_0: + if self.mpl_ge_3_0_0: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -609,7 +591,7 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if _mpl_ge_3_0_0: + if self.mpl_ge_3_0_0: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -628,7 +610,7 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if _mpl_ge_3_0_0: + if self.mpl_ge_3_0_0: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -652,7 +634,7 @@ def test_gap_upsample(self): assert len(ax.right_ax.get_lines()) == 1 l = lines[0] data = l.get_xydata() - if _mpl_ge_3_0_0: + if self.mpl_ge_3_0_0: data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): From d20077ae5189a631659a8f132181ed7b3010a1dc Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 02:27:34 +0200 Subject: [PATCH 24/41] Fix wording --- doc/source/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/install.rst b/doc/source/install.rst index 8fe77272b0a1a..843384b680cf8 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -257,7 +257,7 @@ Optional Dependencies version. Version 0.28.2 or higher. * `SciPy `__: miscellaneous statistical functions, Version 0.18.1 or higher * `xarray `__: pandas like handling for > 2 dims, needed for converting Panels to xarray objects. Version 0.7.0 or higher is recommended. -* `PyTables `__: necessary for HDF5-based storage. Version 3.4.2 or higher required. +* `PyTables `__: necessary for HDF5-based storage, Version 3.4.2 or higher * `Feather Format `__: necessary for feather-based storage, version 0.3.1 or higher. * `Apache Parquet `__, either `pyarrow `__ (>= 0.4.1) or `fastparquet `__ (>= 0.0.6) for parquet-based storage. The `snappy `__ and `brotli `__ are available for compression support. * `SQLAlchemy `__: for SQL database support. Version 0.8.1 or higher recommended. Besides SQLAlchemy, you also need a database specific driver. You can find an overview of supported drivers for each SQL dialect in the `SQLAlchemy docs `__. Some common drivers are: From 925b555321523391dd5d46be184107c392856bef Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 08:00:41 +0200 Subject: [PATCH 25/41] Review (jreback) --- pandas/tests/indexes/period/test_partial_slicing.py | 6 ------ pandas/tests/test_expressions.py | 3 --- 2 files changed, 9 deletions(-) diff --git a/pandas/tests/indexes/period/test_partial_slicing.py b/pandas/tests/indexes/period/test_partial_slicing.py index 58504f2a91d7b..82527464ea6e7 100644 --- a/pandas/tests/indexes/period/test_partial_slicing.py +++ b/pandas/tests/indexes/period/test_partial_slicing.py @@ -68,9 +68,6 @@ def test_range_slice_day(self): didx = DatetimeIndex(start='2013/01/01', freq='D', periods=400) pidx = PeriodIndex(start='2013/01/01', freq='D', periods=400) - # exception changed to TypeError in 1.12 - # https://github.com/numpy/numpy/pull/6271 - for idx in [didx, pidx]: # slices against index should raise IndexError values = ['2014', '2013/02', '2013/01/02', '2013/02/01 9H', @@ -97,9 +94,6 @@ def test_range_slice_seconds(self): periods=4000) pidx = PeriodIndex(start='2013/01/01 09:00:00', freq='S', periods=4000) - # exception changed to TypeError in 1.12 - # https://github.com/numpy/numpy/pull/6271 - for idx in [didx, pidx]: # slices against index should raise IndexError values = ['2014', '2013/02', '2013/01/02', '2013/02/01 9H', diff --git a/pandas/tests/test_expressions.py b/pandas/tests/test_expressions.py index f6bcfbfa3f951..a7b9bf9c9a351 100644 --- a/pandas/tests/test_expressions.py +++ b/pandas/tests/test_expressions.py @@ -272,9 +272,6 @@ def testit(): for op, op_str in [('add', '+'), ('sub', '-'), ('mul', '*'), ('div', '/'), ('pow', '**')]: - # numpy >= 1.11 doesn't handle integers - # raised to integer powers - # https://github.com/pandas-dev/pandas/issues/15363 if op == 'pow': continue From b971bfba245efde575269eca38b09a614256e33b Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 08:00:52 +0200 Subject: [PATCH 26/41] Last round of mpl debugging --- pandas/plotting/_compat.py | 1 - pandas/tests/plotting/common.py | 1 - pandas/tests/plotting/test_datetimelike.py | 14 +++++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index 385e88d58cc26..ea1bc5b069fc1 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -19,7 +19,6 @@ def inner(): _mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) -_mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) _mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) _mpl_ge_2_2_2 = _mpl_version('2.2.2', operator.ge) _mpl_ge_3_0_0 = _mpl_version('3.0.0', operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index efbb083b352b8..1268420f69f4d 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -51,7 +51,6 @@ def setup_method(self, method): mpl.rcdefaults() self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() - self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() self.mpl_ge_2_2_2 = plotting._compat._mpl_ge_2_2_2() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 0b5dbb5709259..5ff8629c3be92 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -554,7 +554,7 @@ def test_finder_hourly(self): ser.plot(ax=ax) xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] - if self.mpl_ge_2_1_0: + if self.mpl_ge_2_0_1: xp = Period('1999-01-01 00:00', freq='H').ordinal else: xp = Period('1998-12-31 22:00', freq='H').ordinal @@ -572,7 +572,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -591,7 +592,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -610,7 +612,8 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): print(matplotlib.__version__, np.__version__, type(data)) @@ -634,7 +637,8 @@ def test_gap_upsample(self): assert len(ax.right_ax.get_lines()) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0: + if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: + # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) if not isinstance(data, np.ma.core.MaskedArray): From 93eabadd5d39bc226f5b170a7baa367b009fecf2 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 08:32:05 +0200 Subject: [PATCH 27/41] Tiny fix --- pandas/tests/plotting/test_datetimelike.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 5ff8629c3be92..377834aaeed74 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -555,7 +555,7 @@ def test_finder_hourly(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] if self.mpl_ge_2_0_1: - xp = Period('1999-01-01 00:00', freq='H').ordinal + xp = Period('1/1/1999', freq='H').ordinal else: xp = Period('1998-12-31 22:00', freq='H').ordinal if rs != xp: @@ -1414,7 +1414,7 @@ def test_format_timedelta_ticks_narrow(self): ['00:00:00.0000000{:0>2d}'.format(2 * i) for i in range(6)]) elif self.mpl_ge_2_0_1: - # same as >= 2.2.3 + # same as >= 2.2.2 expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) for i in range(10)]) else: # 2.0.0 From d72b5474d0cddf34f89127c5dc063a32bd924127 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 08:32:18 +0200 Subject: [PATCH 28/41] Revert debugging helpers --- pandas/tests/plotting/test_datetimelike.py | 50 +++++----------------- 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 377834aaeed74..73f420d4d7e84 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -5,10 +5,6 @@ import pytest from pandas.compat import lrange, zip -try: - import matplotlib -except: - pass import numpy as np from pandas import Index, Series, DataFrame, NaT, isna @@ -429,9 +425,6 @@ def test_finder_daily(self): rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) - if rs1 != xpl1 or rs2 != xpl2: - print(matplotlib.__version__, np.__version__, - rs1, xpl1, rs2, xpl2) assert rs1 == xpl1 assert rs2 == xpl2 @@ -461,9 +454,6 @@ def test_finder_quarterly(self): rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) - if rs1 != xpl1 or rs2 != xpl2: - print(matplotlib.__version__, np.__version__, - rs1, xpl1, rs2, xpl2) assert rs1 == xpl1 assert rs2 == xpl2 @@ -493,9 +483,6 @@ def test_finder_monthly(self): rs2.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) - if rs1 != xpl1 or rs2 != xpl2: - print(matplotlib.__version__, np.__version__, - rs1, xpl1, rs2, xpl2) assert rs1 == xpl1 assert rs2 == xpl2 @@ -528,8 +515,6 @@ def test_finder_annual(self): rs.append(xaxis.get_majorticklocs()[0]) self.plt.close(ax.get_figure()) - if rs != xp: - print(matplotlib.__version__, np.__version__, rs, xp) assert rs == xp @pytest.mark.slow @@ -542,8 +527,7 @@ def test_finder_minutely(self): xaxis = ax.get_xaxis() rs = xaxis.get_majorticklocs()[0] xp = Period('1/1/1999', freq='Min').ordinal - if rs != xp: - print(matplotlib.__version__, np.__version__, rs, xp) + assert rs == xp def test_finder_hourly(self): @@ -556,10 +540,9 @@ def test_finder_hourly(self): rs = xaxis.get_majorticklocs()[0] if self.mpl_ge_2_0_1: xp = Period('1/1/1999', freq='H').ordinal - else: + else: # 2.0.0 xp = Period('1998-12-31 22:00', freq='H').ordinal - if rs != xp: - print(matplotlib.__version__, np.__version__, rs, xp) + assert rs == xp @pytest.mark.slow @@ -575,8 +558,7 @@ def test_gaps(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) - if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version__, type(data)) + assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -595,8 +577,7 @@ def test_gaps(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) - if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version__, type(data)) + assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -615,9 +596,7 @@ def test_gaps(self): if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) - if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version__, type(data)) - print(data) + assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[2:5, 1].all() @@ -641,9 +620,6 @@ def test_gap_upsample(self): # 2.0.0 or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) - if not isinstance(data, np.ma.core.MaskedArray): - print(matplotlib.__version__, np.__version__, type(data)) - print(data) assert isinstance(data, np.ma.core.MaskedArray) mask = data.mask assert mask[5:25, 1].all() @@ -1428,12 +1404,9 @@ def test_format_timedelta_ticks_narrow(self): df.plot(fontsize=2, ax=ax) fig.canvas.draw() labels = ax.get_xticklabels() - if len(labels) != len(expected_labels): - print(matplotlib.__version__, np.__version__, - [str(x) for x in labels], expected_labels) + assert len(labels) == len(expected_labels) - for l, l_expected in zip(labels, expected_labels): - assert l.get_text() == l_expected + assert [x.get_text() for x in labels] == expected_labels def test_format_timedelta_ticks_wide(self): expected_labels = [ @@ -1464,12 +1437,9 @@ def test_format_timedelta_ticks_wide(self): ax = df.plot(fontsize=2, ax=ax) fig.canvas.draw() labels = ax.get_xticklabels() - if len(labels) != len(expected_labels): - print(matplotlib.__version__, np.__version__, - [str(x) for x in labels], expected_labels) + assert len(labels) == len(expected_labels) - for l, l_expected in zip(labels, expected_labels): - assert l.get_text() == l_expected + assert [x.get_text() for x in labels] == expected_labels def test_timedelta_plot(self): # test issue #8711 From e075eff506c5b0e91be5ff4c123d8c53938fa40d Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 08:33:40 +0200 Subject: [PATCH 29/41] Partially revert mpl-pins used for debugging --- ci/travis-27.yaml | 2 +- ci/travis-36-doc.yaml | 2 +- ci/travis-36.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/travis-27.yaml b/ci/travis-27.yaml index 6f6bd4d2f229a..c6d2916601441 100644 --- a/ci/travis-27.yaml +++ b/ci/travis-27.yaml @@ -16,7 +16,7 @@ dependencies: - jemalloc=4.5.0.post - jinja2=2.8 - lxml - - matplotlib=2.1.0 + - matplotlib=2.2.2 - mock - nomkl - numexpr diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 6b0f198dc430e..8353659e7b9a9 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib=2.2.0 + - matplotlib - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36.yaml b/ci/travis-36.yaml index df31fea66e752..3c9daa5f8b73c 100644 --- a/ci/travis-36.yaml +++ b/ci/travis-36.yaml @@ -14,7 +14,7 @@ dependencies: - ipython - jinja2 - lxml - - matplotlib=2.2.2 + - matplotlib - nomkl - numexpr - numpy From 752b5d743f1419ddf61df8563ba6c8a2d2b35185 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Thu, 11 Oct 2018 19:56:11 +0200 Subject: [PATCH 30/41] Rename azure containers --- ci/azure/macos.yml | 2 +- ci/azure/windows-py27.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/azure/macos.yml b/ci/azure/macos.yml index 9bfaef04ea2fa..fb10d89731f26 100644 --- a/ci/azure/macos.yml +++ b/ci/azure/macos.yml @@ -9,7 +9,7 @@ jobs: strategy: maxParallel: 11 matrix: - py35_np_110: + py35_np_120: ENV_FILE: ci/azure-macos-35.yaml CONDA_PY: "35" CONDA_ENV: pandas diff --git a/ci/azure/windows-py27.yml b/ci/azure/windows-py27.yml index 10251bc03b8dc..8718cc849b7a8 100644 --- a/ci/azure/windows-py27.yml +++ b/ci/azure/windows-py27.yml @@ -9,7 +9,7 @@ jobs: strategy: maxParallel: 11 matrix: - py36_np14: + py36_np121: ENV_FILE: ci/azure-windows-27.yaml CONDA_PY: "27" CONDA_ENV: pandas From 9dc846a8b8523a1897de3b859eb7bd4bcc634d2a Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 18:24:06 +0200 Subject: [PATCH 31/41] Bump numexpr check --- pandas/core/computation/check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/computation/check.py b/pandas/core/computation/check.py index 2a9ed0fb9764d..06f72bb36de5c 100644 --- a/pandas/core/computation/check.py +++ b/pandas/core/computation/check.py @@ -2,7 +2,7 @@ from distutils.version import LooseVersion _NUMEXPR_INSTALLED = False -_MIN_NUMEXPR_VERSION = "2.4.6" +_MIN_NUMEXPR_VERSION = "2.6.1" try: import numexpr as ne From 169974be6f22bfeed72963fec8ebeb62d5b009fa Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 18:27:08 +0200 Subject: [PATCH 32/41] Try retrigger CircleCI --- pandas/tests/plotting/test_series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index d97740b9a3e5c..dc708278836d2 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -208,7 +208,7 @@ def test_line_use_index_false(self): @pytest.mark.slow def test_bar_log(self): - expected = np.array([.1, 1., 10., 100., 1000., 1e4]) + expected = np.array([1e-1, 1e0, 1e1, 1e2, 1e3, 1e4]) _, ax = self.plt.subplots() ax = Series([200, 500]).plot.bar(log=True, ax=ax) @@ -221,7 +221,7 @@ def test_bar_log(self): tm.close() # GH 9905 - expected = np.array([1.0e-05, 1.0e-4, 1.0e-3, 1.0e-2, 1.0e-1, 1., 10.]) + expected = np.array([1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1]) _, ax = self.plt.subplots() ax = Series([0.1, 0.01, 0.001]).plot(log=True, kind='bar', ax=ax) From 5b45639f91a1277f4facdb9109a2e76891f0ec99 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 19:36:09 +0200 Subject: [PATCH 33/41] Better error log for failing tests --- pandas/tests/plotting/test_datetimelike.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 73f420d4d7e84..cbe6ec5fedcd3 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1405,7 +1405,6 @@ def test_format_timedelta_ticks_narrow(self): fig.canvas.draw() labels = ax.get_xticklabels() - assert len(labels) == len(expected_labels) assert [x.get_text() for x in labels] == expected_labels def test_format_timedelta_ticks_wide(self): @@ -1438,7 +1437,6 @@ def test_format_timedelta_ticks_wide(self): fig.canvas.draw() labels = ax.get_xticklabels() - assert len(labels) == len(expected_labels) assert [x.get_text() for x in labels] == expected_labels def test_timedelta_plot(self): From 308e9437d5867268d498b4eee58a5e24384cf839 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 20:12:09 +0200 Subject: [PATCH 34/41] Debugging azure macos build --- pandas/tests/plotting/test_datetimelike.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index cbe6ec5fedcd3..9ff0c32f285c1 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1382,15 +1382,7 @@ def test_plot_outofbounds_datetime(self): def test_format_timedelta_ticks_narrow(self): - if self.mpl_ge_2_2_2: - expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) - for i in range(10)]) - elif self.mpl_ge_2_2_0: - expected_labels = (['-1 days 23:59:59.999999998'] + - ['00:00:00.0000000{:0>2d}'.format(2 * i) - for i in range(6)]) - elif self.mpl_ge_2_0_1: - # same as >= 2.2.2 + if self.mpl_ge_2_0_1: expected_labels = (['00:00:00.0000000{:0>2d}'.format(i) for i in range(10)]) else: # 2.0.0 @@ -1405,7 +1397,9 @@ def test_format_timedelta_ticks_narrow(self): fig.canvas.draw() labels = ax.get_xticklabels() - assert [x.get_text() for x in labels] == expected_labels + result_labels = [x.get_text() for x in labels] + assert len(result_labels) == len(expected_labels) + assert result_labels == expected_labels def test_format_timedelta_ticks_wide(self): expected_labels = [ @@ -1423,9 +1417,6 @@ def test_format_timedelta_ticks_wide(self): ] if self.mpl_ge_2_2_2: expected_labels = expected_labels[1:-1] - elif self.mpl_ge_2_2_0: - expected_labels[0] = '-2 days 20:13:20' - expected_labels[-1] = '10 days 10:00:00' elif self.mpl_ge_2_0_1: expected_labels = expected_labels[1:-1] expected_labels[-1] = '' @@ -1437,7 +1428,9 @@ def test_format_timedelta_ticks_wide(self): fig.canvas.draw() labels = ax.get_xticklabels() - assert [x.get_text() for x in labels] == expected_labels + result_labels = [x.get_text() for x in labels] + assert len(result_labels) == len(expected_labels) + assert result_labels == expected_labels def test_timedelta_plot(self): # test issue #8711 From 9be3d10b201e6f65f4fcda09177a33dd6d7474cf Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 20:12:44 +0200 Subject: [PATCH 35/41] Revert "Partially revert mpl-pins used for debugging" This reverts commit e075eff506c5b0e91be5ff4c123d8c53938fa40d. --- ci/travis-27.yaml | 2 +- ci/travis-36-doc.yaml | 2 +- ci/travis-36.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/travis-27.yaml b/ci/travis-27.yaml index f079ac309b97c..aaa682d410db9 100644 --- a/ci/travis-27.yaml +++ b/ci/travis-27.yaml @@ -14,7 +14,7 @@ dependencies: - jemalloc=4.5.0.post - jinja2=2.8 - lxml - - matplotlib=2.2.2 + - matplotlib=2.1.0 - mock - nomkl - numexpr diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 8353659e7b9a9..6b0f198dc430e 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib + - matplotlib=2.2.0 - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36.yaml b/ci/travis-36.yaml index 90c892709d9f6..6f77b19bf2d24 100644 --- a/ci/travis-36.yaml +++ b/ci/travis-36.yaml @@ -16,7 +16,7 @@ dependencies: - ipython - jinja2 - lxml - - matplotlib + - matplotlib=2.2.2 - nomkl - numexpr - numpy From 61763f6687f7a5ae0777a2d760a03aa3f5231e03 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 20:56:43 +0200 Subject: [PATCH 36/41] Final debug??? --- pandas/tests/plotting/test_datetimelike.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 9ff0c32f285c1..418b08f3b9193 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -1403,7 +1403,6 @@ def test_format_timedelta_ticks_narrow(self): def test_format_timedelta_ticks_wide(self): expected_labels = [ - '', '00:00:00', '1 days 03:46:40', '2 days 07:33:20', @@ -1412,13 +1411,9 @@ def test_format_timedelta_ticks_wide(self): '5 days 18:53:20', '6 days 22:40:00', '8 days 02:26:40', - '9 days 06:13:20', - '' + '9 days 06:13:20' ] - if self.mpl_ge_2_2_2: - expected_labels = expected_labels[1:-1] - elif self.mpl_ge_2_0_1: - expected_labels = expected_labels[1:-1] + if not self.mpl_ge_2_0_1: # 2.0.0 expected_labels[-1] = '' rng = timedelta_range('0', periods=10, freq='1 d') From ededd73e30062e818e37467505353df39700434e Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 20:56:56 +0200 Subject: [PATCH 37/41] shift debugging pin away from doc build --- ci/travis-36-doc.yaml | 2 +- ci/travis-36-slow.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 6b0f198dc430e..8353659e7b9a9 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib=2.2.0 + - matplotlib - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36-slow.yaml b/ci/travis-36-slow.yaml index 1a7bc53e1b74b..2f471468bcda4 100644 --- a/ci/travis-36-slow.yaml +++ b/ci/travis-36-slow.yaml @@ -7,7 +7,7 @@ dependencies: - cython>=0.28.2 - html5lib - lxml - - matplotlib + - matplotlib=2.2.0 - numexpr - numpy - openpyxl=2.5.5 From 079bdaf078733adc1faa1d076a43f8b86ea9a44c Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 21:54:12 +0200 Subject: [PATCH 38/41] MPLMPLMPLMPLMPLMPLMPLMPLMPLMPLMPL --- pandas/plotting/_compat.py | 1 + pandas/tests/plotting/common.py | 1 + pandas/tests/plotting/test_datetimelike.py | 59 ++++++++++++++-------- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py index ea1bc5b069fc1..385e88d58cc26 100644 --- a/pandas/plotting/_compat.py +++ b/pandas/plotting/_compat.py @@ -19,6 +19,7 @@ def inner(): _mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge) +_mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge) _mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge) _mpl_ge_2_2_2 = _mpl_version('2.2.2', operator.ge) _mpl_ge_3_0_0 = _mpl_version('3.0.0', operator.ge) diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 1268420f69f4d..efbb083b352b8 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -51,6 +51,7 @@ def setup_method(self, method): mpl.rcdefaults() self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1() + self.mpl_ge_2_1_0 = plotting._compat._mpl_ge_2_1_0() self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0() self.mpl_ge_2_2_2 = plotting._compat._mpl_ge_2_2_2() self.mpl_ge_3_0_0 = plotting._compat._mpl_ge_3_0_0() diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py index 418b08f3b9193..8c502ac09224b 100644 --- a/pandas/tests/plotting/test_datetimelike.py +++ b/pandas/tests/plotting/test_datetimelike.py @@ -403,10 +403,11 @@ def test_get_finder(self): def test_finder_daily(self): day_lst = [10, 40, 252, 400, 950, 2750, 10000] - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 and >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 xpl1 = xpl2 = [Period('1999-1-1', freq='B').ordinal] * len(day_lst) - else: + else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 xpl1 = [7565, 7564, 7553, 7546, 7518, 7428, 7066] xpl2 = [7566, 7564, 7554, 7546, 7519, 7429, 7066] @@ -432,10 +433,11 @@ def test_finder_daily(self): def test_finder_quarterly(self): yrs = [3.5, 11] - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 and >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 xpl1 = xpl2 = [Period('1988Q1').ordinal] * len(yrs) - else: + else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 xpl1 = [68, 68] xpl2 = [72, 68] @@ -461,10 +463,11 @@ def test_finder_quarterly(self): def test_finder_monthly(self): yrs = [1.15, 2.5, 4, 11] - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 xpl1 = xpl2 = [Period('Jan 1988').ordinal] * len(yrs) - else: + else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 xpl1 = [216, 216, 204, 204] xpl2 = [216, 216, 216, 204] @@ -498,10 +501,11 @@ def test_finder_monthly_long(self): @pytest.mark.slow def test_finder_annual(self): - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 xp = [1987, 1988, 1990, 1990, 1995, 2020, 2070, 2170] - else: + else: # 2.0.1, 2.1.0, 2.2.2, 2.2.3 xp = [1986, 1986, 1990, 1990, 1995, 2020, 1970, 1970] xp = [Period(x, freq='A').ordinal for x in xp] @@ -555,8 +559,10 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -574,8 +580,10 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -593,8 +601,9 @@ def test_gaps(self): assert len(lines) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -616,8 +625,9 @@ def test_gap_upsample(self): assert len(ax.right_ax.get_lines()) == 1 l = lines[0] data = l.get_xydata() - if self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1: - # 2.0.0 or >= 3.0.0 + if (self.mpl_ge_3_0_0 or not self.mpl_ge_2_0_1 + or (self.mpl_ge_2_1_0 and not self.mpl_ge_2_2_2)): + # 2.0.0, 2.2.0 (exactly) or >= 3.0.0 data = np.ma.MaskedArray(data, mask=isna(data), fill_value=np.nan) assert isinstance(data, np.ma.core.MaskedArray) @@ -1403,6 +1413,7 @@ def test_format_timedelta_ticks_narrow(self): def test_format_timedelta_ticks_wide(self): expected_labels = [ + '', '00:00:00', '1 days 03:46:40', '2 days 07:33:20', @@ -1411,9 +1422,13 @@ def test_format_timedelta_ticks_wide(self): '5 days 18:53:20', '6 days 22:40:00', '8 days 02:26:40', - '9 days 06:13:20' + '9 days 06:13:20', + '' ] - if not self.mpl_ge_2_0_1: # 2.0.0 + if self.mpl_ge_2_2_0: + expected_labels = expected_labels[1:-1] + elif self.mpl_ge_2_0_1: + expected_labels = expected_labels[1:-1] expected_labels[-1] = '' rng = timedelta_range('0', periods=10, freq='1 d') From 162458bb13149f58f8873eec378a3de9d4e7db69 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 22:58:39 +0200 Subject: [PATCH 39/41] Revert "shift debugging pin away from doc build" This reverts commit ededd73e30062e818e37467505353df39700434e. --- ci/travis-36-doc.yaml | 2 +- ci/travis-36-slow.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 8353659e7b9a9..6b0f198dc430e 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib + - matplotlib=2.2.0 - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36-slow.yaml b/ci/travis-36-slow.yaml index 2f471468bcda4..1a7bc53e1b74b 100644 --- a/ci/travis-36-slow.yaml +++ b/ci/travis-36-slow.yaml @@ -7,7 +7,7 @@ dependencies: - cython>=0.28.2 - html5lib - lxml - - matplotlib=2.2.0 + - matplotlib - numexpr - numpy - openpyxl=2.5.5 From cdd497dc054a578116ecd51c379138ad2adae601 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Fri, 12 Oct 2018 22:58:41 +0200 Subject: [PATCH 40/41] Revert "Revert "Partially revert mpl-pins used for debugging"" This reverts commit 9be3d10b201e6f65f4fcda09177a33dd6d7474cf. --- ci/travis-27.yaml | 2 +- ci/travis-36-doc.yaml | 2 +- ci/travis-36.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/travis-27.yaml b/ci/travis-27.yaml index aaa682d410db9..f079ac309b97c 100644 --- a/ci/travis-27.yaml +++ b/ci/travis-27.yaml @@ -14,7 +14,7 @@ dependencies: - jemalloc=4.5.0.post - jinja2=2.8 - lxml - - matplotlib=2.1.0 + - matplotlib=2.2.2 - mock - nomkl - numexpr diff --git a/ci/travis-36-doc.yaml b/ci/travis-36-doc.yaml index 6b0f198dc430e..8353659e7b9a9 100644 --- a/ci/travis-36-doc.yaml +++ b/ci/travis-36-doc.yaml @@ -15,7 +15,7 @@ dependencies: - ipython==6.5.0 - ipywidgets - lxml - - matplotlib=2.2.0 + - matplotlib - nbconvert - nbformat - nbsphinx diff --git a/ci/travis-36.yaml b/ci/travis-36.yaml index 6f77b19bf2d24..90c892709d9f6 100644 --- a/ci/travis-36.yaml +++ b/ci/travis-36.yaml @@ -16,7 +16,7 @@ dependencies: - ipython - jinja2 - lxml - - matplotlib=2.2.2 + - matplotlib - nomkl - numexpr - numpy From 8e37179f223c186cf510518a3c6be4b4e7ce17c7 Mon Sep 17 00:00:00 2001 From: "H. Vetinari" Date: Sun, 14 Oct 2018 23:32:53 +0200 Subject: [PATCH 41/41] Retrigger CI