From 3df3a2ef53186392a8edfcf1fe0efa9536990f56 Mon Sep 17 00:00:00 2001 From: Hugues Valois Date: Mon, 22 May 2017 17:01:18 -0700 Subject: [PATCH 1/5] Propagate the figsize via the rcParams, since matplotlib doesn't allow passing it as a parameter to gca(). --- pandas/plotting/_core.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 49076ffb469cb..c6f80ba770a4e 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -49,9 +49,18 @@ def _get_standard_kind(kind): return {'density': 'kde'}.get(kind, kind) -def _gca(): +def _gca(figsize=None): import matplotlib.pyplot as plt - return plt.gca() + if figsize is not None: + # No way of passing in figsize via gca() call so temporarily change the + # defaults so that when it calls figure() it uses our figsize. + old_figsize = plt.rcParams.get('figure.figsize') + plt.rcParams['figure.figsize'] = figsize + try: + return plt.gca() + finally: + if figsize is not None: + plt.rcParams['figure.figsize'] = old_figsize def _gcf(): @@ -1871,14 +1880,8 @@ def plot_series(data, kind='line', ax=None, # Series unique **kwds): import matplotlib.pyplot as plt - """ - If no axes is specified, check whether there are existing figures - If there is no existing figures, _gca() will - create a figure with the default figsize, causing the figsize=parameter to - be ignored. - """ if ax is None and len(plt.get_fignums()) > 0: - ax = _gca() + ax = _gca(figsize) ax = MPLPlot._get_ax_layer(ax) return _plot(data, kind=kind, ax=ax, figsize=figsize, use_index=use_index, title=title, @@ -2006,7 +2009,7 @@ def plot_group(keys, values, ax): "'by' is None") if ax is None: - ax = _gca() + ax = _gca(figsize) data = data._get_numeric_data() if columns is None: columns = data.columns From 0c2913bdbb613ba91e48b679813a2cfd0c0632e7 Mon Sep 17 00:00:00 2001 From: Hugues Valois Date: Tue, 23 May 2017 09:18:25 -0700 Subject: [PATCH 2/5] Update what's new for v0.21.0 and use rc_context() to temporarily change rcParams. --- doc/source/whatsnew/v0.21.0.txt | 1 + pandas/plotting/_core.py | 15 +++++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 3734dc15be2e9..2012535df6fc0 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -34,6 +34,7 @@ Other Enhancements - ``Series.to_dict()`` and ``DataFrame.to_dict()`` now support an ``into`` keyword which allows you to specify the ``collections.Mapping`` subclass that you would like returned. The default is ``dict``, which is backwards compatible. (:issue:`16122`) - ``RangeIndex.append`` now returns a ``RangeIndex`` object when possible (:issue:`16212`) - :func:`to_pickle` has gained a protocol parameter (:issue:`16252`). By default, this parameter is set to `HIGHEST_PROTOCOL `__ +- ``DataFrame.boxplot`` now respects the ``figsize`` keyword for non-grouped boxplots (:issue:`11959`) .. _whatsnew_0210.api_breaking: diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index c6f80ba770a4e..a21fcd52ed38e 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -51,16 +51,11 @@ def _get_standard_kind(kind): def _gca(figsize=None): import matplotlib.pyplot as plt - if figsize is not None: - # No way of passing in figsize via gca() call so temporarily change the - # defaults so that when it calls figure() it uses our figsize. - old_figsize = plt.rcParams.get('figure.figsize') - plt.rcParams['figure.figsize'] = figsize - try: + # No way of passing in figsize via gca() call so temporarily change the + # defaults so that when it calls figure() it uses our figsize. + rc = {'figure.figsize': figsize} if figsize is not None else {} + with plt.rc_context(rc): return plt.gca() - finally: - if figsize is not None: - plt.rcParams['figure.figsize'] = old_figsize def _gcf(): @@ -1881,7 +1876,7 @@ def plot_series(data, kind='line', ax=None, # Series unique import matplotlib.pyplot as plt if ax is None and len(plt.get_fignums()) > 0: - ax = _gca(figsize) + ax = _gca() ax = MPLPlot._get_ax_layer(ax) return _plot(data, kind=kind, ax=ax, figsize=figsize, use_index=use_index, title=title, From b9a461bc55df8a44aef388a18c34088b12d68e02 Mon Sep 17 00:00:00 2001 From: Hugues Valois Date: Tue, 23 May 2017 09:27:29 -0700 Subject: [PATCH 3/5] Move bug fix from 0.21.0 whatsnew to 0.20.2. --- doc/source/whatsnew/v0.20.2.txt | 1 + doc/source/whatsnew/v0.21.0.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.20.2.txt b/doc/source/whatsnew/v0.20.2.txt index d5fd879d3f9bf..c199564a4dab6 100644 --- a/doc/source/whatsnew/v0.20.2.txt +++ b/doc/source/whatsnew/v0.20.2.txt @@ -61,6 +61,7 @@ Plotting - Bug in ``DataFrame.plot`` with a single column and a list-like ``color`` (:issue:`3486`) - Bug in ``plot`` where ``NaT`` in ``DatetimeIndex`` results in ``Timestamp.min`` (:issue: `12405`) +- Bug in ``DataFrame.boxplot`` where ``figsize`` keyword was not respected for non-grouped boxplots (:issue:`11959`) diff --git a/doc/source/whatsnew/v0.21.0.txt b/doc/source/whatsnew/v0.21.0.txt index 769884275a8bd..5f58c710606af 100644 --- a/doc/source/whatsnew/v0.21.0.txt +++ b/doc/source/whatsnew/v0.21.0.txt @@ -35,7 +35,6 @@ Other Enhancements - ``RangeIndex.append`` now returns a ``RangeIndex`` object when possible (:issue:`16212`) - :func:`to_pickle` has gained a protocol parameter (:issue:`16252`). By default, this parameter is set to `HIGHEST_PROTOCOL `__ - :func:`api.types.infer_dtype` now infers decimals. (:issue: `15690`) -- ``DataFrame.boxplot`` now respects the ``figsize`` keyword for non-grouped boxplots (:issue:`11959`) .. _whatsnew_0210.api_breaking: From 4915302b802b19642356245ca17dbe2d5780624d Mon Sep 17 00:00:00 2001 From: Hugues Valois Date: Tue, 23 May 2017 10:14:07 -0700 Subject: [PATCH 4/5] Allow passing in an rc to _gca() instead of just figsize, and added a test for boxplot figsize. --- pandas/plotting/_core.py | 8 +++----- pandas/tests/plotting/test_boxplot_method.py | 7 +++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index a21fcd52ed38e..9169eb86895fb 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -49,11 +49,8 @@ def _get_standard_kind(kind): return {'density': 'kde'}.get(kind, kind) -def _gca(figsize=None): +def _gca(rc=None): import matplotlib.pyplot as plt - # No way of passing in figsize via gca() call so temporarily change the - # defaults so that when it calls figure() it uses our figsize. - rc = {'figure.figsize': figsize} if figsize is not None else {} with plt.rc_context(rc): return plt.gca() @@ -2004,7 +2001,8 @@ def plot_group(keys, values, ax): "'by' is None") if ax is None: - ax = _gca(figsize) + rc = {'figure.figsize': figsize} if figsize is not None else {} + ax = _gca(rc) data = data._get_numeric_data() if columns is None: columns = data.columns diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index a4c70f7945347..cfd2e17971a8b 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -160,6 +160,13 @@ def test_boxplot_empty_column(self): df.loc[:, 0] = np.nan _check_plot_works(df.boxplot, return_type='axes') + @slow + def test_figsize(self): + df = DataFrame(np.random.rand(10, 5), columns=['A', 'B', 'C', 'D', 'E']) + result = df.boxplot(return_type='axes', figsize=(12,8)) + assert result.figure.bbox_inches.width == 12 + assert result.figure.bbox_inches.height == 8 + def test_fontsize(self): df = DataFrame({"a": [1, 2, 3, 4, 5, 6]}) self._check_ticks_props(df.boxplot("a", fontsize=16), From bab6ea2813a37d52dba36f4c6415936209143d4a Mon Sep 17 00:00:00 2001 From: Hugues Valois Date: Tue, 23 May 2017 10:42:13 -0700 Subject: [PATCH 5/5] Fix style violations. --- pandas/tests/plotting/test_boxplot_method.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/tests/plotting/test_boxplot_method.py b/pandas/tests/plotting/test_boxplot_method.py index cfd2e17971a8b..ce8fb7a57c912 100644 --- a/pandas/tests/plotting/test_boxplot_method.py +++ b/pandas/tests/plotting/test_boxplot_method.py @@ -162,8 +162,9 @@ def test_boxplot_empty_column(self): @slow def test_figsize(self): - df = DataFrame(np.random.rand(10, 5), columns=['A', 'B', 'C', 'D', 'E']) - result = df.boxplot(return_type='axes', figsize=(12,8)) + df = DataFrame(np.random.rand(10, 5), + columns=['A', 'B', 'C', 'D', 'E']) + result = df.boxplot(return_type='axes', figsize=(12, 8)) assert result.figure.bbox_inches.width == 12 assert result.figure.bbox_inches.height == 8