From 84a8cc20b73da8caf9305b5b35a9c9adbf5cdb46 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Mon, 4 Sep 2017 18:15:35 +0200 Subject: [PATCH 01/10] implemented fix for GH issue #16953 --- pandas/plotting/_core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index e5b9497993172..5aa5aaeb54ebd 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -342,7 +342,9 @@ def _compute_plot_data(self): label = 'None' data = data.to_frame(name=label) - numeric_data = data._convert(datetime=True)._get_numeric_data() + # fix of issue #16953 + data = data.select_dtypes(include=[np.number, "datetime", "timedelta"]) + numeric_data = data._convert(datetime=True) try: is_empty = numeric_data.empty From f8dcb84b73d1b2e012116b3a64c0ef956eb5db83 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Mon, 4 Sep 2017 19:25:57 +0200 Subject: [PATCH 02/10] added tests for fix of issue #16953 --- pandas/tests/plotting/test_frame.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 67098529a0111..21d3c2942b29a 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -380,6 +380,25 @@ def test_subplots_timeseries(self): self._check_ticks_props(ax, xlabelsize=7, xrot=45, ylabelsize=7) + def test_subplots_timeseries_y_axis(self): + # tests for fix of issue #16953 + testdata = DataFrame({"numeric": np.array([1, 2, 5]), + "timedelta": [pd.Timedelta(10, unit="s"), + pd.Timedelta(10, unit="m"), + pd.Timedelta(10, unit="h")], + "datetime": [pd.to_datetime("2017-08-01 00:00:00"), + pd.to_datetime("2017-08-01 02:00:00"), + pd.to_datetime("2017-08-02 00:00:00")], + "text": ["This", "should", "fail"]}) + ax_numeric = testdata.plot(y="numeric") + assert (ax_numeric.get_lines()[0].get_data()[1] == testdata["numeric"].values).all() + ax_timedelta = testdata.plot(y="timedelta") + assert (ax_timedelta.get_lines()[0].get_data()[1] == testdata["timedelta"].values).all() + ax_datetime = testdata.plot(y="datetime") + assert (ax_datetime.get_lines()[0].get_data()[1] == testdata["datetime"].values).all() + with pytest.raises(TypeError): + testdata.plot(y="text") + @pytest.mark.slow def test_subplots_layout(self): # GH 6667 From 23475c2cabcc87a4222efc36459099a766a40e95 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Mon, 4 Sep 2017 20:12:15 +0200 Subject: [PATCH 03/10] changed comments for git issue to pandas style GH# --- pandas/plotting/_core.py | 2 +- pandas/tests/plotting/test_frame.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 5aa5aaeb54ebd..4f9dc85ae6c8e 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -342,7 +342,7 @@ def _compute_plot_data(self): label = 'None' data = data.to_frame(name=label) - # fix of issue #16953 + # GH16953 data = data.select_dtypes(include=[np.number, "datetime", "timedelta"]) numeric_data = data._convert(datetime=True) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 21d3c2942b29a..cc690f1af44e9 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -381,7 +381,7 @@ def test_subplots_timeseries(self): ylabelsize=7) def test_subplots_timeseries_y_axis(self): - # tests for fix of issue #16953 + # GH16953 testdata = DataFrame({"numeric": np.array([1, 2, 5]), "timedelta": [pd.Timedelta(10, unit="s"), pd.Timedelta(10, unit="m"), From 9bb738930ae2b2c49efb4ee8f6b1d77f0b7dc7eb Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Mon, 4 Sep 2017 20:53:37 +0200 Subject: [PATCH 04/10] changed linelength in tests, so all lines are less than 80 characters --- pandas/tests/plotting/test_frame.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index cc690f1af44e9..d91590ebe94b0 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -382,20 +382,24 @@ def test_subplots_timeseries(self): def test_subplots_timeseries_y_axis(self): # GH16953 - testdata = DataFrame({"numeric": np.array([1, 2, 5]), - "timedelta": [pd.Timedelta(10, unit="s"), - pd.Timedelta(10, unit="m"), - pd.Timedelta(10, unit="h")], - "datetime": [pd.to_datetime("2017-08-01 00:00:00"), - pd.to_datetime("2017-08-01 02:00:00"), - pd.to_datetime("2017-08-02 00:00:00")], - "text": ["This", "should", "fail"]}) + data = {"numeric": np.array([1, 2, 5]), + "timedelta": [pd.Timedelta(10, unit="s"), + pd.Timedelta(10, unit="m"), + pd.Timedelta(10, unit="h")], + "datetime": [pd.to_datetime("2017-08-01 00:00:00"), + pd.to_datetime("2017-08-01 02:00:00"), + pd.to_datetime("2017-08-02 00:00:00")], + "text": ["This", "should", "fail"]} + testdata = DataFrame(data) ax_numeric = testdata.plot(y="numeric") - assert (ax_numeric.get_lines()[0].get_data()[1] == testdata["numeric"].values).all() + assert (ax_numeric.get_lines()[0].get_data()[1] == + testdata["numeric"].values).all() ax_timedelta = testdata.plot(y="timedelta") - assert (ax_timedelta.get_lines()[0].get_data()[1] == testdata["timedelta"].values).all() + assert (ax_timedelta.get_lines()[0].get_data()[1] == + testdata["timedelta"].values).all() ax_datetime = testdata.plot(y="datetime") - assert (ax_datetime.get_lines()[0].get_data()[1] == testdata["datetime"].values).all() + assert (ax_datetime.get_lines()[0].get_data()[1] == + testdata["datetime"].values).all() with pytest.raises(TypeError): testdata.plot(y="text") From 13b60dc751781f99bc87357a7434d544fc4ffcae Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Mon, 4 Sep 2017 23:54:42 +0200 Subject: [PATCH 05/10] added whatsnew entry --- doc/source/whatsnew/v0.21.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 273cbd8357f85..9138a986572b8 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -400,7 +400,7 @@ I/O Plotting ^^^^^^^^ - Bug in plotting methods using ``secondary_y`` and ``fontsize`` not setting secondary axis font size (:issue:`12565`) - +- Bug when plotting Timedelta and Datetime on y-axis (:issue:`16953`) Groupby/Resample/Rolling ^^^^^^^^^^^^^^^^^^^^^^^^ From eb6a1104f34d638063e6d6f6967a3b2a55de5d16 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Tue, 5 Sep 2017 01:32:10 +0200 Subject: [PATCH 06/10] swaped conversion and filtering of values, for plot to also work with object dtypes --- pandas/plotting/_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 4f9dc85ae6c8e..73d256dcfc6be 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -343,8 +343,8 @@ def _compute_plot_data(self): data = data.to_frame(name=label) # GH16953 - data = data.select_dtypes(include=[np.number, "datetime", "timedelta"]) - numeric_data = data._convert(datetime=True) + data = data._convert(datetime=True, timedelta=True) + numeric_data = data.select_dtypes(include=[np.number, "datetime", "timedelta"]) try: is_empty = numeric_data.empty From c438bb2f962116fdd33fad4e21110219fb4ed4e5 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Tue, 5 Sep 2017 01:35:33 +0200 Subject: [PATCH 07/10] refomated code, so len(line) < 80 --- pandas/plotting/_core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 73d256dcfc6be..c7e218267ebe1 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -344,7 +344,9 @@ def _compute_plot_data(self): # GH16953 data = data._convert(datetime=True, timedelta=True) - numeric_data = data.select_dtypes(include=[np.number, "datetime", "timedelta"]) + numeric_data = data.select_dtypes(include=[np.number, + "datetime", + "timedelta"]) try: is_empty = numeric_data.empty From e51a5583bad5557a0b4bcb5653074e689f7a866b Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Tue, 5 Sep 2017 17:56:36 +0200 Subject: [PATCH 08/10] changed whatsnew with timedelta and datetime dtypes --- doc/source/whatsnew/v0.21.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 9138a986572b8..44438d57dc0ad 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -400,7 +400,7 @@ I/O Plotting ^^^^^^^^ - Bug in plotting methods using ``secondary_y`` and ``fontsize`` not setting secondary axis font size (:issue:`12565`) -- Bug when plotting Timedelta and Datetime on y-axis (:issue:`16953`) +- Bug when plotting ``timedelta`` and ``datetime`` dtypes on y-axis (:issue:`16953`) Groupby/Resample/Rolling ^^^^^^^^^^^^^^^^^^^^^^^^ From 84ad1d4513b4f1709cf8c5cbe34d4e5f63f382f7 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Tue, 5 Sep 2017 18:44:23 +0200 Subject: [PATCH 09/10] added support for datetimetz and extended tests --- pandas/plotting/_core.py | 4 +- pandas/tests/plotting/test_frame.py | 66 ++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index c7e218267ebe1..a0b7e93efd05c 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -342,10 +342,12 @@ def _compute_plot_data(self): label = 'None' data = data.to_frame(name=label) - # GH16953 + # GH16953, _convert is needed as fallback, for ``Series`` + # with ``dtype == object`` data = data._convert(datetime=True, timedelta=True) numeric_data = data.select_dtypes(include=[np.number, "datetime", + "datetimetz", "timedelta"]) try: diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index d91590ebe94b0..88b11c2556b08 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -383,26 +383,78 @@ def test_subplots_timeseries(self): def test_subplots_timeseries_y_axis(self): # GH16953 data = {"numeric": np.array([1, 2, 5]), - "timedelta": [pd.Timedelta(10, unit="s"), + "timedelta": [pd.Timedelta(-10, unit="s"), pd.Timedelta(10, unit="m"), pd.Timedelta(10, unit="h")], - "datetime": [pd.to_datetime("2017-08-01 00:00:00"), - pd.to_datetime("2017-08-01 02:00:00"), - pd.to_datetime("2017-08-02 00:00:00")], + "datetime_no_tz": [pd.to_datetime("2017-08-01 00:00:00"), + pd.to_datetime("2017-08-01 02:00:00"), + pd.to_datetime("2017-08-02 00:00:00")], + "datetime_all_tz": [pd.to_datetime("2017-08-01 00:00:00", + utc=True), + pd.to_datetime("2017-08-01 02:00:00", + utc=True), + pd.to_datetime("2017-08-02 00:00:00", + utc=True)], "text": ["This", "should", "fail"]} testdata = DataFrame(data) + ax_numeric = testdata.plot(y="numeric") assert (ax_numeric.get_lines()[0].get_data()[1] == testdata["numeric"].values).all() ax_timedelta = testdata.plot(y="timedelta") assert (ax_timedelta.get_lines()[0].get_data()[1] == testdata["timedelta"].values).all() - ax_datetime = testdata.plot(y="datetime") - assert (ax_datetime.get_lines()[0].get_data()[1] == - testdata["datetime"].values).all() + ax_datetime_no_tz = testdata.plot(y="datetime_no_tz") + assert (ax_datetime_no_tz.get_lines()[0].get_data()[1] == + testdata["datetime_no_tz"].values).all() + ax_datetime_all_tz = testdata.plot(y="datetime_all_tz") + assert (ax_datetime_all_tz.get_lines()[0].get_data()[1] == + testdata["datetime_all_tz"].values).all() with pytest.raises(TypeError): testdata.plot(y="text") + @pytest.mark.xfail + def test_subplots_timeseries_y_axis_not_supported(self): + """ + This test will fail for: + period: + since period isn't yet implemented in ``select_dtypes`` + and because it will need a custom value converter + + tick formater (as was done for x-axis plots) + + categorical: + because it will need a custom value converter + + tick formater (also doesn't work for x-axis, as of now) + + datetime_mixed_tz: + because of the way how pandas handels ``Series`` of + ``datetime`` objects with different timezone, + generally converting ``datetime`` objects in a tz-aware + form could help with this problem + """ + data = {"numeric": np.array([1, 2, 5]), + "period": [pd.Period('2017-08-01 00:00:00', freq='H'), + pd.Period('2017-08-01 02:00', freq='H'), + pd.Period('2017-08-02 00:00:00', freq='H')], + "categorical": pd.Categorical(["c", "b", "a"], + categories=["a", "b", "c"], + ordered=False), + "datetime_mixed_tz": [pd.to_datetime("2017-08-01 00:00:00", + utc=True), + pd.to_datetime("2017-08-01 02:00:00"), + pd.to_datetime("2017-08-02 00:00:00")]} + testdata = pd.DataFrame(data) + ax_period = testdata.plot(x="numeric", y="period") + assert (ax_period.get_lines()[0].get_data()[1] == + testdata["period"].values).all() + ax_categorical = testdata.plot(x="numeric", y="categorical") + assert (ax_categorical.get_lines()[0].get_data()[1] == + testdata["categorical"].values).all() + ax_datetime_mixed_tz = testdata.plot(x="numeric", + y="datetime_mixed_tz") + assert (ax_datetime_mixed_tz.get_lines()[0].get_data()[1] == + testdata["datetime_mixed_tz"].values).all() + @pytest.mark.slow def test_subplots_layout(self): # GH 6667 From 1ebfb134d58443ef64a4f40acf67d211be45beb2 Mon Sep 17 00:00:00 2001 From: Sebastian Weigand Date: Tue, 5 Sep 2017 19:37:57 +0200 Subject: [PATCH 10/10] added reason to pytest.mark.xfail --- pandas/tests/plotting/test_frame.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/plotting/test_frame.py b/pandas/tests/plotting/test_frame.py index 88b11c2556b08..f3b287a8889c3 100644 --- a/pandas/tests/plotting/test_frame.py +++ b/pandas/tests/plotting/test_frame.py @@ -413,7 +413,8 @@ def test_subplots_timeseries_y_axis(self): with pytest.raises(TypeError): testdata.plot(y="text") - @pytest.mark.xfail + @pytest.mark.xfail(reason='not support for period, categorical, ' + 'datetime_mixed_tz') def test_subplots_timeseries_y_axis_not_supported(self): """ This test will fail for: