diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index c6dadb7589869..5f008a7bc8dea 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1024,6 +1024,7 @@ I/O Plotting ^^^^^^^^ +- Better error message when attempting to plot but matplotlib is not installed (:issue:`19810`). - :func:`DataFrame.plot` now raises a ``ValueError`` when the ``x`` or ``y`` argument is improperly formed (:issue:`18671`) - Bug in :func:`DataFrame.plot` when ``x`` and ``y`` arguments given as positions caused incorrect referenced columns for line, bar and area plots (:issue:`20056`) - Bug in formatting tick labels with ``datetime.time()`` and fractional seconds (:issue:`18478`). diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 6c3d07124215b..c5f72cb391572 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -44,12 +44,19 @@ try: from pandas.plotting import _converter except ImportError: - pass + _HAS_MPL = False else: + _HAS_MPL = True if get_option('plotting.matplotlib.register_converters'): _converter.register(explicit=True) +def _raise_if_no_mpl(): + # TODO(mpl_converter): remove once converter is explicit + if not _HAS_MPL: + raise ImportError("matplotlib is required for plotting.") + + def _get_standard_kind(kind): return {'density': 'kde'}.get(kind, kind) @@ -97,6 +104,7 @@ def __init__(self, data, kind=None, by=None, subplots=False, sharex=None, secondary_y=False, colormap=None, table=False, layout=None, **kwds): + _raise_if_no_mpl() _converter._WARN = False self.data = data self.by = by @@ -2264,6 +2272,7 @@ def hist_frame(data, column=None, by=None, grid=True, xlabelsize=None, ... }, index= ['pig', 'rabbit', 'duck', 'chicken', 'horse']) >>> hist = df.hist(bins=3) """ + _raise_if_no_mpl() _converter._WARN = False if by is not None: axes = grouped_hist(data, column=column, by=by, ax=ax, grid=grid, @@ -2403,6 +2412,7 @@ def grouped_hist(data, column=None, by=None, ax=None, bins=50, figsize=None, ------- axes: collection of Matplotlib Axes """ + _raise_if_no_mpl() _converter._WARN = False def plot_group(group, ax): @@ -2469,6 +2479,7 @@ def boxplot_frame_groupby(grouped, subplots=True, column=None, fontsize=None, >>> grouped = df.unstack(level='lvl1').groupby(level=0, axis=1) >>> boxplot_frame_groupby(grouped, subplots=False) """ + _raise_if_no_mpl() _converter._WARN = False if subplots is True: naxes = len(grouped) diff --git a/pandas/tests/plotting/test_misc.py b/pandas/tests/plotting/test_misc.py index c5ce8aba9d80e..c82c939584dc7 100644 --- a/pandas/tests/plotting/test_misc.py +++ b/pandas/tests/plotting/test_misc.py @@ -17,6 +17,15 @@ from pandas.tests.plotting.common import TestPlotBase, _check_plot_works +@td.skip_if_mpl +def test_import_error_message(): + # GH-19810 + df = DataFrame({"A": [1, 2]}) + + with tm.assert_raises_regex(ImportError, 'matplotlib is required'): + df.plot() + + @td.skip_if_no_mpl class TestSeriesPlots(TestPlotBase): diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 8ad73538fbec1..ab6dfee9c862c 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -160,6 +160,8 @@ def decorated_func(func): skip_if_no_mpl = pytest.mark.skipif(_skip_if_no_mpl(), reason="Missing matplotlib dependency") +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(),