#37467 BUG: Fix .hist and .plot.hist when passing existing figure (#37278)

Open krsnik93 krsnik93
Coverage Reach
core/arrays/sparse/array.py core/arrays/sparse/dtype.py core/arrays/sparse/accessor.py core/arrays/sparse/scipy_sparse.py core/arrays/sparse/__init__.py core/arrays/categorical.py core/arrays/datetimelike.py core/arrays/datetimes.py core/arrays/timedeltas.py core/arrays/interval.py core/arrays/period.py core/arrays/integer.py core/arrays/boolean.py core/arrays/floating.py core/arrays/base.py core/arrays/string_arrow.py core/arrays/numpy_.py core/arrays/string_.py core/arrays/masked.py core/arrays/_mixins.py core/arrays/_arrow_utils.py core/arrays/_ranges.py core/arrays/__init__.py core/indexes/base.py core/indexes/multi.py core/indexes/interval.py core/indexes/datetimelike.py core/indexes/range.py core/indexes/datetimes.py core/indexes/period.py core/indexes/category.py core/indexes/extension.py core/indexes/numeric.py core/indexes/accessors.py core/indexes/api.py core/indexes/timedeltas.py core/indexes/frozen.py core/internals/blocks.py core/internals/managers.py core/internals/construction.py core/internals/concat.py core/internals/ops.py core/internals/__init__.py core/groupby/groupby.py core/groupby/generic.py core/groupby/ops.py core/groupby/grouper.py core/groupby/numba_.py core/groupby/base.py core/groupby/categorical.py core/groupby/__init__.py core/reshape/merge.py core/reshape/reshape.py core/reshape/pivot.py core/reshape/concat.py core/reshape/tile.py core/reshape/melt.py core/reshape/util.py core/reshape/api.py core/generic.py core/dtypes/cast.py core/dtypes/dtypes.py core/dtypes/common.py core/dtypes/missing.py core/dtypes/concat.py core/dtypes/base.py core/dtypes/inference.py core/dtypes/generic.py core/dtypes/api.py core/frame.py core/computation/expr.py core/computation/pytables.py core/computation/ops.py core/computation/expressions.py core/computation/eval.py core/computation/scope.py core/computation/align.py core/computation/engines.py core/computation/parsing.py core/computation/common.py core/computation/check.py core/computation/api.py core/window/rolling.py core/window/ewm.py core/window/indexers.py core/window/expanding.py core/window/common.py core/window/numba_.py core/window/__init__.py core/strings/accessor.py core/strings/object_array.py core/strings/base.py core/strings/__init__.py core/series.py core/indexing.py core/algorithms.py core/ops/array_ops.py core/ops/__init__.py core/ops/docstrings.py core/ops/missing.py core/ops/mask_ops.py core/ops/common.py core/ops/methods.py core/ops/roperator.py core/ops/invalid.py core/ops/dispatch.py core/nanops.py core/resample.py core/tools/datetimes.py core/tools/times.py core/tools/numeric.py core/tools/timedeltas.py core/base.py core/missing.py core/aggregation.py core/sorting.py core/apply.py core/construction.py core/common.py core/config_init.py core/util/hashing.py core/util/numba_.py core/arraylike.py core/indexers.py core/array_algos/replace.py core/array_algos/masked_reductions.py core/array_algos/transforms.py core/accessor.py core/flags.py core/api.py core/shared_docs.py core/index.py core/sparse/api.py io/formats/format.py io/formats/style.py io/formats/excel.py io/formats/html.py io/formats/latex.py io/formats/info.py io/formats/printing.py io/formats/csvs.py io/formats/string.py io/formats/css.py io/formats/console.py io/pytables.py io/excel/_base.py io/excel/_openpyxl.py io/excel/_odfreader.py io/excel/_odswriter.py io/excel/_xlsxwriter.py io/excel/_xlwt.py io/excel/_util.py io/excel/_xlrd.py io/excel/_pyxlsb.py io/sas/sas7bdat.py io/sas/sas_xport.py io/sas/sas_constants.py io/sas/sasreader.py io/json/_json.py io/json/_table_schema.py io/json/_normalize.py io/html.py io/clipboard/__init__.py io/common.py io/parquet.py io/date_converters.py io/feather_format.py io/gbq.py io/api.py io/spss.py io/orc.py io/clipboards.py plotting/_matplotlib/core.py plotting/_matplotlib/converter.py plotting/_matplotlib/misc.py plotting/_matplotlib/boxplot.py plotting/_matplotlib/tools.py plotting/_matplotlib/hist.py plotting/_matplotlib/timeseries.py plotting/_matplotlib/style.py plotting/_matplotlib/__init__.py plotting/_matplotlib/compat.py plotting/_core.py plotting/_misc.py _testing.py util/_decorators.py util/_validators.py util/_doctools.py util/_test_decorators.py util/_print_versions.py util/_depr_module.py util/_tester.py util/_exceptions.py util/testing.py tseries/frequencies.py tseries/holiday.py tseries/api.py tseries/offsets.py compat/numpy/function.py compat/numpy/__init__.py compat/pickle_compat.py compat/_optional.py compat/__init__.py compat/chainmap.py _config/config.py _config/localization.py _config/display.py _config/dates.py _config/__init__.py errors/__init__.py _libs/tslibs/__init__.py _libs/__init__.py api/extensions/__init__.py api/types/__init__.py api/indexers/__init__.py

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -1,4 +1,4 @@
Loading
1 -
from typing import TYPE_CHECKING
1 +
from typing import TYPE_CHECKING, Optional
2 2
3 3
import numpy as np
4 4
@@ -16,6 +16,7 @@
Loading
16 16
17 17
if TYPE_CHECKING:
18 18
    from matplotlib.axes import Axes
19 +
    from matplotlib.figure import Figure
19 20
20 21
21 22
class HistPlot(LinePlot):
@@ -181,6 +182,7 @@
Loading
181 182
    column=None,
182 183
    by=None,
183 184
    numeric_only=True,
185 +
    figure: Optional["Figure"] = None,
184 186
    figsize=None,
185 187
    sharex=True,
186 188
    sharey=True,
@@ -203,7 +205,13 @@
Loading
203 205
204 206
    naxes = len(grouped)
205 207
    fig, axes = create_subplots(
206 -
        naxes=naxes, figsize=figsize, sharex=sharex, sharey=sharey, ax=ax, layout=layout
208 +
        naxes=naxes,
209 +
        figure=figure,
210 +
        figsize=figsize,
211 +
        sharex=sharex,
212 +
        sharey=sharey,
213 +
        ax=ax,
214 +
        layout=layout,
207 215
    )
208 216
209 217
    _axes = flatten_axes(axes)
@@ -222,6 +230,7 @@
Loading
222 230
    data,
223 231
    column=None,
224 232
    by=None,
233 +
    figure=None,
225 234
    ax=None,
226 235
    bins=50,
227 236
    figsize=None,
@@ -245,6 +254,7 @@
Loading
245 254
    data : Series/DataFrame
246 255
    column : object, optional
247 256
    by : object, optional
257 +
    figure: figure, optional
248 258
    ax : axes, optional
249 259
    bins : int, default 50
250 260
    figsize : tuple, optional
@@ -282,6 +292,7 @@
Loading
282 292
        data,
283 293
        column=column,
284 294
        by=by,
295 +
        figure=figure,
285 296
        sharex=sharex,
286 297
        sharey=sharey,
287 298
        ax=ax,
@@ -381,6 +392,7 @@
Loading
381 392
    xrot=None,
382 393
    ylabelsize=None,
383 394
    yrot=None,
395 +
    figure=None,
384 396
    ax=None,
385 397
    sharex=False,
386 398
    sharey=False,
@@ -397,6 +409,7 @@
Loading
397 409
            data,
398 410
            column=column,
399 411
            by=by,
412 +
            figure=figure,
400 413
            ax=ax,
401 414
            grid=grid,
402 415
            figsize=figsize,
@@ -430,6 +443,7 @@
Loading
430 443
431 444
    fig, axes = create_subplots(
432 445
        naxes=naxes,
446 +
        figure=figure,
433 447
        ax=ax,
434 448
        squeeze=False,
435 449
        sharex=sharex,

@@ -1,6 +1,6 @@
Loading
1 1
# being a bit too dynamic
2 2
from math import ceil
3 -
from typing import TYPE_CHECKING, Iterable, List, Sequence, Tuple, Union
3 +
from typing import TYPE_CHECKING, Iterable, List, Optional, Sequence, Tuple, Union
4 4
import warnings
5 5
6 6
import matplotlib.table
@@ -17,6 +17,7 @@
Loading
17 17
if TYPE_CHECKING:
18 18
    from matplotlib.axes import Axes
19 19
    from matplotlib.axis import Axis
20 +
    from matplotlib.figure import Figure
20 21
    from matplotlib.lines import Line2D
21 22
    from matplotlib.table import Table
22 23
@@ -108,6 +109,7 @@
Loading
108 109
    sharey: bool = False,
109 110
    squeeze: bool = True,
110 111
    subplot_kw=None,
112 +
    figure: Optional["Figure"] = None,
111 113
    ax=None,
112 114
    layout=None,
113 115
    layout_type: str = "box",
@@ -147,6 +149,9 @@
Loading
147 149
      Dict with keywords passed to the add_subplot() call used to create each
148 150
      subplots.
149 151
152 +
    figure : Matplotlib figure object, optional
153 +
        Existing figure to be used for plotting.
154 +
150 155
    ax : Matplotlib axis object, optional
151 156
152 157
    layout : tuple
@@ -192,7 +197,9 @@
Loading
192 197
    if subplot_kw is None:
193 198
        subplot_kw = {}
194 199
195 -
    if ax is None:
200 +
    if figure is not None:
201 +
        fig = figure
202 +
    elif ax is None:
196 203
        fig = plt.figure(**fig_kw)
197 204
    else:
198 205
        if is_list_like(ax):

@@ -51,6 +51,10 @@
Loading
51 51
    # work)
52 52
    import matplotlib.pyplot as plt
53 53
54 +
    if kwargs.get("figure"):
55 +
        kwargs["fig"] = kwargs.get("figure")
56 +
        kwargs["ax"] = kwargs["figure"].gca()
57 +
        kwargs.pop("reuse_plot", None)
54 58
    if kwargs.pop("reuse_plot", False):
55 59
        ax = kwargs.get("ax")
56 60
        if ax is None and len(plt.get_fignums()) > 0:

@@ -325,12 +325,16 @@
Loading
325 325
                sharex=self.sharex,
326 326
                sharey=self.sharey,
327 327
                figsize=self.figsize,
328 +
                figure=self.fig,
328 329
                ax=self.ax,
329 330
                layout=self.layout,
330 331
                layout_type=self._layout_type,
331 332
            )
332 333
        else:
333 -
            if self.ax is None:
334 +
            if self.fig is not None:
335 +
                fig = self.fig
336 +
                axes = fig.add_subplot(111)
337 +
            elif self.ax is None:
334 338
                fig = self.plt.figure(figsize=self.figsize)
335 339
                axes = fig.add_subplot(111)
336 340
            else:

@@ -12,6 +12,8 @@
Loading
12 12
from pandas.core.base import PandasObject
13 13
14 14
if TYPE_CHECKING:
15 +
    from matplotlib.figure import Figure
16 +
15 17
    from pandas import DataFrame
16 18
17 19
@@ -107,6 +109,7 @@
Loading
107 109
    xrot: Optional[float] = None,
108 110
    ylabelsize: Optional[int] = None,
109 111
    yrot: Optional[float] = None,
112 +
    figure: Optional["Figure"] = None,
110 113
    ax=None,
111 114
    sharex: bool = False,
112 115
    sharey: bool = False,
@@ -146,6 +149,8 @@
Loading
146 149
    yrot : float, default None
147 150
        Rotation of y axis labels. For example, a value of 90 displays the
148 151
        y labels rotated 90 degrees clockwise.
152 +
    figure : Matplotlib Figure object, default None
153 +
        The figure to plot the histogram on.
149 154
    ax : Matplotlib axes object, default None
150 155
        The axes to plot the histogram on.
151 156
    sharex : bool, default True if ax is None else False
@@ -217,6 +222,7 @@
Loading
217 222
        xrot=xrot,
218 223
        ylabelsize=ylabelsize,
219 224
        yrot=yrot,
225 +
        figure=figure,
220 226
        ax=ax,
221 227
        sharex=sharex,
222 228
        sharey=sharey,

Learn more Showing 3 files with coverage changes found.

Changes in pandas/io/gbq.py
-2
+2
Loading file...
Changes in pandas/core/frame.py
-2
+2
Loading file...
Changes in pandas/_testing.py
-1
+1
Loading file...
Files Coverage
pandas -0.02% 90.62%
Project Totals (215 files) 90.62%
Loading