| 
1 | 1 | """ Test cases for DataFrame.plot """  | 
2 |  | - | 
3 | 2 | from datetime import date, datetime  | 
4 | 3 | import itertools  | 
 | 4 | +import re  | 
5 | 5 | import string  | 
6 | 6 | import warnings  | 
7 | 7 | 
 
  | 
@@ -358,10 +358,10 @@ def test_negative_log(self):  | 
358 | 358 |             index=list(string.ascii_letters[:6]),  | 
359 | 359 |             columns=["x", "y", "z", "four"],  | 
360 | 360 |         )  | 
361 |  | - | 
362 |  | -        with pytest.raises(ValueError):  | 
 | 361 | +        msg = "Log-y scales are not supported in area plot"  | 
 | 362 | +        with pytest.raises(ValueError, match=msg):  | 
363 | 363 |             df.plot.area(logy=True)  | 
364 |  | -        with pytest.raises(ValueError):  | 
 | 364 | +        with pytest.raises(ValueError, match=msg):  | 
365 | 365 |             df.plot.area(loglog=True)  | 
366 | 366 | 
 
  | 
367 | 367 |     def _compare_stacked_y_cood(self, normal_lines, stacked_lines):  | 
@@ -406,7 +406,12 @@ def test_line_area_stacked(self):  | 
406 | 406 |                 self._compare_stacked_y_cood(ax1.lines[2:], ax2.lines[2:])  | 
407 | 407 | 
 
  | 
408 | 408 |                 _check_plot_works(mixed_df.plot, stacked=False)  | 
409 |  | -                with pytest.raises(ValueError):  | 
 | 409 | +                msg = (  | 
 | 410 | +                    "When stacked is True, each column must be either all positive or "  | 
 | 411 | +                    "all negative. Column 'w' contains both positive and negative "  | 
 | 412 | +                    "values"  | 
 | 413 | +                )  | 
 | 414 | +                with pytest.raises(ValueError, match=msg):  | 
410 | 415 |                     mixed_df.plot(stacked=True)  | 
411 | 416 | 
 
  | 
412 | 417 |                 # Use an index with strictly positive values, preventing  | 
@@ -650,9 +655,11 @@ def test_plot_scatter(self):  | 
650 | 655 |         _check_plot_works(df.plot.scatter, x="x", y="y")  | 
651 | 656 |         _check_plot_works(df.plot.scatter, x=1, y=2)  | 
652 | 657 | 
 
  | 
653 |  | -        with pytest.raises(TypeError):  | 
 | 658 | +        msg = re.escape("scatter() missing 1 required positional argument: 'y'")  | 
 | 659 | +        with pytest.raises(TypeError, match=msg):  | 
654 | 660 |             df.plot.scatter(x="x")  | 
655 |  | -        with pytest.raises(TypeError):  | 
 | 661 | +        msg = re.escape("scatter() missing 1 required positional argument: 'x'")  | 
 | 662 | +        with pytest.raises(TypeError, match=msg):  | 
656 | 663 |             df.plot.scatter(y="y")  | 
657 | 664 | 
 
  | 
658 | 665 |         # GH 6951  | 
@@ -850,8 +857,9 @@ def test_boxplot_return_type(self):  | 
850 | 857 |             index=list(string.ascii_letters[:6]),  | 
851 | 858 |             columns=["one", "two", "three", "four"],  | 
852 | 859 |         )  | 
853 |  | -        with pytest.raises(ValueError):  | 
854 |  | -            df.plot.box(return_type="NOTATYPE")  | 
 | 860 | +        msg = "return_type must be {None, 'axes', 'dict', 'both'}"  | 
 | 861 | +        with pytest.raises(ValueError, match=msg):  | 
 | 862 | +            df.plot.box(return_type="not_a_type")  | 
855 | 863 | 
 
  | 
856 | 864 |         result = df.plot.box(return_type="dict")  | 
857 | 865 |         self._check_box_return_type(result, "dict")  | 
@@ -1309,44 +1317,47 @@ def test_partially_invalid_plot_data(self):  | 
1309 | 1317 |             df = DataFrame(np.random.randn(10, 2), dtype=object)  | 
1310 | 1318 |             df[np.random.rand(df.shape[0]) > 0.5] = "a"  | 
1311 | 1319 |             for kind in plotting.PlotAccessor._common_kinds:  | 
1312 |  | - | 
1313 | 1320 |                 msg = "no numeric data to plot"  | 
1314 | 1321 |                 with pytest.raises(TypeError, match=msg):  | 
1315 | 1322 |                     df.plot(kind=kind)  | 
1316 | 1323 | 
 
  | 
1317 | 1324 |         with tm.RNGContext(42):  | 
1318 | 1325 |             # area plot doesn't support positive/negative mixed data  | 
1319 |  | -            kinds = ["area"]  | 
1320 | 1326 |             df = DataFrame(np.random.rand(10, 2), dtype=object)  | 
1321 | 1327 |             df[np.random.rand(df.shape[0]) > 0.5] = "a"  | 
1322 |  | -            for kind in kinds:  | 
1323 |  | -                with pytest.raises(TypeError):  | 
1324 |  | -                    df.plot(kind=kind)  | 
 | 1328 | +            with pytest.raises(TypeError, match="no numeric data to plot"):  | 
 | 1329 | +                df.plot(kind="area")  | 
1325 | 1330 | 
 
  | 
1326 | 1331 |     def test_invalid_kind(self):  | 
1327 | 1332 |         df = DataFrame(np.random.randn(10, 2))  | 
1328 |  | -        with pytest.raises(ValueError):  | 
1329 |  | -            df.plot(kind="aasdf")  | 
 | 1333 | +        msg = "invalid_plot_kind is not a valid plot kind"  | 
 | 1334 | +        with pytest.raises(ValueError, match=msg):  | 
 | 1335 | +            df.plot(kind="invalid_plot_kind")  | 
1330 | 1336 | 
 
  | 
1331 | 1337 |     @pytest.mark.parametrize(  | 
1332 | 1338 |         "x,y,lbl",  | 
1333 | 1339 |         [  | 
1334 | 1340 |             (["B", "C"], "A", "a"),  | 
1335 | 1341 |             (["A"], ["B", "C"], ["b", "c"]),  | 
1336 |  | -            ("A", ["B", "C"], "badlabel"),  | 
1337 | 1342 |         ],  | 
1338 | 1343 |     )  | 
1339 | 1344 |     def test_invalid_xy_args(self, x, y, lbl):  | 
1340 | 1345 |         # GH 18671, 19699 allows y to be list-like but not x  | 
1341 | 1346 |         df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]})  | 
1342 |  | -        with pytest.raises(ValueError):  | 
 | 1347 | +        with pytest.raises(ValueError, match="x must be a label or position"):  | 
1343 | 1348 |             df.plot(x=x, y=y, label=lbl)  | 
1344 | 1349 | 
 
  | 
 | 1350 | +    def test_bad_label(self):  | 
 | 1351 | +        df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]})  | 
 | 1352 | +        msg = "label should be list-like and same length as y"  | 
 | 1353 | +        with pytest.raises(ValueError, match=msg):  | 
 | 1354 | +            df.plot(x="A", y=["B", "C"], label="bad_label")  | 
 | 1355 | + | 
1345 | 1356 |     @pytest.mark.parametrize("x,y", [("A", "B"), (["A"], "B")])  | 
1346 | 1357 |     def test_invalid_xy_args_dup_cols(self, x, y):  | 
1347 | 1358 |         # GH 18671, 19699 allows y to be list-like but not x  | 
1348 | 1359 |         df = DataFrame([[1, 3, 5], [2, 4, 6]], columns=list("AAB"))  | 
1349 |  | -        with pytest.raises(ValueError):  | 
 | 1360 | +        with pytest.raises(ValueError, match="x must be a label or position"):  | 
1350 | 1361 |             df.plot(x=x, y=y)  | 
1351 | 1362 | 
 
  | 
1352 | 1363 |     @pytest.mark.parametrize(  | 
@@ -1416,7 +1427,8 @@ def test_pie_df(self):  | 
1416 | 1427 |             columns=["X", "Y", "Z"],  | 
1417 | 1428 |             index=["a", "b", "c", "d", "e"],  | 
1418 | 1429 |         )  | 
1419 |  | -        with pytest.raises(ValueError):  | 
 | 1430 | +        msg = "pie requires either y column or 'subplots=True'"  | 
 | 1431 | +        with pytest.raises(ValueError, match=msg):  | 
1420 | 1432 |             df.plot.pie()  | 
1421 | 1433 | 
 
  | 
1422 | 1434 |         ax = _check_plot_works(df.plot.pie, y="Y")  | 
@@ -1520,11 +1532,11 @@ def test_errorbar_plot(self):  | 
1520 | 1532 |             ax = _check_plot_works(s_df.plot, y="y", x="x", yerr=yerr)  | 
1521 | 1533 |             self._check_has_errorbars(ax, xerr=0, yerr=1)  | 
1522 | 1534 | 
 
  | 
1523 |  | -        with pytest.raises(ValueError):  | 
 | 1535 | +        with tm.external_error_raised(ValueError):  | 
1524 | 1536 |             df.plot(yerr=np.random.randn(11))  | 
1525 | 1537 | 
 
  | 
1526 | 1538 |         df_err = DataFrame({"x": ["zzz"] * 12, "y": ["zzz"] * 12})  | 
1527 |  | -        with pytest.raises((ValueError, TypeError)):  | 
 | 1539 | +        with tm.external_error_raised(TypeError):  | 
1528 | 1540 |             df.plot(yerr=df_err)  | 
1529 | 1541 | 
 
  | 
1530 | 1542 |     @pytest.mark.parametrize("kind", ["line", "bar", "barh"])  | 
@@ -1647,7 +1659,10 @@ def test_errorbar_asymmetrical(self):  | 
1647 | 1659 |         expected_0_0 = err[0, :, 0] * np.array([-1, 1])  | 
1648 | 1660 |         tm.assert_almost_equal(yerr_0_0, expected_0_0)  | 
1649 | 1661 | 
 
  | 
1650 |  | -        with pytest.raises(ValueError):  | 
 | 1662 | +        msg = re.escape(  | 
 | 1663 | +            "Asymmetrical error bars should be provided with the shape (3, 2, 5)"  | 
 | 1664 | +        )  | 
 | 1665 | +        with pytest.raises(ValueError, match=msg):  | 
1651 | 1666 |             df.plot(yerr=err.T)  | 
1652 | 1667 | 
 
  | 
1653 | 1668 |         tm.close()  | 
@@ -1837,9 +1852,10 @@ def test_memory_leak(self):  | 
1837 | 1852 |         tm.close()  | 
1838 | 1853 |         # force a garbage collection  | 
1839 | 1854 |         gc.collect()  | 
 | 1855 | +        msg = "weakly-referenced object no longer exists"  | 
1840 | 1856 |         for key in results:  | 
1841 | 1857 |             # check that every plot was collected  | 
1842 |  | -            with pytest.raises(ReferenceError):  | 
 | 1858 | +            with pytest.raises(ReferenceError, match=msg):  | 
1843 | 1859 |                 # need to actually access something to get an error  | 
1844 | 1860 |                 results[key].lines  | 
1845 | 1861 | 
 
  | 
@@ -2095,7 +2111,7 @@ def test_plot_no_rows(self):  | 
2095 | 2111 | 
 
  | 
2096 | 2112 |     def test_plot_no_numeric_data(self):  | 
2097 | 2113 |         df = DataFrame(["a", "b", "c"])  | 
2098 |  | -        with pytest.raises(TypeError):  | 
 | 2114 | +        with pytest.raises(TypeError, match="no numeric data to plot"):  | 
2099 | 2115 |             df.plot()  | 
2100 | 2116 | 
 
  | 
2101 | 2117 |     def test_missing_markers_legend(self):  | 
 | 
0 commit comments